5.4
;==========================================================================
;
; 功能:
;
; ① 选择清屏
; ② 弹奏音乐(部分音阶1~高音1,Ctrl+Z返回主菜单)
; ③ 选择播放音乐(可选三首,可增加,Q结束播放,ESC返回主菜单)
; ④ 显示时间(W结束显示并返回主菜单)
; ⑤ F1变换界面颜色(中断方法)
;
;===========================================================================
title main(exe)
include macro.mac
extrn piano:far
.8086
.model small
.stack 1000H
.data
zd dw ?, ? ;存原中断入口地址
menu db 22 dup(0), 0c9h, 34 dup(0cdh), 0bbh, 10, 13
db 22 dup(0), 0bah, ' Menu ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 1.Clear the screen. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 2.Play like a piano. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 3.Select a song to play. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 4.Displays the current time. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 5.Press F1 to change the color.', 0bah, 10, 13
db 22 dup(0), 0bah, ' 0.Exit the program. ', 0bah, 10, 13
db 22 dup(0), 0c8h, 34 dup(0cdh), 0bch, 10, 13
tips db 10, 13, 22 dup(0), 'Please enter a number from 0 to 5. ', 14, 10, 13, '$'
time_tip db ' Press the W key to exit the time display. ', '$'
tip5 db ' !!!Press F1 to change the color!!! ', '$'
nextline db 10, 13, 22 dup(0), '$'
error db ' Error! Please re-enter. ', '$'
songs_name db 22 dup(0), ' Song track ', 10, 13
db 22 dup(0), '1.Two tigers.(liang zhi lao hu) ', 10, 13
db 22 dup(0), '2.Whitewasher.(fen shua jiang) ', 10, 13
db 22 dup(0), '3.A Good New Year.(xin nian hao) ', 10, 13
db 10, 13
db 22 dup(0), ' Press Q to quit playing. ', 10, 13
db 22 dup(0), 'Press ESC to return to the menu. ', 10, 13
db 10, 13, '$'
play_finished db ' Play finished. ', '$'
play_exited db ' Playback exited. ', '$'
; 两只老虎
mus_freq1 dw 2 dup(262,294,330,262)
dw 2 dup(330,349,392)
dw 2 dup(392,440,392,349,330,262)
dw 2 dup(294,196,262)
dw -1 ;结束
mus_time1 dw 2 dup(20,20,20,20)
dw 2 dup(20,20,40)
dw 2 dup(10,10,10,10,20,20)
dw 2 dup(20,20,40)
; 粉刷匠
mus_freq2 dw 392,330,392,330,392,330,262
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw 294,294,349,349,330,262,392
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw -1 ;结束
mus_time2 dw 3 dup(10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,40h)
dw 10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,20h
; 新年好
mus_freq3 dw 262,262,262,196
dw 330,330,330,262
dw 262,330,392,392
dw 349,330,294
dw 294,330,349,349
dw 330,294,330,262
dw 262,330,294,196
dw 247,294,262
dw -1 ;结束
mus_time3 dw 3 dup(12,12,25,25),12,12,50
dw 3 dup(12,12,25,25),12,12,50
; 直接定址表
table dw m1, m2, m3
.code
;============================================================
;
; 主程序: main
; 功能: 程序入口
; 入口参数:无
; 出口参数:无
;
;============================================================
main proc
start:
mov ax, @data
mov ds, ax
; 改中断例程入口地址
mov ax, 0
mov es, ax
push es:[9*4]
pop ds:[0]
push es:[9*4+2]
pop ds:[2]
mov word ptr es:[9*4], offset int9
mov es:[9*4+2], cs
begin:
call cls
point 6, 0
print menu
lop:
enter_cmd
input_21h
sub al, 48
cmp al, 0
je exit
call call_fun
jmp lop
exit:
; 恢复原来中断的地址
mov ax, 0
mov es, ax
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
call cls
mov ax, 4c00h
int 21h
main endp
;============================================================
;
; 子程序: int9
; 功能: 定义中断例程
; 入口参数:无
; 出口参数:无
;
;============================================================
int9:
pushall
push es
in al, 60h
pushf
call dword ptr ds:[0]
cmp al, 03bh ;F1扫描码
jne int9ret
;改变颜色
mov ax, 0b800h
mov es, ax
mov bx, 1 ;指向显存属性单元
mov cx, 80*25 ;改变整个页面的颜色
s1:
inc byte ptr es:[bx] ;属性值+1
add bx, 2
loop s1
int9ret:
pop es
popall
iret
;============================================================
;
; 子程序: call_fun
; 功能: 选择菜单功能
; 入口参数:al - 功能序号
; 出口参数:无
;
;============================================================
call_fun proc
f1:
cmp al, 1
jne f2
jmp retu
f2:
cmp al, 2
jne f3
push8
call far ptr piano
pop8
jmp retu
f3:
cmp al, 3
jne f4
call choose_song
jmp retu
f4:
cmp al, 4
jne f5
call display_time
jmp retu
f5:
cmp al, 5
jne f_
print tip5
jmp return
f_:
in al, 60h
cmp al, 3bh ;F1扫描码
je isf1
print error
jmp return
isf1:
point 17, 0
jmp return
retu:
call cls
point 6, 0
print menu
return:
ret
call_fun endp
;============================================================
;
; 子程序: choose_song
; 功能: 输入选择播放的歌曲序号
; 入口参数:无
; 出口参数:无
;
;============================================================
choose_song proc
call cls
point 7, 0
print songs_name
cc:
enter_cmd
ff:
input_16h ;输入选择哪首歌
cmp ah, 3bh ;F1扫描码
je ff
cmp ah, 01h ;ESC扫描码
je over
cmp ah, 02h
je con
cmp ah, 03h
je con
cmp ah, 04h
je con
; print error
jmp ff
con:
sub al, 48
mov bl, al
mov bh, 0
call play_music
jmp cc
over:
ret
choose_song endp
;============================================================
;
; 子程序: play_music
; 功能: 确定歌曲的数据地址并播放
; 入口参数:无
; 出口参数:无
;
;============================================================
play_music proc
add bx, bx
jmp word ptr table[bx-2]
m1: setsidi mus_freq1, mus_time1
jmp play
m2: setsidi mus_freq2, mus_time2
jmp play
m3: setsidi mus_freq3, mus_time3
play:
mov dx, [si]
cmp dx, -1
je end1play
in al, 60h
cmp al, 10h ;Q扫描码
je end2play
call sound
add si, 2
add di, 2
jmp play
end1play:
print play_finished
jmp endplay
end2play:
print play_exited
endplay:
ret
play_music endp
;============================================================
;
; 子程序: sound
; 功能: 播放一个音符
; 入口参数:si - 频率
; di - 音长
; 出口参数:无
;
;============================================================
; @演奏一个音符
sound proc
pushall
; 8253 芯片(定时/计数器)的设置
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div word ptr [si] ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 设置8255芯片 控制扬声器的开/关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, [di] ;保持[di]时长
delay:
mov cx, 7000h
wait_:
nop
loop wait_
dec dx
jnz delay
off:
mov al, ah ;恢复扬声器端口原值
out 61h, al
popall
ret
sound endp
;============================================================
;
; 子程序: cls
; 功能: 清屏
; 入口参数:无
; 出口参数:无
;
;============================================================
cls proc
push ax
mov ah, 0fh ;BIOS-读取显示器模式
int 10h ;出口参数之一AL为显示模式
mov ah, 0h ;BIOS-设置显示器模式
int 10h ;入口参数AL为显示模式(已保存)
pop ax
ret
cls endp
;============================================================
;
; 子程序: display_time
; 功能: 显示系统日期和时间
; 入口参数:无
; 出口参数:无
;
;============================================================
display_time proc
pushall
push es
push si
show:
mov ax, 0b800h
mov es, ax
mov si, 0
mov al, 8 ;月
call disp_num
add si, 6
mov al, 7 ;日
call disp_num
add si, 6
mov al, 4 ;时
call disp_num
add si, 6
mov al, 2 ;分
call disp_num
add si, 6
mov al, 0 ;秒
call disp_num
in al, 60h
cmp al, 11h ;W扫描码
je r
jmp short show
r:
pop si
pop es
popall
ret
display_time endp
;============================================================
;
; 子程序: disp_num
; 功能: 把时间写入内存
; 入口参数:al - 时间对象
; si - 要写入内存的地址
; 出口参数:无
;
;============================================================
disp_num proc
out 70h, al
in al, 71h
mov ah, al
mov cl, 4
shr ah, cl
and al, 00001111b
add ah, 30h
add al, 30h
mov bx, 0b800h
mov es, bx
mov byte ptr es:[160*6+32*2+si], ah
mov byte ptr es:[160*6+32*2+si+1], 01001111b
mov byte ptr es:[160*6+32*2+si+2], al
mov byte ptr es:[160*6+32*2+si+2+1], 01001111b
mov byte ptr es:[160*6+32*2+si+4], ' '
mov byte ptr es:[160*6+32*2+si+4+1], 01001111b
ret
disp_num endp
end start
title piano(exe)
public piano
include macro.mac
.8086
.model small
.stack 10H
.data
scale dw 659, 262, 294, 330, 349, 392, 440, 494, 524, 587
;高3 1 2 3 4 5 6 7 高1 高2 对应 “0123456789”
piano_exit db ' You can press 0-9. CTRL+Z exit.', '$'
.code
;============================================================
;
; 子程序: piano
; 功能: 弹奏
; 入口参数:无
; 出口参数:无
;
;============================================================
piano proc
pushall
mov ax, @data
mov ds, ax
print piano_exit
co:
mov ah, 0
int 16h
cmp ah, 2ch ;Ctrl+Z扫描码
je r
cmp al, '0'
jb co
cmp al, '9'
ja co
sub al, 30H
mov bh, 0
mov bl, al
add bx, bx
mov si, word ptr ds:[scale+bx]
call sound1
jmp co
r:
popall
retf
piano endp
;============================================================
;
; 子程序: sound1
; 功能: 播放一个音符
; 入口参数:无
; 出口参数:无
;
;============================================================
sound1 proc
pushall
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div si ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 扬声器的开关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, 10 ;保持
delay:
mov cx, 7000H
w:
nop
loop w
dec dx
cmp dx, 0
je off
jmp delay
off: mov al, ah ;恢复扬声器端口原值
out 61h, al
popall
ret
sound1 endp
end
; macro.mac
;===========================宏定义===========================
;**************************
;
; # PUSH ax bx cx dx
;
;**************************
pushall macro
push ax
push bx
push cx
push dx
endm
;**************************
;
; # POP dx cx bx ax
;
;**************************
popall macro
pop dx
pop cx
pop bx
pop ax
endm
;**************************
;
; # PUSH ax bx cx dx es ds si di
;
;**************************
push8 macro
push ax
push bx
push cx
push dx
push es
push ds
push si
push di
endm
;**************************
;
; # POP di si ds es dx cx bx ax
;
;**************************
pop8 macro
pop di
pop si
pop ds
pop es
pop dx
pop cx
pop bx
pop ax
endm
;**************************
;
; # 设置光标位置 (r,c)
;
;**************************
point macro row, column
pushall
mov ah, 02h ;INT10h的2号中断-设置光标位置
mov bh, 0 ;页码-第0页
mov dh, row ;行Y -第row行
mov dl, column ;列X -第column列
int 10h
popall
endm
;**************************
;
; # 显示字符串 以'$'结尾
;
;**************************
print macro label
lea dx, label ;取偏移地址
mov ah, 09h ;21h的9号中断-显示字符串
int 21h
endm
;**************************
;
; # 输出一个字符
;
;**************************
putchar macro char
mov ah, 02h
mov dl, char
int 21h
endm
;**************************
;
; # 输入一个字符
;
;**************************
input_21h macro
mov ah, 0ch ;21h中断的c号功能 AL保存读入字符的ASCII码
mov al, 01h
int 21h
endm
;**************************
;
; # 从键盘读入字符
; # AH保存扫描码
; # AL保存ASCII码
;
;**************************
input_16h macro
mov ah, 0h
int 16h
endm
;**************************
;
; # 进入下一行
;
;**************************
newline macro
print nextline
endm
;**************************
;
; # 下一行等待输入命令
;
;**************************
enter_cmd macro
newline
putchar '$'
putchar ' '
endm
;**************************
;
; # 设置si di偏移地址
;
;**************************
setsidi macro S, D
lea si, S
lea di, D
endm
;==========================宏定义完==========================
5.3
①选择清屏
②弹奏音乐(部分音阶,Ctrl+Z返回主菜单)
③选择播放音乐(可选三首,可增加,Q结束播放,ESC返回主菜单)
④显示时间(显示的位置算是摆正了,W结束显示并返回主菜单,无法加提示语)
⑤变换界面颜色(中断方法)
title main(exe)
include macro.mac
extrn piano:far
.8086
.model small
.stack 1000H
.data
zd dw ?, ? ;存原中断入口地址
menu db 22 dup(0), 0c9h, 34 dup(0cdh), 0bbh, 10, 13
db 22 dup(0), 0bah, ' Menu ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 1.Clear the screen. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 2.Play like a piano. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 3.Select a song to play. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 4.Displays the current time. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 5.Press F1 to change the color.', 0bah, 10, 13
db 22 dup(0), 0bah, ' 0.Exit the program. ', 0bah, 10, 13
db 22 dup(0), 0c8h, 34 dup(0cdh), 0bch, 10, 13
tips db 10, 13, 22 dup(0), 'Please enter a number from 0 to 4. ', 14, 10, 13, '$'
time_tip db ' Press the W key to exit the time display. ', '$'
tip5 db ' !!!Press F1 to change the color!!! ', '$'
nextline db 10, 13, 22 dup(0), '$'
error db ' Error! Please re-enter. ', '$'
songs_name db 22 dup(0), ' Song track ', 10, 13
db 22 dup(0), '1.Two tigers.(liang zhi lao hu) ', 10, 13
db 22 dup(0), '2.Whitewasher.(fen shua jiang) ', 10, 13
db 22 dup(0), '3.A Good New Year.(xin nian hao) ', 10, 13
db 10, 13
db 22 dup(0), ' Press Q to quit playing. ', 10, 13
db 22 dup(0), 'Press ESC to return to the menu. ', 10, 13
db 10, 13, '$'
play_finished db ' Play finished. ', '$'
play_exited db ' Playback exited. ', '$'
; 两只老虎
mus_freq1 dw 2 dup(262,294,330,262)
dw 2 dup(330,349,392)
dw 2 dup(392,440,392,349,330,262)
dw 2 dup(294,196,262)
dw -1 ;结束
mus_time1 dw 2 dup(20,20,20,20)
dw 2 dup(20,20,40)
dw 2 dup(10,10,10,10,20,20)
dw 2 dup(20,20,40)
; 粉刷匠
mus_freq2 dw 392,330,392,330,392,330,262
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw 294,294,349,349,330,262,392
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw -1 ;结束
mus_time2 dw 3 dup(10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,40h)
dw 10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,20h
; 新年好
mus_freq3 dw 262,262,262,196
dw 330,330,330,262
dw 262,330,392,392
dw 349,330,294
dw 294,330,349,349
dw 330,294,330,262
dw 262,330,294,196
dw 247,294,262
dw -1 ;结束
mus_time3 dw 3 dup(12,12,25,25),12,12,50
dw 3 dup(12,12,25,25),12,12,50
; 直接定址表
table dw m1, m2, m3
.code
main proc
start:
mov ax, @data
mov ds, ax
; 改中断例程入口地址
mov ax, 0
mov es, ax
push es:[9*4]
pop ds:[0]
push es:[9*4+2]
pop ds:[2]
mov word ptr es:[9*4], offset int9
mov es:[9*4+2], cs
begin:
call cls
point 6, 0
print menu
lop:
enter_cmd
input_21h
sub al, 48
cmp al, 0
je exit
call call_fun
jmp lop
exit:
; 恢复原来的地址
mov ax, 0
mov es, ax
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
call cls
mov ax, 4c00h
int 21h
main endp
; 定义中断例程
int9:
pushall
push es
in al, 60h
pushf
call dword ptr ds:[0]
cmp al, 03bh ;F1扫描码
jne int9ret
;改变颜色
mov ax, 0b800h
mov es, ax
mov bx, 1 ;指向显存属性单元
mov cx, 80*25 ;改变整个页面的颜色
s1:
inc byte ptr es:[bx] ;属性值+1
add bx, 2
loop s1
int9ret:
pop es
popall
iret
; @功能选择 al:选择的功能号
call_fun proc
f1:
cmp al, 1
jne f2
jmp retu
f2:
cmp al, 2
jne f3
push8
call far ptr piano
pop8
jmp retu
f3:
cmp al, 3
jne f4
call choose_song
jmp retu
f4:
cmp al, 4
jne f5
call display_time
jmp retu
f5:
cmp al, 5
jne f_
print tip5
jmp return
f_:
in al, 60h
cmp al, 3bh ;F1扫描码
je isf1
print error
jmp return
isf1:
point 17, 0
jmp return
retu:
call cls
point 6, 0
print menu
return:
ret
call_fun endp
; @选择播放的歌曲
choose_song proc
call cls
point 7, 0
print songs_name
cc:
enter_cmd
ff:
input_16h
cmp ah, 3bh ;F1扫描码
je ff
cmp ah, 01h ;ESC扫描码
je over
cmp ah, 02h
je con
cmp ah, 03h
je con
cmp ah, 04h
je con
; print error
jmp ff
con:
sub al, 48
mov bl, al
mov bh, 0
call play_music
jmp cc
over:
ret
choose_song endp
play_music proc
add bx, bx
jmp word ptr table[bx-2]
m1: setsidi mus_freq1, mus_time1
jmp play
m2: setsidi mus_freq2, mus_time2
jmp play
m3: setsidi mus_freq3, mus_time3
play:
mov dx, [si]
cmp dx, -1
je end1play
in al, 60h
cmp al, 10h ;Q扫描码
je end2play
call sound
add si, 2
add di, 2
jmp play
end1play:
print play_finished
jmp endplay
end2play:
print play_exited
endplay:
ret
play_music endp
; @演奏一个音符 si频率 di音长
sound proc
pushall
; 8253 芯片(定时/计数器)的设置
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div word ptr [si] ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 设置8255芯片 控制扬声器的开/关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, [di] ;保持[di]时长
delay:
mov cx, 7000h
wait_:
nop
loop wait_
dec dx
jnz delay
off:
mov al, ah ;恢复扬声器端口原值
out 61h, al
popall
ret
sound endp
; @清屏
cls proc
push ax
mov ah, 0fh ;BIOS-读取显示器模式
int 10h ;出口参数之一AL为显示模式
mov ah, 0h ;BIOS-设置显示器模式
int 10h ;入口参数AL为显示模式(已保存)
pop ax
ret
cls endp
; 显示系统日期和时间
display_time proc
pushall
push es
push si
show:
mov ax, 0b800h
mov es, ax
mov si, 0
mov al, 8 ;月
call disp_num
add si, 6
mov al, 7 ;日
call disp_num
add si, 6
mov al, 4 ;时
call disp_num
add si, 6
mov al, 2 ;分
call disp_num
add si, 6
mov al, 0 ;秒
call disp_num
in al, 60h
cmp al, 11h ;W扫描码
je r
jmp short show
r:
pop si
pop es
popall
ret
display_time endp
disp_num proc
out 70h, al
in al, 71h
mov ah, al
mov cl, 4
shr ah, cl
and al, 00001111b
add ah, 30h
add al, 30h
mov bx, 0b800h
mov es, bx
mov byte ptr es:[160*6+32*2+si], ah
mov byte ptr es:[160*6+32*2+si+1], 01001111b
mov byte ptr es:[160*6+32*2+si+2], al
mov byte ptr es:[160*6+32*2+si+2+1], 01001111b
mov byte ptr es:[160*6+32*2+si+4], ' '
mov byte ptr es:[160*6+32*2+si+4+1], 01001111b
ret
disp_num endp
end start
title piano(exe)
public piano
include macro.mac
.8086
.model small
.stack 10H
.data
scale dw 659, 262, 294, 330, 349, 392, 440, 494, 524, 587
;高3 1 2 3 4 5 6 7 高1 高2 对应 “0123456789”
piano_exit db ' You can press 0-9. CTRL+Z exit.', '$'
.code
piano proc
pushall
mov ax, @data
mov ds, ax
print piano_exit
co:
mov ah, 0
int 16h
cmp ah, 2ch ;Ctrl+Z扫描码
je r
cmp al, '0'
jb co
cmp al, '9'
ja co
sub al, 30H
mov bh, 0
mov bl, al
add bx, bx
mov si, word ptr ds:[scale+bx]
call sound1
jmp co
r:
popall
retf
piano endp
sound1 proc
pushall
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div si ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 扬声器的开关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, 10 ;保持
delay:
mov cx, 7000H
w:
nop
loop w
dec dx
cmp dx, 0
je off
jmp delay
off: mov al, ah ;恢复扬声器端口原值
out 61h, al
popall
ret
sound1 endp
end
;===========================宏定义===========================
; # PUSH ax bx cx dx
pushall macro
push ax
push bx
push cx
push dx
endm
; # POP dx cx bx ax
popall macro
pop dx
pop cx
pop bx
pop ax
endm
push8 macro
push ax
push bx
push cx
push dx
push es
push ds
push si
push di
endm
pop8 macro
pop di
pop si
pop ds
pop es
pop dx
pop cx
pop bx
pop ax
endm
; # 设置光标位置
point macro row, column
pushall
mov ah, 02h ;INT10h的2号中断-设置光标位置
mov bh, 0 ;页码-第0页
mov dh, row ;行Y -第row行
mov dl, column ;列X -第column列
int 10h
popall
endm
; # 显示到屏幕 以'$'结尾
print macro label
lea dx, label ;取偏移地址
mov ah, 09h ;21h的9号中断-显示字符串
int 21h
endm
; # 输出一个字符
putchar macro char
mov ah, 02h
mov dl, char
int 21h
endm
; # 输入一个字符
input_21h macro
mov ah, 0ch ;21h中断的c号功能 AL保存读入字符的ASCII码
mov al, 01h
int 21h
endm
; # 从键盘读入字符,AH保存扫描码 AL保存ASCII码
input_16h macro
mov ah, 0h
int 16h
endm
; # 进入下一行
newline macro
print nextline
endm
; # 选择功能显示
enter_cmd macro
newline
putchar '$'
putchar ' '
endm
setsidi macro S, D
lea si, S
lea di, D
endm
;==========================宏定义完==========================
5.2
①选择清屏
②弹奏音乐(部分音阶)
③选择播放音乐(可选三首,可增加)
④显示时间(显示位置没解决)
⑤变换界面颜色(中断方法)
title main(exe)
include macro.mac
extrn piano:far
.8086
.model small
.stack 1000H
.data
zd dw ?, ? ;存原中断入口地址
menu db 22 dup(0), 0c9h, 34 dup(0cdh), 0bbh, 10, 13
db 22 dup(0), 0bah, ' Menu ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 1.Clear the screen. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 2.Play like a piano. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 3.Select a song to play. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 4.Displays the current time. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 5.Press F1 to change the color.', 0bah, 10, 13
db 22 dup(0), 0bah, ' 0.Exit the program. ', 0bah, 10, 13
db 22 dup(0), 0c8h, 34 dup(0cdh), 0bch, 10, 13
tips db 10, 13, 22 dup(0), 'Please enter a number from 0 to 4. ', 14, 10, 13, '$'
time_tip db ' Press the W key to exit the time display. ', '$'
tip5 db ' !!!Press F1 to change the color!!! ', '$'
nextline db 10, 13, 22 dup(0), '$'
error db ' Error! Please re-enter. ', '$'
songs_name db 22 dup(0), ' Song track ', 10, 13
db 22 dup(0), '1.Two tigers.(liang zhi lao hu) ', 10, 13
db 22 dup(0), '2.Whitewasher.(fen shua jiang) ', 10, 13
db 22 dup(0), '3.A Good New Year.(xin nian hao) ', 10, 13
db 10, 13
db 22 dup(0), ' Press Q to quit playing. ', 10, 13
db 22 dup(0), 'Press ESC to return to the menu. ', 10, 13
db 10, 13, '$'
play_finished db ' Play finished. ', '$'
play_exited db ' Playback exited. ', '$'
; 两只老虎
mus_freq1 dw 2 dup(262,294,330,262)
dw 2 dup(330,349,392)
dw 2 dup(392,440,392,349,330,262)
dw 2 dup(294,196,262)
dw -1 ;结束
mus_time1 dw 2 dup(20,20,20,20)
dw 2 dup(20,20,40)
dw 2 dup(10,10,10,10,20,20)
dw 2 dup(20,20,40)
; 粉刷匠
mus_freq2 dw 392,330,392,330,392,330,262
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw 294,294,349,349,330,262,392
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw -1 ;结束
mus_time2 dw 3 dup(10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,40h)
dw 10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,20h
; 新年好
mus_freq3 dw 262,262,262,196
dw 330,330,330,262
dw 262,330,392,392
dw 349,330,294
dw 294,330,349,349
dw 330,294,330,262
dw 262,330,294,196
dw 247,294,262
dw -1 ;结束
mus_time3 dw 3 dup(12,12,25,25),12,12,50
dw 3 dup(12,12,25,25),12,12,50
; 直接定址表
table dw m1, m2, m3
.code
main proc
start:
mov ax, @data
mov ds, ax
; 改中断例程入口地址
mov ax, 0
mov es, ax
push es:[9*4]
pop ds:[0]
push es:[9*4+2]
pop ds:[2]
mov word ptr es:[9*4], offset int9
mov es:[9*4+2], cs
begin:
call cls
point 6, 0
print menu
lop:
enter_cmd
input_21h
sub al, 48
cmp al, 0
je exit
call call_fun
jmp lop
exit:
; 恢复原来的地址
mov ax, 0
mov es, ax
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
call cls
mov ax, 4c00h
int 21h
main endp
; 定义中断例程
int9:
pushall
push es
in al, 60h
pushf
call dword ptr ds:[0]
cmp al, 03bh ;F1扫描码
jne int9ret
;改变颜色
mov ax, 0b800h
mov es, ax
mov bx, 1 ;指向显存属性单元
mov cx, 80*25 ;改变整个页面的颜色
s1:
inc byte ptr es:[bx] ;属性值+1
add bx, 2
loop s1
int9ret:
pop es
popall
iret
; @功能选择 al:选择的功能号
call_fun proc
f1:
cmp al, 1
jne f2
jmp retu
f2:
cmp al, 2
jne f3
push8
call far ptr piano
pop8
jmp retu
f3:
cmp al, 3
jne f4
call choose_song
jmp retu
f4:
cmp al, 4
jne f5
call display_time
jmp retu
f5:
cmp al, 5
jne f_
print tip5
jmp return
f_:
in al, 60h
cmp al, 3bh ;F1扫描码
je isf1
print error
jmp return
isf1:
point 17, 0
jmp return
retu:
call cls
point 6, 0
print menu
return:
ret
call_fun endp
; @选择播放的歌曲
choose_song proc
call cls
point 7, 0
print songs_name
cc:
enter_cmd
ff:
input_16h
cmp ah, 3bh ;F1扫描码
je ff
cmp ah, 01h ;ESC扫描码
je over
cmp ah, 02h
je con
cmp ah, 03h
je con
cmp ah, 04h
je con
; print error
jmp ff
con:
sub al, 48
mov bl, al
mov bh, 0
call play_music
jmp cc
over:
ret
choose_song endp
play_music proc
add bx, bx
jmp word ptr table[bx-2]
m1: setsidi mus_freq1, mus_time1
jmp play
m2: setsidi mus_freq2, mus_time2
jmp play
m3: setsidi mus_freq3, mus_time3
play:
mov dx, [si]
cmp dx, -1
je end1play
in al, 60h
cmp al, 10h ;Q扫描码
je end2play
call sound
add si, 2
add di, 2
jmp play
end1play:
print play_finished
jmp endplay
end2play:
print play_exited
endplay:
ret
play_music endp
; @演奏一个音符 si频率 di音长
sound proc
pushall
; 8253 芯片(定时/计数器)的设置
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div word ptr [si] ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 设置8255芯片 控制扬声器的开/关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, [di] ;保持[di]时长
delay:
mov cx, 7000h
wait_:
nop
loop wait_
dec dx
jnz delay
off:
mov al, ah ;恢复扬声器端口原值
out 61h, al
popall
ret
sound endp
; @清屏
cls proc
push ax
mov ah, 0fh ;BIOS-读取显示器模式
int 10h ;出口参数之一AL为显示模式
mov ah, 0h ;BIOS-设置显示器模式
int 10h ;入口参数AL为显示模式(已保存)
pop ax
ret
cls endp
; 显示系统日期和时间
display_time proc
pushall
push es
push si
show:
mov ax, 0b800h
mov es, ax
mov si, 0
mov al, 8 ;月
call disp_num
add si, 6
mov al, 7 ;日
call disp_num
add si, 6
mov al, 4 ;时
call disp_num
add si, 6
mov al, 2 ;分
call disp_num
add si, 6
mov al, 0 ;秒
call disp_num
in al, 60h
cmp al, 11h ;W扫描码
je r
jmp short show
r:
pop si
pop es
popall
ret
display_time endp
disp_num proc
out 70h, al
in al, 71h
mov ah, al
mov cl, 4
shr ah, cl
and al, 00001111b
add ah, 30h
add al, 30h
mov bx, 0b800h
mov es, bx
mov byte ptr es:[160*12+40*2+si], ah
mov byte ptr es:[160*12+40*2+si+1], 01001111b
mov byte ptr es:[160*12+40*2+si+2], al
mov byte ptr es:[160*12+40*2+si+2+1], 01001111b
mov byte ptr es:[160*12+40*2+si+4], '-'
mov byte ptr es:[160*12+40*2+si+4+1], 01001111b
ret
disp_num endp
end start
title piano(exe)
public piano
include macro.mac
.8086
.model small
.stack 10H
.data
scale dw 659, 262, 294, 330, 349, 392, 440, 494, 524, 587
;高3 1 2 3 4 5 6 7 高1 高2 对应 “0123456789”
piano_exit db ' You can press 0-9. CTRL+Z exit.', '$'
.code
piano proc
pushall
mov ax, @data
mov ds, ax
print piano_exit
co:
mov ah, 0
int 16h
cmp ah, 2ch ;Ctrl+Z扫描码
je r
cmp al, '0'
jb co
cmp al, '9'
ja co
sub al, 30H
mov bh, 0
mov bl, al
add bx, bx
mov si, word ptr ds:[scale+bx]
call sound1
jmp co
r:
popall
retf
piano endp
sound1 proc
pushall
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div si ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 扬声器的开关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, 10 ;保持
delay:
mov cx, 7000H
w:
nop
loop w
dec dx
cmp dx, 0
je off
jmp delay
off: mov al, ah ;恢复扬声器端口原值
out 61h, al
popall
ret
sound1 endp
end
;===========================宏定义===========================
; # PUSH ax bx cx dx
pushall macro
push ax
push bx
push cx
push dx
endm
; # POP dx cx bx ax
popall macro
pop dx
pop cx
pop bx
pop ax
endm
push8 macro
push ax
push bx
push cx
push dx
push es
push ds
push si
push di
endm
pop8 macro
pop di
pop si
pop ds
pop es
pop dx
pop cx
pop bx
pop ax
endm
; # 设置光标位置
point macro row, column
pushall
mov ah, 02h ;INT10h的2号中断-设置光标位置
mov bh, 0 ;页码-第0页
mov dh, row ;行Y -第row行
mov dl, column ;列X -第column列
int 10h
popall
endm
; # 显示到屏幕 以'$'结尾
print macro label
lea dx, label ;取偏移地址
mov ah, 09h ;21h的9号中断-显示字符串
int 21h
endm
; # 输出一个字符
putchar macro char
mov ah, 02h
mov dl, char
int 21h
endm
; # 输入一个字符
input_21h macro
mov ah, 0ch ;21h中断的c号功能 AL保存读入字符的ASCII码
mov al, 01h
int 21h
endm
; # 从键盘读入字符,AH保存扫描码 AL保存ASCII码
input_16h macro
mov ah, 0h
int 16h
endm
; # 进入下一行
newline macro
print nextline
endm
; # 选择功能显示
enter_cmd macro
newline
putchar '$'
putchar ' '
endm
setsidi macro S, D
lea si, S
lea di, D
endm
;==========================宏定义完==========================
5.1
title main(exe)
include macro.mac
extrn piano:far
.8086
.model small
.stack 1000H
.data
zd dw ?, ? ;存原中断入口地址
menu db 22 dup(0), 0c9h, 34 dup(0cdh), 0bbh, 10, 13
db 22 dup(0), 0bah, ' Menu ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 1.Clear the screen. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 2.Play like a piano. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 3.Select a song to play. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 4.Displays the current time. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 5.Press F1 to change the color.', 0bah, 10, 13
db 22 dup(0), 0bah, ' 0.Exit the program. ', 0bah, 10, 13
db 22 dup(0), 0c8h, 34 dup(0cdh), 0bch, 10, 13
tips db 10, 13, 22 dup(0), 'Please enter a number from 0 to 4. ', 14, 10, 13, '$'
tip4 db ' !!!Press W to return to the menu!!!', '$'
tip5 db ' !!!Press F1 to change the color!!!', '$'
nextline db 10, 13, 22 dup(0), '$'
error db ' Error! Please re-enter.', '$'
songs_name db 22 dup(0), ' Song track ', 10, 13
db 22 dup(0), '1.Two tigers.(liang zhi lao hu) ', 10, 13
db 22 dup(0), '2.Whitewasher.(fen shua jiang) ', 10, 13
db 22 dup(0), '3.A Good New Year.(xin nian hao) ', 10, 13
db 10, 13
db 22 dup(0), ' Press Q to quit playing. ', 10, 13
db 22 dup(0), 'Press ESC to return to the menu. ', 10, 13
db 10, 13, '$'
play_finished db ' Play finished.', '$'
play_exited db ' Playback exited.', '$'
place db 7*80 dup(0), '$'
; 两只老虎
mus_freq1 dw 2 dup(262,294,330,262)
dw 2 dup(330,349,392)
dw 2 dup(392,440,392,349,330,262)
dw 2 dup(294,196,262)
dw -1 ;结束
mus_time1 dw 2 dup(20,20,20,20)
dw 2 dup(20,20,40)
dw 2 dup(10,10,10,10,20,20)
dw 2 dup(20,20,40)
; 粉刷匠
mus_freq2 dw 392,330,392,330,392,330,262
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw 294,294,349,349,330,262,392
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw -1 ;结束
mus_time2 dw 3 dup(10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,40h)
dw 10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,20h
; 新年好
mus_freq3 dw 262,262,262,196
dw 330,330,330,262
dw 262,330,392,392
dw 349,330,294
dw 294,330,349,349
dw 330,294,330,262
dw 262,330,294,196
dw 247,294,262
dw -1 ;结束
mus_time3 dw 3 dup(12,12,25,25),12,12,50
dw 3 dup(12,12,25,25),12,12,50
; 直接定址表
table dw m1, m2, m3
.code
main proc
start:
mov ax, @data
mov ds, ax
; 改中断例程入口地址
mov ax, 0
mov es, ax
push es:[9*4]
pop ds:[0]
push es:[9*4+2]
pop ds:[2]
mov word ptr es:[9*4], offset int9
mov es:[9*4+2], cs
begin:
call cls
point 6, 0
print menu
lop:
enter_cmd
input_21h
sub al, 48
cmp al, 0
je exit
call call_fun
jmp lop
exit:
; 恢复原来的地址
mov ax, 0
mov es, ax
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
call cls
mov ax, 4c00h
int 21h
main endp
; 定义中断例程
int9:
pushall
push es
in al, 60h
pushf
call dword ptr ds:[0]
cmp al, 03bh ;F1扫描码
jne int9ret
;改变颜色
mov ax, 0b800h
mov es, ax
mov bx, 1 ;指向显存属性单元
mov cx, 80*25 ;改变整个页面的颜色
s1:
inc byte ptr es:[bx] ;属性值+1
add bx, 2
loop s1
int9ret:
pop es
popall
iret
; @功能选择 al:选择的功能号
call_fun proc
f1:
cmp al, 1
jne f2
jmp retu
f2:
cmp al, 2
jne f3
call far ptr piano
jmp retu
f3:
cmp al, 3
jne f4
call choose_song
jmp retu
f4:
cmp al, 4
jne f5
call display_time
jmp retu
f5:
cmp al, 5
jne f_
print tip5
jmp return
f_:
in al, 60h
cmp al, 3bh ;F1扫描码
je isf1
print error
jmp return
isf1:
point 17, 0
jmp return
retu:
call cls
point 6, 0
print menu
return:
ret
call_fun endp
; @选择播放的歌曲
choose_song proc
call cls
point 7, 0
print songs_name
cc:
enter_cmd
ff:
input_16h
cmp ah, 3bh ;F1扫描码
je ff
cmp ah, 01h ;ESC扫描码
je over
cmp ah, 02h
je con
cmp ah, 03h
je con
cmp ah, 04h
je con
; print error
jmp ff
con:
sub al, 48
mov bl, al
mov bh, 0
call play_music
jmp cc
over:
ret
choose_song endp
play_music proc
add bx, bx
jmp word ptr table[bx-2]
m1: setsidi mus_freq1, mus_time1
jmp play
m2: setsidi mus_freq2, mus_time2
jmp play
m3: setsidi mus_freq3, mus_time3
play:
mov dx, [si]
cmp dx, -1
je end1play
in al, 60h
cmp al, 10h ;Q扫描码
je end2play
call sound
add si, 2
add di, 2
jmp play
end1play:
print play_finished
jmp endplay
end2play:
print play_exited
endplay:
ret
play_music endp
; @演奏一个音符 si频率 di音长
sound proc
pushall
; 8253 芯片(定时/计数器)的设置
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div word ptr [si] ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 设置8255芯片 控制扬声器的开/关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, [di] ;保持[di]时长
delay:
mov cx, 7000h
wait_:
nop
loop wait_
dec dx
jnz delay
off:
mov al, ah ;恢复扬声器端口原值
out 61h, al
popall
ret
sound endp
; @清屏
cls proc
push ax
mov ah, 0fh ;BIOS-读取显示器模式
int 10h ;出口参数之一AL为显示模式
mov ah, 0h ;BIOS-设置显示器模式
int 10h ;入口参数AL为显示模式(已保存)
pop ax
ret
cls endp
; 显示系统日期和时间
display_time proc
pushall
push es
push si
show:
mov ax, 0b800h
mov es, ax
mov si, 0
mov al, 8 ;月
call disp_num
add si, 6
mov al, 7 ;日
call disp_num
add si, 6
mov al, 4 ;时
call disp_num
add si, 6
mov al, 2 ;分
call disp_num
add si, 6
mov al, 0 ;秒
call disp_num
in al, 60h
cmp al, 11h ;W扫描码
je r
jmp short show
r:
pop si
pop es
popall
ret
display_time endp
disp_num proc
out 70h, al
in al, 71h
mov ah, al
mov cl, 4
shr ah, cl
and al, 00001111b
add ah, 30h
add al, 30h
mov bx, 0b800h
mov es, bx
mov byte ptr es:[160*12+40*2+si], ah
mov byte ptr es:[160*12+40*2+si+1], 01001111b
mov byte ptr es:[160*12+40*2+si+2], al
mov byte ptr es:[160*12+40*2+si+2+1], 01001111b
mov byte ptr es:[160*12+40*2+si+4], '-'
mov byte ptr es:[160*12+40*2+si+4+1], 01001111b
ret
disp_num endp
end start
title piano(exe)
public piano
include macro.mac
.8086
.model small
.stack 10H
.data
scale dw 262, 294, 330, 349, 392, 440, 494, 524, 587, 659
;1 2 3 4 5 6 7 高1 高2 高3 对应键盘 “1234567890”
piano_exit db ' You can press 0-9. CTRL+Z exit.', 10, 13, '$'
.code
piano proc
pushall
mov ax, @data
mov ds, ax
print piano_exit
co:
mov ah, 0
int 16h
cmp ah, 2ch ;Ctrl+Z扫描码
je r
cmp al, '0'
jb co
cmp al, '9'
ja co
mov bh, ah
sub bh, 2
mov bl, 0
add bx, bx
mov si, ds:[scale+bx]
call sound1
jmp co
r:
popall
retf
piano endp
sound1 proc
pushall
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div si ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 扬声器的开关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, 10 ;保持
delay:
mov cx, 7000h
w:nop
loop w
dec dx
jnz delay
off: mov al, ah ;恢复扬声器端口原值
out 61h, al
popall
ret
sound1 endp
end
;===========================宏定义===========================
; # PUSH ax bx cx dx
pushall macro
push ax
push bx
push cx
push dx
endm
; # POP dx cx bx ax
popall macro
pop dx
pop cx
pop bx
pop ax
endm
; # 设置光标位置
point macro row, column
pushall
mov ah, 02h ;INT10h的2号中断-设置光标位置
mov bh, 0 ;页码-第0页
mov dh, row ;行Y -第row行
mov dl, column ;列X -第column列
int 10h
popall
endm
; # 显示到屏幕 以'$'结尾
print macro label
lea dx, label ;取偏移地址
mov ah, 09h ;21h的9号中断-显示字符串
int 21h
endm
; # 输出一个字符
putchar macro char
mov ah, 02h
mov dl, char
int 21h
endm
; # 输入一个字符
input_21h macro
mov ah, 0ch ;21h中断的c号功能 AL保存读入字符的ASCII码
mov al, 01h
int 21h
endm
; # 从键盘读入字符,AH保存扫描码 AL保存ASCII码
input_16h macro
mov ah, 0h
int 16h
endm
; # 进入下一行
newline macro
print nextline
endm
; # 选择功能显示
enter_cmd macro
newline
putchar '$'
putchar ' '
endm
setsidi macro S, D
lea si, S
lea di, D
endm
;==========================宏定义完==========================
4.2
title main(exe)
include macro.mac
.8086
.model small
.stack 1000H
.data
zd dw ?, ? ;存原中断入口地址
menu db 22 dup(0), 0c9h, 34 dup(0cdh), 0bbh, 10, 13
db 22 dup(0), 0bah, ' Menu ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 1.Clear the screen. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 2.Play like a piano. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 3.Select a song to play. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 4.Displays the current time. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 5.Press F1 to change the color.', 0bah, 10, 13
db 22 dup(0), 0bah, ' 0.Exit the program. ', 0bah, 10, 13
db 22 dup(0), 0c8h, 34 dup(0cdh), 0bch, 10, 13
tips db 10, 13, 22 dup(0), 'Please enter a number from 0 to 4. ', 14, 10, 13, '$'
tip4 db ' !!!Press W to return to the menu!!!', '$'
tip5 db ' !!!Press F1 to change the color!!!', '$'
nextline db 10, 13, 22 dup(0), '$'
error db ' Error! Please re-enter.', '$'
songs_name db 22 dup(0), ' Song track ', 10, 13
db 22 dup(0), '1.Two tigers.(liang zhi lao hu) ', 10, 13
db 22 dup(0), '2.Whitewasher.(fen shua jiang) ', 10, 13
db 22 dup(0), '3.A Good New Year.(xin nian hao) ', 10, 13
db 10, 13
db 22 dup(0), ' Press Q to quit playing. ', 10, 13
db 22 dup(0), 'Press ESC to return to the menu. ', 10, 13
db 10, 13, '$'
play_finished db ' Play finished.', '$'
play_exited db ' Playback exited.', '$'
place db 7*80 dup(0), '$'
; 两只老虎
mus_freq1 dw 2 dup(262,294,330,262)
dw 2 dup(330,349,392)
dw 2 dup(392,440,392,349,330,262)
dw 2 dup(294,196,262)
dw -1 ;结束
mus_time1 dw 2 dup(20,20,20,20)
dw 2 dup(20,20,40)
dw 2 dup(10,10,10,10,20,20)
dw 2 dup(20,20,40)
; 粉刷匠
mus_freq2 dw 392,330,392,330,392,330,262
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw 294,294,349,349,330,262,392
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw -1 ;结束
mus_time2 dw 3 dup(10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,40h)
dw 10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,20h
; 新年好
mus_freq3 dw 262,262,262,196
dw 330,330,330,262
dw 262,330,392,392
dw 349,330,294
dw 294,330,349,349
dw 330,294,330,262
dw 262,330,294,196
dw 247,294,262
dw -1 ;结束
mus_time3 dw 3 dup(12,12,25,25),12,12,50
dw 3 dup(12,12,25,25),12,12,50
; 直接定址表
table dw m1, m2, m3
.code
main proc
start:
mov ax, @data
mov ds, ax
; 改中断例程入口地址
mov ax, 0
mov es, ax
push es:[9*4]
pop ds:[0]
push es:[9*4+2]
pop ds:[2]
mov word ptr es:[9*4], offset int9
mov es:[9*4+2], cs
begin:
call cls
point 6, 0
print menu
lop:
enter_cmd
input_21h
sub al, 48
cmp al, 0
je exit
call call_fun
jmp lop
exit:
; 恢复原来的地址
mov ax, 0
mov es, ax
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
call cls
mov ax, 4c00h
int 21h
main endp
; 定义中断例程
int9:
pushall
push es
in al, 60h
pushf
call dword ptr ds:[0]
cmp al, 03bh ;F1扫描码
jne int9ret
;改变颜色
mov ax, 0b800h
mov es, ax
mov bx, 1 ;指向显存属性单元
mov cx, 80*25 ;改变整个页面的颜色
s1:
inc byte ptr es:[bx] ;属性值+1
add bx, 2
loop s1
int9ret:
pop es
popall
iret
; @功能选择 al:选择的功能号
call_fun proc
f1:
cmp al, 1
jne f2
jmp retu
f2:
cmp al, 2
jne f3
; call piano
jmp retu
f3:
cmp al, 3
jne f4
call choose_song
jmp retu
f4:
cmp al, 4
jne f5
call display_time
jmp retu
f5:
cmp al, 5
jne f_
print tip5
jmp return
f_:
in al, 60h
cmp al, 3bh ;F1扫描码
je isf1
print error
jmp return
isf1:
point 17, 0
jmp return
retu:
call cls
point 6, 0
print menu
return:
ret
call_fun endp
; @选择播放的歌曲
choose_song proc
call cls
point 7, 0
print songs_name
cc:
enter_cmd
ff:
input_16h
cmp ah, 3bh ;F1扫描码
je ff
cmp ah, 01h ;ESC扫描码
je over
cmp ah, 02h
je con
cmp ah, 03h
je con
cmp ah, 04h
je con
; print error
jmp ff
con:
sub al, 48
mov bl, al
mov bh, 0
call play_music
jmp cc
over:
ret
choose_song endp
play_music proc
add bx, bx
jmp word ptr table[bx-2]
m1: setsidi mus_freq1, mus_time1
jmp play
m2: setsidi mus_freq2, mus_time2
jmp play
m3: setsidi mus_freq3, mus_time3
play:
mov dx, [si]
cmp dx, -1
je end1play
in al, 60h
cmp al, 10h ;Q扫描码
je end2play
call sound
add si, 2
add di, 2
jmp play
end1play:
print play_finished
jmp endplay
end2play:
print play_exited
endplay:
ret
play_music endp
; @演奏一个音符 si频率 di音长
sound proc
pushall
; 8253 芯片(定时/计数器)的设置
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div word ptr [si] ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 设置8255芯片 控制扬声器的开/关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, [di] ;保持[di]时长
delay:
mov cx, 7000h
wait_:
nop
loop wait_
dec dx
jnz delay
off:
mov al, ah ;恢复扬声器端口原值
out 61h, al
popall
ret
sound endp
; @清屏
cls proc
push ax
mov ah, 0fh ;BIOS-读取显示器模式
int 10h ;出口参数之一AL为显示模式
mov ah, 0h ;BIOS-设置显示器模式
int 10h ;入口参数AL为显示模式(已保存)
pop ax
ret
cls endp
; 显示系统日期和时间
display_time proc
pushall
push es
push si
show:
mov ax, 0b800h
mov es, ax
mov si, 0
mov al, 8 ;月
call disp_num
add si, 6
mov al, 7 ;日
call disp_num
add si, 6
mov al, 4 ;时
call disp_num
add si, 6
mov al, 2 ;分
call disp_num
add si, 6
mov al, 0 ;秒
call disp_num
in al, 60h
cmp al, 11h ;W扫描码
je r
jmp short show
r:
pop si
pop es
popall
ret
display_time endp
disp_num proc
out 70h, al
in al, 71h
mov ah, al
mov cl, 4
shr ah, cl
and al, 00001111b
add ah, 30h
add al, 30h
mov bx, 0b800h
mov es, bx
mov byte ptr es:[160*12+40*2+si], ah
mov byte ptr es:[160*12+40*2+si+1], 01001111b
mov byte ptr es:[160*12+40*2+si+2], al
mov byte ptr es:[160*12+40*2+si+2+1], 01001111b
mov byte ptr es:[160*12+40*2+si+4], '-'
mov byte ptr es:[160*12+40*2+si+4+1], 01001111b
ret
disp_num endp
end start
;===========================宏定义===========================
; # PUSH ax bx cx dx
pushall macro
push ax
push bx
push cx
push dx
endm
; # POP dx cx bx ax
popall macro
pop dx
pop cx
pop bx
pop ax
endm
; # 设置光标位置
point macro row, column
pushall
mov ah, 02h ;INT10h的2号中断-设置光标位置
mov bh, 0 ;页码-第0页
mov dh, row ;行Y -第row行
mov dl, column ;列X -第column列
int 10h
popall
endm
; # 显示到屏幕 '$'结尾
print macro label
lea dx, label ;取偏移地址
mov ah, 09h ;21h的9号中断-显示字符串
int 21h
endm
; # 输出一个字符
putchar macro char
mov ah, 02h
mov dl, char
int 21h
endm
; # 输入一个字符
input_21h macro
mov ah, 0ch ;21h中断的c号功能 AL保存读入字符的ASCII码
mov al, 01h
int 21h
endm
; # 从键盘读入字符,AH保存扫描码 AL保存ASCII码
input_16h macro
mov ah, 10h
int 16h
endm
; # 进入下一行
newline macro
print nextline
endm
; # 选择功能显示
enter_cmd macro
newline
putchar '$'
putchar ' '
endm
setsidi macro S, D
lea si, S
lea di, D
endm
;==========================宏定义完==========================
4.1
title main(exe)
.8086
.model small
.stack 100H
.data
zd dw ?, ? ;存原中断入口地址
menu db 22 dup(0), 0c9h, 34 dup(0cdh), 0bbh, 10, 13
db 22 dup(0), 0bah, ' Menu ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 1.Clear the screen. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 2.Play like a piano. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 3.Select a song to play. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 4.Displays the current time. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 5.Press F1 to change the color.', 0bah, 10, 13
db 22 dup(0), 0bah, ' 0.Exit the program. ', 0bah, 10, 13
db 22 dup(0), 0c8h, 34 dup(0cdh), 0bch, 10, 13
tips db 10, 13, 22 dup(0), 'Please enter a number from 0 to 4. ', 14, 10, 13, '$'
tip4 db ' !!!Press W to return to the menu!!!', '$'
tip5 db ' !!!Press F1 to change the color!!!', '$'
nextline db 10, 13, 22 dup(0), '$'
error db ' Error! Please re-enter.', '$'
songs_name db 22 dup(0), ' Song track ', 10, 13
db 22 dup(0), '1.Two tigers.(liang zhi lao hu) ', 10, 13
db 22 dup(0), '2.Whitewasher.(fen shua jiang) ', 10, 13
db 22 dup(0), '3.A Good New Year.(xin nian hao) ', 10, 13
db 10, 13
db 22 dup(0), ' Press Q to quit playing. ', 10, 13
db 22 dup(0), 'Press ESC to return to the menu. ', 10, 13
db 10, 13, '$'
play_finished db ' Play finished.', '$'
play_exited db ' Playback exited.', '$'
; 两只老虎
mus_freq1 dw 2 dup(262,294,330,262)
dw 2 dup(330,349,392)
dw 2 dup(392,440,392,349,330,262)
dw 2 dup(294,196,262)
dw -1 ;结束
mus_time1 dw 2 dup(20,20,20,20)
dw 2 dup(20,20,40)
dw 2 dup(10,10,10,10,20,20)
dw 2 dup(20,20,40)
; 粉刷匠
mus_freq2 dw 392,330,392,330,392,330,262
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw 294,294,349,349,330,262,392
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw -1 ;结束
mus_time2 dw 3 dup(10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,40h)
dw 10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,20h
; 新年好
mus_freq3 dw 262,262,262,196
dw 330,330,330,262
dw 262,330,392,392
dw 349,330,294
dw 294,330,349,349
dw 330,294,330,262
dw 262,330,294,196
dw 247,294,262
dw -1 ;结束
mus_time3 dw 3 dup(12,12,25,25),12,12,50
dw 3 dup(12,12,25,25),12,12,50
; 直接定址表
table dw m1, m2, m3
.code
main proc
;===========================宏定义===========================
; # PUSH ax bx cx dx
pushall macro
push ax
push bx
push cx
push dx
endm
; # POP dx cx bx ax
popall macro
pop dx
pop cx
pop bx
pop ax
endm
; # 设置光标位置
point macro row, column
pushall
mov ah, 02h ;INT10h的2号中断-设置光标位置
mov bh, 0 ;页码-第0页
mov dh, row ;行Y -第row行
mov dl, column ;列X -第column列
int 10h
popall
endm
; # 显示到屏幕 '$'结尾
print macro label
lea dx, label ;取偏移地址
mov ah, 09h ;21h的9号中断-显示字符串
int 21h
endm
; # 输出一个字符
putchar macro char
mov ah, 02h
mov dl, char
int 21h
endm
; # 输入一个字符
input_21h macro
mov ah, 0ch ;21h中断的c号功能 AL保存读入字符的ASCII码
mov al, 01h
int 21h
endm
; # 从键盘读入字符,AH保存扫描码 AL保存ASCII码
input_16h macro
mov ah, 10h
int 16h
endm
; # 进入下一行
newline macro
print nextline
endm
; # 选择功能显示
enter_cmd macro
newline
putchar '$'
putchar ' '
endm
setsidi macro S, D
lea si, S
lea di, D
endm
;==========================宏定义完==========================
start:
mov ax, @data
mov ds, ax
; 改中断例程入口地址
mov ax, 0
mov es, ax
push es:[9*4]
pop ds:[0]
push es:[9*4+2]
pop ds:[2]
mov word ptr es:[9*4], offset int9
mov es:[9*4+2], cs
begin:
call cls
point 6, 0
print menu
lop:
enter_cmd
input_21h
sub al, 48
cmp al, 0
je exit
call call_fun
jmp lop
exit:
; 恢复原来的地址
mov ax, 0
mov es, ax
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
call cls
mov ax, 4c00h
int 21h
main endp
; 定义中断例程
int9:
pushall
push es
in al, 60h
pushf
call dword ptr ds:[0]
cmp al, 03bh ;F1扫描码
jne int9ret
;改变颜色
mov ax, 0b800h
mov es, ax
mov bx, 1 ;指向显存属性单元
mov cx, 80*25 ;改变整个页面的颜色
s1:
inc byte ptr es:[bx] ;属性值+1
add bx, 2
loop s1
int9ret:
pop es
popall
iret
; @功能选择 al:选择的功能号
call_fun proc
f1:
cmp al, 1
jne f2
call cls
point 6, 0
print menu
jmp return
f2:
cmp al, 2
jne f3
; call piano
jmp return
f3:
cmp al, 3
jne f4
call choose_song
jmp return
f4:
cmp al, 4
jne f5
call display_time
; call cls
; point 6, 0
; print menu
jmp return
f5:
cmp al, 5
jne f_
print tip5
jmp return
f_:
in al, 60h
cmp al, 3bh ;F1扫描码
je return
print error
return:
ret
call_fun endp
; @选择播放的歌曲
choose_song proc
call cls
point 7, 0
print songs_name
cc:
enter_cmd
ff:
input_16h
cmp ah, 3bh ;F1扫描码
je ff
cmp ah, 01h ;ESC扫描码
je over
cmp ah, 02h
je con
cmp ah, 03h
je con
cmp ah, 04h
je con
; print error
jmp ff
con:
sub al, 48
mov bl, al
mov bh, 0
call play_music
jmp cc
over:
call cls
point 6,0
print menu
ret
choose_song endp
play_music proc
add bx, bx
jmp word ptr table[bx-2]
m1:
setsidi mus_freq1, mus_time1
jmp play
m2:
setsidi mus_freq2, mus_time2
jmp play
m3:
setsidi mus_freq3, mus_time3
play:
mov dx, [si]
cmp dx, -1
je end1play
in al, 60h
cmp al, 10h ;Q扫描码
je end2play
call sound
add si, 2
add di, 2
jmp play
end1play:
print play_finished
jmp endplay
end2play:
print play_exited
endplay:
ret
play_music endp
; @演奏一个音符 si频率 di音长
sound proc
pushall
; 8253 芯片(定时/计数器)的设置
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div word ptr [si] ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 设置8255芯片 控制扬声器的开/关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, [di] ;保持[di]时长
delay:
mov cx, 7000h
wait_:
nop
loop wait_
dec dx
jnz delay
off:
mov al, ah ;恢复扬声器端口原值
out 61h, al
popall
ret
sound endp
; @清屏
cls proc
push ax
mov ah, 0fh ;BIOS-读取显示器模式
int 10h ;出口参数之一AL为显示模式
mov ah, 0h ;BIOS-设置显示器模式
int 10h ;入口参数AL为显示模式(已保存)
pop ax
ret
cls endp
; cls proc
; pushall
; mov ax, 0600h ;向上滚行清窗口
; mov bh, 3ch
; mov cx, 0000h ;左上角位置(Y,X)
; mov dx, 184fh ;右下角位置(Y,X)
; int 10h
; popall
; ret
; cls endp
; 显示系统日期和时间
display_time proc
pushall
push es
push si
show:
; mov al, 8
; mov si, 0
; call disp_num
; mov byte ptr es:[4], '.'
; mov byte ptr es:[5], 01001111b
; mov al, 7
; mov si, 6
; call disp_num
; mov byte ptr es:[10], ' '
; mov byte ptr es:[11], 01001111b
; mov al, 4
; mov si, 12
; call disp_num
; mov byte ptr es:[16], ':'
; mov byte ptr es:[17], 01001111b
; mov al, 2 ;分
; mov si, 18
; call disp_num
; mov byte ptr es:[22], ':'
; mov byte ptr es:[23], 01001111b
; mov al, 0 ;秒
; mov si, 24
; call disp_num
mov ax, 0b800h
mov es, ax
mov si, 0
mov al, 8
call disp_num
add si, 6
mov al, 7
call disp_num
add si, 6
mov al, 4
call disp_num
add si, 6
mov al, 2
call disp_num
in al, 60h
cmp al, 11h ;W扫描码
je r
jmp short show
r:
call cls
point 6, 0
print menu
pop si
pop es
popall
ret
display_time endp
disp_num proc
out 70h, al
in al, 71h
mov ah, al
mov cl, 4
shr ah, cl
and al, 00001111b
add ah, 30h
add al, 30h
mov bx, 0b800h
mov es, bx
mov byte ptr es:[160*12+40*2+si], ah
mov byte ptr es:[160*12+40*2+si+1], 01001111b
mov byte ptr es:[160*12+40*2+si+2], al
mov byte ptr es:[160*12+40*2+si+2+1], 01001111b
mov byte ptr es:[160*12+40*2+si+4], '/'
mov byte ptr es:[160*12+40*2+si+4+1], 01001111b
ret
disp_num endp
end start
4.0
title main(exe)
.8086
.model small
.stack 100H
.data
zd dw ?, ? ;存原中断入口地址
menu db 22 dup(0), 0c9h, 34 dup(0cdh), 0bbh, 10, 13
db 22 dup(0), 0bah, ' Menu ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 1.Clear the screen. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 2.Play like a piano. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 3.Select a song to play. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 4.Displays the current time. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 5.Press F1 to change the color.', 0bah, 10, 13
db 22 dup(0), 0bah, ' 0.Exit the program. ', 0bah, 10, 13
db 22 dup(0), 0c8h, 34 dup(0cdh), 0bch, 10, 13
tips db 10, 13, 22 dup(0), 'Please enter a number from 0 to 4. ', 14, 10, 13, '$'
tip5 db ' !!!Press F1 to change the color!!!', '$'
nextline db 10, 13, 22 dup(0), '$'
error db ' Error! Please re-enter.', '$'
songs_name db 22 dup(0), ' Song track ', 10, 13
db 22 dup(0), '1.Two tigers.(liang zhi lao hu) ', 10, 13
db 22 dup(0), '2.Whitewasher.(fen shua jiang) ', 10, 13
db 22 dup(0), '3.A Good New Year.(xin nian hao) ', 10, 13
db 10, 13
db 22 dup(0), ' Press Q to quit playing. ', 10, 13
db 22 dup(0), 'Press ESC to return to the menu. ', 10, 13
db 10, 13, '$'
play_finished db ' Play finished.', '$'
play_exited db ' Playback exited.', '$'
; 两只老虎
mus_freq1 dw 2 dup(262,294,330,262)
dw 2 dup(330,349,392)
dw 2 dup(392,440,392,349,330,262)
dw 2 dup(294,196,262)
dw -1 ;结束
mus_time1 dw 2 dup(20,20,20,20)
dw 2 dup(20,20,40)
dw 2 dup(10,10,10,10,20,20)
dw 2 dup(20,20,40)
; 粉刷匠
mus_freq2 dw 392,330,392,330,392,330,262
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw 294,294,349,349,330,262,392
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw -1 ;结束
mus_time2 dw 3 dup(10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,40h)
dw 10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,20h
; 新年好
mus_freq3 dw 262,262,262,196
dw 330,330,330,262
dw 262,330,392,392
dw 349,330,294
dw 294,330,349,349
dw 330,294,330,262
dw 262,330,294,196
dw 247,294,262
dw -1 ;结束
mus_time3 dw 3 dup(12,12,25,25),12,12,50
dw 3 dup(12,12,25,25),12,12,50
; 直接定址表
table dw m1, m2, m3
.code
main proc
;===========================宏定义===========================
; # PUSH ax bx cx dx
pushall macro
push ax
push bx
push cx
push dx
endm
; # POP dx cx bx ax
popall macro
pop dx
pop cx
pop bx
pop ax
endm
; # 设置光标位置
point macro row, column
pushall
mov ah, 02h ;INT10h的2号中断-设置光标位置
mov bh, 0 ;页码-第0页
mov dh, row ;行Y -第row行
mov dl, column ;列X -第column列
int 10h
popall
endm
; # 显示到屏幕 '$'结尾
print macro label
lea dx, label ;取偏移地址
mov ah, 09h ;21h的9号中断-显示字符串
int 21h
endm
; # 输出一个字符
putchar macro char
mov ah, 02h
mov dl, char
int 21h
endm
; # 输入一个字符
input_21h macro
mov ah, 0ch ;21h中断的c号功能 AL保存读入字符的ASCII码
mov al, 01h
int 21h
endm
; # 从键盘读入字符,AH保存扫描码 AL保存ASCII码
input_16h macro
mov ah, 10h
int 16h
endm
; # 进入下一行
newline macro
print nextline
endm
; # 选择功能显示
enter_cmd macro
newline
putchar '$'
putchar ' '
endm
setsidi macro S, D
lea si, S
lea di, D
endm
;==========================宏定义完==========================
start:
mov ax, @data
mov ds, ax
; 改中断例程入口地址
mov ax, 0
mov es, ax
push es:[9*4]
pop ds:[0]
push es:[9*4+2]
pop ds:[2]
mov word ptr es:[9*4], offset int9
mov es:[9*4+2], cs
begin:
call cls
point 6, 0
print menu
lop:
enter_cmd
input_21h
sub al, 48
cmp al, 0
je exit
call call_fun
jmp lop
exit:
; 恢复原来的地址
mov ax, 0
mov es, ax
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
call cls
mov ax, 4c00h
int 21h
main endp
; 定义中断例程
int9:
pushall
push es
in al, 60h
pushf
call dword ptr ds:[0]
cmp al, 03bh ;F1扫描码
jne int9ret
;改变颜色
mov ax, 0b800h
mov es, ax
mov bx, 1 ;指向显存属性单元
mov cx, 80*25 ;改变整个页面的颜色
s1:
inc byte ptr es:[bx] ;属性值+1
add bx, 2
loop s1
int9ret:
pop es
popall
iret
; @功能选择 al:选择的功能号
call_fun proc
f1:
cmp al, 1
jne f2
call cls
point 6, 0
print menu
jmp return
f2:
cmp al, 2
jne f3
; call piano
jmp return
f3:
cmp al, 3
jne f4
call choose_song
jmp return
f4:
cmp al, 4
jne f5
call display_time
call cls
point 6, 0
print menu
jmp return
f5:
cmp al, 5
jne f_
print tip5
jmp return
f_:
in al, 60h
cmp al, 3bh ;F1扫描码
je return
print error
return:
ret
call_fun endp
; @选择播放的歌曲
choose_song proc
call cls
point 7, 0
print songs_name
cc:
enter_cmd
ff:
input_16h
cmp ah, 3bh ;F1扫描码
je ff
cmp ah, 01h ;ESC扫描码
je over
cmp ah, 02h
je con
cmp ah, 03h
je con
cmp ah, 04h
je con
; print error
jmp ff
con:
sub al, 48
mov bl, al
mov bh, 0
call play_music
; print play_finished
jmp cc
over:
call cls
point 6,0
print menu
ret
choose_song endp
play_music proc
add bx, bx
jmp word ptr table[bx-2]
m1:
setsidi mus_freq1, mus_time1
jmp play
m2:
setsidi mus_freq2, mus_time2
jmp play
m3:
setsidi mus_freq3, mus_time3
play:
mov dx, [si]
cmp dx, -1
je end1play
in al, 60h
cmp al, 10h ;Q扫描码
je end2play
call sound
add si, 2
add di, 2
jmp play
end1play:
print play_finished
jmp endplay
end2play:
print play_exited
endplay:
ret
play_music endp
; @演奏一个音符 si频率 di音长
sound proc
pushall
; 8253 芯片(定时/计数器)的设置
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div word ptr [si] ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 设置8255芯片 控制扬声器的开/关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, [di] ;保持[di]时长
delay:
mov cx, 7000h
wait_:
nop
loop wait_
dec dx
jnz delay
off:
mov al, ah ;恢复扬声器端口原值
out 61h, al
popall
ret
sound endp
; @清屏
cls proc
push ax
mov ah, 0fh ;BIOS-读取显示器模式
int 10h ;出口参数之一AL为显示模式
mov ah, 0h ;BIOS-设置显示器模式
int 10h ;入口参数AL为显示模式(已保存)
pop ax
ret
cls endp
; cls proc
; pushall
; mov ax, 0600h ;向上滚行清窗口
; mov bh, 3ch
; mov cx, 0000h ;左上角位置(Y,X)
; mov dx, 184fh ;右下角位置(Y,X)
; int 10h
; popall
; ret
; cls endp
; 显示系统日期和时间
display_time proc
pushall
push es
push si
show:
; mov al, 8
; mov si, 0
; call disp_num
; mov byte ptr es:[4], '.'
; mov byte ptr es:[5], 01001111b
; mov al, 7
; mov si, 6
; call disp_num
; mov byte ptr es:[10], ' '
; mov byte ptr es:[11], 01001111b
; mov al, 4
; mov si, 12
; call disp_num
; mov byte ptr es:[16], ':'
; mov byte ptr es:[17], 01001111b
; mov al, 2 ;分
; mov si, 18
; call disp_num
; mov byte ptr es:[22], ':'
; mov byte ptr es:[23], 01001111b
; mov al, 0 ;秒
; mov si, 24
; call disp_num
mov ax, 0b800h
mov es, ax
mov si, 0
mov al, 8
call disp_num
add si, 6
mov al, 7
call disp_num
add si, 6
mov al, 4
call disp_num
add si, 6
mov al, 2
call disp_num
in al, 60h
cmp al, 11h ;W扫描码
je r
jmp short show
r:
pop si
pop es
popall
ret
display_time endp
disp_num proc
out 70h, al
in al, 71h
mov ah, al
mov cl, 4
shr ah, cl
and al, 00001111b
add ah, 30h
add al, 30h
mov bx, 0b800h
mov es, bx
mov byte ptr es:[160*12+40*2+si], ah
mov byte ptr es:[160*12+40*2+si+1], 01001111b
mov byte ptr es:[160*12+40*2+si+2], al
mov byte ptr es:[160*12+40*2+si+2+1], 01001111b
mov byte ptr es:[160*12+40*2+si+4], '/'
mov byte ptr es:[160*12+40*2+si+4+1], 01001111b
ret
disp_num endp
end start
3.0
title main(exe)
.8086
.model small
.stack 100H
.data
dw ?, ? ;存原中断入口地址
flag db 0
menu db 22 dup(0), 0c9h, 34 dup(0cdh), 0bbh, 10, 13
db 22 dup(0), 0bah, ' Menu ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 1.Clear the screen. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 2.Play like a piano. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 3.Select a song to play. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 4.Displays the current time. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 5.Press F1 to change the color.', 0bah, 10, 13
db 22 dup(0), 0bah, ' 0.Exit the program. ', 0bah, 10, 13
db 22 dup(0), 0c8h, 34 dup(0cdh), 0bch, 10, 13
tips db 10, 13, 22 dup(0), 'Please enter a number from 0 to 4. ', 14, 10, 13, '$'
tip5 db ' Press F1 to change the color.', '$'
nextline db 10, 13, 22 dup(0), '$'
error db ' Error! Please re-enter.', '$'
songs_name db 22 dup(0), ' Song track ', 10, 13
db 22 dup(0), '1.Two tigers.(liang zhi lao hu) ', 10, 13
db 22 dup(0), '2.Whitewasher.(fen shua jiang) ', 10, 13
db 22 dup(0), '3.A Good New Year.(xin nian hao) ', 10, 13
db 10, 13
db 22 dup(0), ' Press ESC to exit. ', 10, 13
db 10, 13, '$'
play_finished db ' Play finished.', '$'
; 两只老虎
mus_freq1 dw 2 dup(262,294,330,262)
dw 2 dup(330,349,392)
dw 2 dup(392,440,392,349,330,262)
dw 2 dup(294,196,262)
dw -1 ;结束
mus_time1 dw 2 dup(20,20,20,20)
dw 2 dup(20,20,40)
dw 2 dup(10,10,10,10,20,20)
dw 2 dup(20,20,40)
; 粉刷匠
mus_freq2 dw 392,330,392,330,392,330,262
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw 294,294,349,349,330,262,392
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw -1 ;结束
mus_time2 dw 3 dup(10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,40h)
dw 10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,20h
; 新年好
mus_freq3 dw 262,262,262,196
dw 330,330,330,262
dw 262,330,392,392
dw 349,330,294
dw 294,330,349,349
dw 330,294,330,262
dw 262,330,294,196
dw 247,294,262
dw -1 ;结束
mus_time3 dw 3 dup(12,12,25,25),12,12,50
dw 3 dup(12,12,25,25),12,12,50
; 直接定址表
table dw m1, m2, m3
.code
main proc
;===========================宏定义===========================
; # 设置光标位置
point macro row, column
push ax
push bx
push cx
push dx
mov ah, 02h ;INT10h的2号中断-设置光标位置
mov bh, 0 ;页码-第0页
mov dh, row ;行Y -第row行
mov dl, column ;列X -第column列
int 10h
pop dx
pop cx
pop bx
pop ax
endm
; # 显示到屏幕 '$'结尾
print macro label
lea dx, label ;取偏移地址
mov ah, 09h ;21h的9号中断-显示字符串
int 21h
endm
; # 输出一个字符
putchar macro char
mov ah, 02h
mov dl, char
int 21h
endm
; # 输入一个字符
input_21h macro
mov ah, 0ch ;21h中断的c号功能 AL保存读入字符的ASCII码
mov al, 01h
int 21h
endm
; # 从键盘读入字符,AH保存扫描码 AL保存ASCII码
input_16h macro
mov ah, 10h
int 16h
endm
; # 进入下一行
newline macro
print nextline
endm
; # 选择功能显示
enter_cmd macro
newline
putchar '$'
putchar ' '
endm
setsidi macro S, D
lea si, S
lea di, D
endm
;==========================宏定义完==========================
start:
mov ax, @data
mov ds, ax
; 改中断例程入口地址
mov ax, 0
mov es, ax
push es:[9*4]
pop ds:[0]
push es:[9*4+2]
pop ds:[2]
mov word ptr es:[9*4], offset int9
mov es:[9*4+2], cs
call cls
point 6, 0
print menu
lop:
enter_cmd
input_21h
sub al, 48
cmp al, 0
je exit
call call_fun
jmp lop
exit:
; 恢复原来的地址
mov ax, 0
mov es, ax
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
call cls
mov ax, 4c00h
int 21h
main endp
; ; 定义中断例程
; int9: push ax
; push bx
; push dx
; push es
; in al, 60h
; pushf
; pushf
; pop bx
; and bh, 11111100b
; push bx
; popf
; call dword ptr ds:[0]
; mov dl, al ;保存al
; ; cmp al,47h ; 47h是HOME键的扫描码
; ; jne ifend
; ; ;处理HOME
; ; lea dx, home
; ; mov ah,9
; ; int 21h
; ; jmp int9ret
; ; ifend:
; ; cmp dl, 4Fh ;4Fh是end键的扫描码
; ; jne int9ret
; ; ;处理END,使程序结束,注意在此要恢复中断向量
; ; mov ax,0
; ; mov es,ax
; ; push ds:[0]
; ; pop es:[9*4]
; ; push ds:[2]
; ; pop es:[9*4+2]
; ; mov ax,4c00h
; ; int 21h
; int9ret:
; pop es
; pop dx
; pop bx
; pop ax
; iret
; 定义中断例程
int9:
push ax
push bx
push cx
push es
in al, 60h
pushf
call dword ptr ds:[0]
cmp al, 03bh ;F1扫描码
jne int9ret
;改变颜色
mov ax, 0b800h
mov es, ax
mov bx, 1 ;指向显存属性单元
mov cx, 80*25 ;改变整个页面的颜色
s:
inc byte ptr es:[bx] ;属性值+1
add bx, 2
loop s
int9ret:
pop es
pop cx
pop bx
pop ax
iret
; @功能选择 al:选择的功能号
call_fun proc
f1:
cmp al, 1
jne f2
call cls
point 6,0
print menu
jmp return
f2:
cmp al, 2
jne f3
; call piano
jmp return
f3:
cmp al, 3
jne f4
call choose_song
jmp return
f4:
cmp al, 4
jne f5
call display_time
jmp return
f5:
cmp al, 5
jne f_else
print tip5
jmp return
f_else:
in al, 60h
cmp al, 3bh ;F1扫描码
je return
print error
return:
ret
call_fun endp
; @选择播放的歌曲
choose_song proc
call cls
point 7, 0
print songs_name
cc:
enter_cmd
ff:
input_16h
cmp ah, 3bh ;F1扫描码
je ff
cmp ah, 01h ;ESC扫描码
je over
cmp ah, 02h
je con
cmp ah, 03h
je con
cmp ah, 04h
je con
; print error
jmp ff
con:
sub al, 48
mov bl, al
mov bh, 0
call play_music
print play_finished
jmp cc
over:
call cls
point 6,0
print menu
ret
choose_song endp
play_music proc
add bx, bx
jmp word ptr table[bx-2]
m1:
setsidi mus_freq1, mus_time1
jmp play
m2:
setsidi mus_freq2, mus_time2
jmp play
m3:
setsidi mus_freq3, mus_time3
play:
mov dx, [si]
cmp dx, -1
je end_play
call sound
add si, 2
add di, 2
jmp play
end_play:
ret
play_music endp
; @演奏一个音符 si频率 di音长
sound proc
push ax
push dx
push cx
; 8253 芯片(定时/计数器)的设置
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div word ptr [si] ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 设置8255芯片 控制扬声器的开/关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, [di] ;保持[di]时长
delay:
mov cx, 7000h
wait_:
nop
loop wait_
dec dx
jnz delay
mov al, ah ;恢复扬声器端口原值
out 61h, al
pop cx
pop dx
pop ax
ret
sound endp
; @清屏
cls proc
push ax
mov ah, 0fh ;BIOS-读取显示器模式
int 10h ;出口参数之一AL为显示模式
mov ah, 0h ;BIOS-设置显示器模式
int 10h ;入口参数AL为显示模式(已保存)
pop ax
ret
cls endp
; 显示系统日期和时间
display_time proc
push ax
push bx
push cx
push dx
push es
show:
mov al, 2 ;分
out 70h, al
in al, 71h
mov ah, al
mov cl, 4
shr ah, cl
and al, 00001111b
add ah, 30h
add al, 30h
mov bx, 0b800h
mov es, bx
mov byte ptr es:[0], ah
mov byte ptr es:[1], 01001111b
mov byte ptr es:[2], al
mov byte ptr es:[3], 01001111b
mov byte ptr es:[4], ':'
mov byte ptr es:[5], 01001111b
mov al, 0 ;秒
out 70h, al
in al, 71h
mov ah, al
mov cl, 4
shr ah, cl
and al, 00001111b
add ah, 30h
add al, 30h
mov bx, 0b800h
mov es, bx
mov byte ptr es:[6], ah
mov byte ptr es:[7], 01001111b
mov byte ptr es:[8], al
mov byte ptr es:[9], 01001111b
jmp show
r:
pop es
pop dx
pop cx
pop bx
pop ax
ret
display_time endp
end start
1.0
title main(exe)
extrn play_music:far
.8086
.model small
.stack 1000H
.data
dw 0, 0 ;存原中断入口地址
menu db 22 dup(0), 0c9h, 34 dup(0cdh), 0bbh, 10, 13
db 22 dup(0), 0bah, ' Menu ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 1.Play like a piano. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 2.Select a song to play. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 3.Displays the current time. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 4.Press F1 to change the color.', 0bah, 10, 13
db 22 dup(0), 0bah, ' 0.Exit the program. ', 0bah, 10, 13
db 22 dup(0), 0c8h, 34 dup(0cdh), 0bch, 10, 13
tips db 10, 13, 22 dup(0), 'Please enter a number from 0 to 4. ', 14, 10, 13, '$'
nextline db 10, 13, 22 dup(0), '$'
error db ' Error! Please re-enter.', '$'
songs_name db 22 dup(0), ' Song track ', 10, 13
db 22 dup(0), '1.Two tigers.(liang zhi lao hu) ', 10, 13
db 22 dup(0), '2.Whitewasher.(fen shua jiang) ', 10, 13
db 22 dup(0), '3.A Good New Year.(xin nian hao) ', 10, 13
db 10, 13
db 22 dup(0), ' Press ESC to exit. ', 10, 13
db 10, 13, '$'
play_finished db ' Play finished.', '$'
.code
main proc
;===========================宏定义===========================
; # 设置光标位置
point macro row, column
push ax
push bx
push cx
push dx
mov ah, 02h ;INT10h的2号中断-设置光标位置
mov bh, 0 ;页码-第0页
mov dh, row ;行Y -第row行
mov dl, column ;列X -第column列
int 10h
pop dx
pop cx
pop bx
pop ax
endm
; # 显示到屏幕 '$'结尾
print macro label
lea dx, label ;取偏移地址
mov ah, 09h ;21h的9号中断-显示字符串
int 21h
endm
; # 输出一个字符
putchar macro char
mov ah, 02h
mov dl, char
int 21h
endm
; # 输入一个字符
input_21h macro
; mov ah, 0ch ;21h中断的c号功能 AL保存读入字符的ASCII码
; mov al, 01h
mov ah, 08h
int 21h
endm
; # 从键盘读入字符,AH保存扫描码 AL保存ASCII码
input_16h macro
mov ah, 10h
int 16h
endm
; # 进入下一行
newline macro
print nextline
endm
; # 选择功能显示
enter_cmd macro
newline
putchar '$'
putchar ' '
endm
;==========================宏定义完==========================
start:
mov ax, @data
mov ds, ax
mov es, ax
; 改中断例程入口地址
mov ax, 0
mov es, ax
push es:[9*4]
pop ds:[0]
push es:[9*4+2]
pop ds:[2]
mov word ptr es:[9*4], offset int9
mov es:[9*4+2], cs
call cls
point 7, 0
print menu
l1:
enter_cmd
l2:
input_21h ;输入数字
sub al, 48 ;ASCII码转数字
cmp al, 0 ;判断0退出
je exit
f1:
cmp al, 1
jne f2
; call piano
jmp l1
f2:
cmp al, 2
jne f3
call choose_song
jmp l1
f3:
cmp al, 3
jne f4
; call time
jmp l1
f4:
cmp al, 4
jne f_else
; call change_color
jmp l1
f_else:
; print error
jmp l2
exit:
; 恢复原来的地址
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
mov ax, 4c00h
int 21h
main endp
; 定义中断例程
int9:
push ax
push bx
push es
in al, 60h
pushf
call dword ptr ds:[0] ;调用旧中断例程
cmp al, 03bh ;F1扫描码
jne int9ret
;改变颜色
mov ax, 0b800h
mov es, ax
; inc byte ptr es:[160*12+40*2+1]
mov bx, 1 ;指向显存属性单元
mov cx, 80*25 ;改变整个页面的颜色
s:
inc byte ptr es:[bx] ;属性值+1
add bx, 2
loop s
int9ret:
pop es
pop bx
pop ax
iret
; @选择播放的歌曲
choose_song proc
call cls
point 7,0
print songs_name
cc:
enter_cmd
ff:
input_16h
cmp ah, 3bh ;F1扫描码
je ff
cmp ah, 01h ;ESC扫描码
je over
cmp ah, 02h
je con
cmp ah, 03h
je con
cmp ah, 04h
je con
print error
jmp cc
con:
sub al, 48
mov bl, al
mov bh, 0
call far ptr play_music
print play_finished
jmp cc
over:
call cls
point 7,0
print menu
ret
choose_song endp
; @清屏
cls proc
push ax
mov ah, 0fh ;BIOS-读取显示器模式
int 10h ;出口参数之一AL为显示模式
mov ah, 0h ;BIOS-设置显示器模式
int 10h ;入口参数AL为显示模式(已保存)
pop ax
ret
cls endp
end start
title sing(exe)
public play_music
.8086
.model small
.stack 10H
.data
; 两只老虎
mus_freq1 dw 2 dup(262,294,330,262)
dw 2 dup(330,349,392)
dw 2 dup(392,440,392,349,330,262)
dw 2 dup(294,196,262)
dw -1 ;结束
mus_time1 dw 2 dup(20,20,20,20)
dw 2 dup(20,20,40)
dw 2 dup(10,10,10,10,20,20)
dw 2 dup(20,20,40)
; 粉刷匠
mus_freq2 dw 392,330,392,330,392,330,262
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw 294,294,349,349,330,262,392
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw -1 ;结束
mus_time2 dw 3 dup(10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,40h)
dw 10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,20h
; 新年好
mus_freq3 dw 262,262,262,196
dw 330,330,330,262
dw 262,330,392,392
dw 349,330,294
dw 294,330,349,349
dw 330,294,330,262
dw 262,330,294,196
dw 247,294,262
dw -1 ;结束
mus_time3 dw 3 dup(12,12,25,25),12,12,50
dw 3 dup(12,12,25,25),12,12,50
; 直接定址表
table dw m1, m2, m3
.code
; 宏定义
setsidi macro S,D
lea si, S
lea di, D
endm
; @播放音乐 入口参数bx:选第几首歌
play_music proc
mov ax, @data
mov ds, ax
add bx, bx
jmp word ptr table[bx-2]
m1: setsidi mus_freq1, mus_time1
jmp play
m2: setsidi mus_freq2, mus_time2
jmp play
m3: setsidi mus_freq3, mus_time3
play:
mov dx, [si]
cmp dx, -1
je end_play
call sound
add si, 2
add di, 2
jmp play
end_play:
retf
play_music endp
; @演奏一个音符 si频率 di音长
sound proc
push ax
push dx
push cx
; 8253 芯片(定时/计数器)的设置
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div word ptr [si] ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 设置8255芯片 控制扬声器的开/关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, [di] ;保持[di]时长
delay:
mov cx, 7000h
wait_:
nop
loop wait_
dec dx
jnz delay
mov al, ah ;恢复扬声器端口原值
out 61h, al
pop cx
pop dx
pop ax
ret
sound endp
end
2.0 无中断
title main(exe)
extrn play_music:far
.8086
.model small
.stack 1000H
.data
dw 0, 0 ;存原中断入口地址
menu db 22 dup(0), 0c9h, 34 dup(0cdh), 0bbh, 10, 13
db 22 dup(0), 0bah, ' Menu ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 1.Play like a piano. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 2.Select a song to play. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 3.Displays the current time. ', 0bah, 10, 13
db 22 dup(0), 0bah, ' 4.Press F1 to change the color.', 0bah, 10, 13
db 22 dup(0), 0bah, ' 0.Exit the program. ', 0bah, 10, 13
db 22 dup(0), 0c8h, 34 dup(0cdh), 0bch, 10, 13
tips db 10, 13, 22 dup(0), 'Please enter a number from 0 to 4. ', 14, 10, 13, '$'
nextline db 10, 13, 22 dup(0), '$'
error db ' Error! Please re-enter.', '$'
songs_name db 22 dup(0), ' Song track ', 10, 13
db 22 dup(0), '1.Two tigers.(liang zhi lao hu) ', 10, 13
db 22 dup(0), '2.Whitewasher.(fen shua jiang) ', 10, 13
db 22 dup(0), '3.A Good New Year.(xin nian hao) ', 10, 13
db 10, 13
db 22 dup(0), ' Press ESC to exit. ', 10, 13
db 10, 13, '$'
play_finished db ' Play finished.', '$'
tip5 db 'Press F1 to change the color.', '$'
.code
main proc
;===========================宏定义===========================
; # 设置光标位置
point macro row, column
push ax
push bx
push cx
push dx
mov ah, 02h ;INT10h的2号中断-设置光标位置
mov bh, 0 ;页码-第0页
mov dh, row ;行Y -第row行
mov dl, column ;列X -第column列
int 10h
pop dx
pop cx
pop bx
pop ax
endm
; # 显示到屏幕 '$'结尾
print macro label
lea dx, label ;取偏移地址
mov ah, 09h ;21h的9号中断-显示字符串
int 21h
endm
; # 输出一个字符
putchar macro char
mov ah, 02h
mov dl, char
int 21h
endm
; # 输入一个字符
input_21h macro
mov ah, 0ch ;21h中断的c号功能 AL保存读入字符的ASCII码
mov al, 01h
int 21h
endm
; # 从键盘读入字符,AH保存扫描码 AL保存ASCII码
input_16h macro
mov ah, 10h
int 16h
endm
; # 进入下一行
newline macro
print nextline
endm
; # 选择功能显示
enter_cmd macro
newline
putchar '$'
putchar ' '
endm
;==========================宏定义完==========================
start:
mov ax, @data
mov ds, ax
mov es, ax
; ; 改中断例程入口地址
; mov ax, 0
; mov es, ax
; push es:[9*4]
; pop ds:[0]
; push es:[9*4+2]
; pop ds:[2]
; mov word ptr es:[9*4], offset int9
; mov es:[9*4+2], cs
call cls
point 7, 0
print menu
lop:
enter_cmd
input_21h
sub al, 48
cmp al, 0
je exit
call call_fun
jmp lop
exit:
; 恢复原来的地址
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
mov ax, 4c00h
int 21h
main endp
; ; 定义中断例程
; int9:
; push ax
; push bx
; push es
; in al, 60h
; pushf
; call dword ptr ds:[0]
; cmp al, 03bh ;F1扫描码
; jne int9ret
; ;改变颜色
; mov ax, 0b800h
; mov es, ax
; mov bx, 1 ;指向显存属性单元
; mov cx, 80*25 ;改变整个页面的颜色
; s:
; inc byte ptr es:[bx] ;属性值+1
; add bx, 2
; loop s
; int9ret:
; pop es
; pop bx
; pop ax
; iret
; @功能选择 al:选择的功能号
call_fun proc
f1:
cmp al, 1
jne f2
; call piano
jmp return
f2:
cmp al, 2
jne f3
call choose_song
jmp return
f3:
cmp al, 3
jne f4
; call time
jmp return
f4:
cmp al, 4
jne f_else
; call change_color
jmp return
f_else:
print error
return:
ret
call_fun endp
; @选择播放的歌曲
choose_song proc
call cls
point 7,0
print songs_name
cc:
enter_cmd
ff:
input_16h
cmp ah, 3bh ;F1扫描码
je ff
cmp ah, 01h ;ESC扫描码
je over
cmp ah, 02h
je con
cmp ah, 03h
je con
cmp ah, 04h
je con
; print error
jmp ff
con:
sub al, 48
mov bl, al
mov bh, 0
call far ptr play_music
print play_finished
jmp cc
over:
call cls
point 7,0
print menu
ret
choose_song endp
; @清屏
cls proc
push ax
mov ah, 0fh ;BIOS-读取显示器模式
int 10h ;出口参数之一AL为显示模式
mov ah, 0h ;BIOS-设置显示器模式
int 10h ;入口参数AL为显示模式(已保存)
pop ax
ret
cls endp
end start
title sing(exe)
public play_music
.8086
.model small
.stack 10H
.data
; 两只老虎
mus_freq1 dw 2 dup(262,294,330,262)
dw 2 dup(330,349,392)
dw 2 dup(392,440,392,349,330,262)
dw 2 dup(294,196,262)
dw -1 ;结束
mus_time1 dw 2 dup(20,20,20,20)
dw 2 dup(20,20,40)
dw 2 dup(10,10,10,10,20,20)
dw 2 dup(20,20,40)
; 粉刷匠
mus_freq2 dw 392,330,392,330,392,330,262
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw 294,294,349,349,330,262,392
dw 294,349,330,294,392
dw 392,330,392,330,392,330,262
dw 294,349,330,294,262
dw -1 ;结束
mus_time2 dw 3 dup(10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,40h)
dw 10h,10h,10h,10h,10h,10h,20h,10h,10h,10h,10h,20h
; 新年好
mus_freq3 dw 262,262,262,196
dw 330,330,330,262
dw 262,330,392,392
dw 349,330,294
dw 294,330,349,349
dw 330,294,330,262
dw 262,330,294,196
dw 247,294,262
dw -1 ;结束
mus_time3 dw 3 dup(12,12,25,25),12,12,50
dw 3 dup(12,12,25,25),12,12,50
; 直接定址表
table dw m1, m2, m3
.code
; 宏定义
setsidi macro S,D
lea si, S
lea di, D
endm
; @播放音乐 入口参数bx:选第几首歌
play_music proc
mov ax, @data
mov ds, ax
add bx, bx
jmp word ptr table[bx-2]
m1: setsidi mus_freq1, mus_time1
jmp play
m2: setsidi mus_freq2, mus_time2
jmp play
m3: setsidi mus_freq3, mus_time3
play:
mov dx, [si]
cmp dx, -1
je end_play
call sound
add si, 2
add di, 2
jmp play
end_play:
retf
play_music endp
; @演奏一个音符 si频率 di音长
sound proc
push ax
push dx
push cx
; 8253 芯片(定时/计数器)的设置
mov al, 0b6h ;8253初始化
out 43h, al ;43H是8253芯片控制口的端口地址
mov dx, 12h
mov ax, 34dch
div word ptr [si] ;计算分频值,赋给ax
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
; 设置8255芯片 控制扬声器的开/关
in al, 61h ;读取8255 B端口原值
mov ah, al ;保存原值
or al, 3 ;使低两位置1,以便打开开关
out 61h, al ;开扬声器, 发声
mov dx, [di] ;保持[di]时长
delay:
mov cx, 7000h
wait_:
nop
loop wait_
dec dx
jnz delay
mov al, ah ;恢复扬声器端口原值
out 61h, al
pop cx
pop dx
pop ax
ret
sound endp
end