学校举办了汇编竞赛,因为兴趣,我参加了,记录一下。
我写的是一个弹钢琴的小程序,程序比较简单。由于水平有限,程序中有的地方是借鉴网上的一些例子,光让我写我闷头写还真写不出来。
程序的内容就是通过键盘的输入,发出各种音调。键盘的1 ~ 7(不是小键盘),q ~ u分别对应不同的音调,以特定的节奏按下可以演奏音乐。这里附上小星星的简谱:1155665,4422331,5544332,5544332,1155665,4433221。
由于比赛的那段时间事多,所以写的代码没注释,这次记录的同时再补上注释。
data segment
describe db 'piano key: 1~7,q~u'
db 0dh,0ah,'exit: 9'
db 0dh,0ah,'this is a procedure that play music'
db 0dh,0ah,'please input number for music__','$'
tone_1 dw 882,-1 ;定义音调
tone_2 dw 990,-1
tone_3 dw 1112,-1
tone_4 dw 1178,-1
tone_5 dw 1322,-1
tone_6 dw 1484,-1
tone_7 dw 1655,-1
tone_q dw 441,-1
tone_w dw 495,-1
tone_e dw 556,-1
tone_r dw 589,-1
tone_t dw 661,-1
tone_y dw 742,-1
tone_u dw 833,-1
data ends
stack segment
db 200 dup('stack')
stack ends
code segment
assume ds:data,ss:stack,cs:code
start: mov ax,data
mov ds,ax
mov ah,0 ;设置显示模式
mov al,03h ;文字,80*25*16色
int 10h
;定义一个宏
show macro b
lea dx,b
mov ah,9
int 21h
endm
;定义声音宏
sound macro sou,jumpto,char
cmp al,char ;匹配输入的字符
jnz jumpto ;不相等就跳到jumpto继续匹配
lea si,sou ;将音调的偏移存储在si中
call music
jmp input
endm
show describe ;调用宏
input: mov ah,01h
int 21h
cmp al,'9' ;是否退出
jnz go1
mov ah,4ch ;返回DOS
int 21h
go1:sound tone_1,go2,'1'
go2:sound tone_2,go3,'2'
go3:sound tone_3,go4,'3'
go4:sound tone_4 go5,'4'
go5:sound tone_5,go6,'5'
go6:sound tone_6,go7,'6'
go7:sound tone_7,goq,'7'
goq:sound tone_q,gow,'q'
gow:sound tone_w,goe,'w'
goe:sound tone_e,gor,'e'
gor:sound tone_r,got,'r'
got:sound tone_t,goy,'t'
goy:sound tone_y,gou,'y'
gou:sound tone_u,gon,'u'
gon:jmp input
play proc near
push ax
push bx
push dx
push di
mov al,0b6h
out 43h,al ;初始化定时器
mov dx,12h
mov ax,348ch
div di ;计算出AX=(DX+AX)/DI
out 42h,al ;将ax分为高低两位存储在
mov al,ah ;42h端口中,由此可以得到
out 42h,al ;输出的频率
in al,61h
or al,3 ;给61h端口写入11,打开定时器和开关
out 61h,al
mov ah,0
int 1ah ;ah==0时,读当前时钟值CX:DX
add dx,6 ;计数器从0加到6需要大约1/3秒的时间,
mov bx,dx ;这也就是每个音调播放的时间
delay: int 1ah
cmp dx,bx ;再次取得当前计数器的值,如果计数值==6
jne delay ;延时结束
mov al,1 ;关掉扬声器
out 61h,al
pop ax
pop bx
pop dx
pop di
ret
play endp
music proc near
sub ax,ax ;将ax清零,没有这句程序会异常停止
push ax ;ax入栈,没有这句回显的字符会一直存在
s: mov di,[si] ;ds[si]存储的是音调的地址
cmp di,-1 ;-1为播放结束的标志
je end_music ;结束播放
call play ;调用play开始播放音调
add si,2 ;播放完后si+2,即si==-1
jmp s
end_music: ret ;函数返回
music endp
code ends
end start
由于是借鉴了一点网上的例子,不免有问题,问题就是在music函数的开头两句sub ax,ax和push ax;
sub ax,ax ;将ax清零,没有这句程序会异常停止
push ax ;ax入栈,没有这句回显的字符会一直存在
但是我一直想不出为啥去掉sub ax,ax程序会异常停止,没有push ax 回显的字符会一直存在。
如果有大佬知道希望不吝赐教。
下面是程序的流程图: