📄 单片机演奏多首音乐通用程序.asm
字号:
org 00h
;mov 96h,#00111111b;p2M1
mov 8eh,#0 ;允许使用内部扩展的ram
jmp cfg
org 0bh
jmp t0int
org 1bh
jmp t1int
;40保存设定时间,41保存A分数,42保存B分数,43保存当前时间(正在计时),44保存发声地址
cfg: mov 55h,#20
mov 40h,#30 ;开机时的初始分数
mov 41h,#00 ;左计分
mov 42h,#00 ;右计分
mov 43h,#30 ;读取初始时间从40读来
mov 5dh,#14;发开机声,可以分别查表不同的发声频率,不同的发声时间
mov r2,#1;工作模式,单机分别模式双机同时模式
mov tmod,#00100010b;t1工作方式二自动装入
mov th0,#245 ;12MHz时,1US*50=50us(20KHz,0.05ms)扫描一下转向记数
setb tr0
setb et0
setb ea
main:
call js
call disp
call key1
call key2
call key3
call run1
jb 10h, main
call run2
call run3
jmp main
key1:jb 09h,k1edd
setb 09h
jb p2.7,k1ed
jb 08h,k1edd
setb 08h
mov r0,#15
mov a,40h
cjne a,#90,rr10
mov 40h,#15
rr10:inc 40h
djnz r0,rr10
mov 43h,40h
clr 11h ;允许倒计时和加分
ret
k1ed:clr 08h
k1edd:ret
key2:
k2ed:ret
key3:
k3ed:ret
run1:jb 0fh,r1ed
setb 0fh
dec 43h
clr 10h ;允许计分
mov a,43h
cjne a ,#0, rrrr
setb 10h ;不许计分
setb 11h;还要加个不充再减
rrrr:mov a,#10
cjne a,43h,$+3
jc r1ed
mov 5dh ,#0 ;发声
r1ed:ret
run2:
jb 0dh,r2ed
setb 0dh
jb p3.1,r3ed
jb p3.0,r3ed
inc 41h
inc 41h
mov 5dh ,#2 ;发声
mov a,#10
cjne a,43h,$+3
jc r2ed
inc 41h
r2ed:ret
run3:
jb 0bh,r3ed
setb 0bh
jb p3.2,r3ed
jb p3.3,r3ed
inc 42h
inc 42h
mov 5dh ,#4 ;发声
mov a,#10
cjne a,43h,$+3
jc r3ed
inc 42h
r3ed:ret
t1int:jmp $
mov th0,#(65535-1000)/255
mov tl0,#(65535-1000)
push acc
push psw
mov psw,#11000b
mov a,p2 ;设p2.6/p2.7检测,r6记录123顺序,3dh记录上一次值,21h记录检测的桉键值
anl a,#11000000b
ek0: cjne a,#00000000b,ek2 ;检查出现在的状态
cjne r6,#01000000b,ek1 ;查看上一次的状态
call inc1
ek1: cjne r6,#10000000b,ek2 ;查看上一次的状态
call dec1
ek2: cjne a,#01000000b,ek4 ;检查出现在的状态
cjne r6,#11000000b,ek3 ;查看上一次的状态
call inc1
ek3: cjne r6,#00000000b,ek4 ;查看上一次的状态
call dec1
ek4: cjne a,#11000000b,ek6 ;检查出现在的状态
cjne r6,#10000000b,ek5 ;查看上一次的状态
call inc1
ek5: cjne r6,#01000000b,ek6 ;查看上一次的状态
call dec1
ek6: cjne a,#10000000b,ek8 ;检查出现在的状态
cjne r6,#00000000b,ek7 ;查看上一次的状态
call inc1
ek7: cjne r6,#11000000b,ek8 ;查看上一次的状态
call dec1
ek8: mov r6,a ;将本次伯数据保存
mov a,42h
cjne a,#0,ek9
setb p2.0
jmp t0d
ek9: cpl p2.0
djnz 43h,t0d
mov 43h,#100
dec 42h
t0d: pop psw
pop acc
reti
t0int: push acc
push psw
cpl p2.6
call su1
pop psw
pop acc
djnz 57h,t0end
djnz 56h,t0end
clr 0dh
clr 0bh
mov 56h,#20
clr 09h
djnz 55h,t0end
mov 55h,#20
jb 11h,t0int ;高电平不允许计时
clr 0fh
t0end: reti
su1:mov a,5dh ;8音播放程序,58/59延时,59是0就停,5a分频系数,5b步数,5c分频,5d是N首两倍,是1停止,高频固定调用
cjne a,#1,su6 ;查看1新声音标志,5e/5f为当前表,占用资源ACC/PSW/DPTR/58H-5AH
mov a,59h
cjne a,#0,su7 ;查看0声音结束标志,
jmp su3
su2:mov a,5ah
cjne a,#0,su4 ;查看是否需要静音
su3:setb p2.0
ret
su4:djnz 5ch,su5 ;不需静音就分频发音
mov 5ch,5ah
cpl p2.0
su5:ret
su6:mov dptr,#sds ;查表看该唱哪一首歌
movc a,@a+dptr
mov 5eh,a
mov a,5dh
inc a
movc a,@a+dptr
mov 5fh,a
mov 5dh,#1 ;只查一次
mov 5bh,#0 ;从该首头开始放
jmp su8
su7:djnz 58h,su2 ;延时
mov 58h,#200 ;延时
djnz 59h,su2 ;发声时间减1到0后查下一步时间和音调
inc 5bh
su8:mov a,5bh ;发声的查表程序
mov dph,5eh ;装入当前首表地址
mov dpl,5fh ;装入当前首表地址
movc a,@a+dptr ;查出当前步时间和音调,上半字节为时间0为结束,下半字节为音调D为静音
mov 59h,a ;发声时间,结束标志为0,最长时间为15个单位,
anl a,#0fh ;进一步查出音调,
mov dptr,#sbb ;查音阶分频表,
movc a,@a+dptr
mov 5ah,a ;音调分频系数
mov a,59h ;再求出发生时间
anl a,#0f0h ;删除音调数据
ret
saa:db 255,227,203, 191,170,152,143,128,114,101, 96,85,76,0;高频晶振音阶分频数据,音准高
sbb:db 101,90, 81, 76, 67, 60, 57, 51, 45, 40, 38,34,30,0;低频晶振音阶分频数据,音准较差
;sbb:db 10,9, 8, 7, 6, 5, 4, 3, 2, 1, 38,34,30,0;低频晶振音阶分频数据,音准较差
sds:db sd1/255,sd1,sd2/255,sd2,sd3/255,sd3,sd4/255,sd4,sd5/255,sd5,sd6/255,sd6,sd7/255,sd7,sd8/255,sd8
sd1:db 48h,0;声音数据:前面是时间,0结束,后面是音调,d静音.
sd2:db 1ch,1dh,1ch,0
sd3:db 18h,1dh,18h,1dh,1ch,0
sd4:db 1ch,1dh,1ch,1dh,1ch,1dh,1ch,1dh,1ch,0
sd5:db 1ch,15h,1dh,1ch,15h,0
sd6:db 1ch,15h,1dh,1ch,15h,0
sd7:db 4ch,4bh,4ah,49h,48h,47h,46h,45h,44h,43h,42h,41h,40h,0
sd8:db 40h,41h,42h,43h,44h,45h,46h,47h,48h,49h,4ah,4bh,4ch,0;8音程序结束
inc1:mov 02h,#0 ;模式为0
inc 39h
mov r4 ,39h
cjne r4,#0,iend
inc 38h
iend:ret
dec1:mov 02h,#0 ;模式为0
dec 39h
mov r4 ,39h
cjne r4,#255,dend
dec 38h
dend:ret
d10ms:mov r7,#10
d1ms:djnz r6 ,$
djnz r7 ,d1ms
ret
js:
mov a,41h
mov b,#10
div ab
mov 30h,a
mov 31h,b
mov a,30h
mov b,#10
div ab
mov 30h,b
mov a,43h
mov b,#10
div ab
mov 32h,a
mov 33h,b
mov a,32h
mov b,#10
div ab
mov 32h,b
mov a,42h
mov b,#10
div ab
mov 34h,a
mov 35h,b
mov a,34h
mov b,#10
div ab
mov 34h,b
ret
disp:
djnz r7,$+4
mov r7,#6
mov a,r7
mov dptr,#tab1
movc a,@a+dptr
;mov p1,#0ffh
orl p1,#11111011b
;anl p2,#11000000b
anl a,#00111111b
;orl p2,a
;mov p2,a
mov a,r7
add a,#2fh
mov r0,a
mov a,@r0
mov dptr,#tab2
movc a,@a+dptr
mov c,p1.2
anl p1,a
mov p1.2,c
ret
tab1: db 11000000b,11000001b,11000010b,11000100b,11001000b,11010000b,11100000b
tab2: db 10000100b,11101110b,01000101b,01000110b,00101110b,00010110b,00010100b,11001110b,00000100b,00000110b,00001100b,00110100b,10010101b,01100100b,00010101b,00011101b,00000000b
ys00:djnz 50h,$
mov 50h,#10
djnz 51h, ys00
ret
TAB2b: DB 11H,0D7H,32H,92H,0D4H,98H,18H,0D3H,10H,90H,50H,1CH,39H,16H,38H,78H,0ffH,0ffh,0ffh,0ffh
tab1b:db 10b,1b,100b,10000b,1000b,100000b,1000000b,10000000b;2a 1b 5c 7d 6e 3f 4g
;tab2:db 10000b,11011100b,101000b,01001000b,11000100b,01000010b,10b,11011000b,0b,1000000b,11111110b,9;2a 1b 5c 7d 6e 3f 4g
tab3:db 0001000b,1101110b,0010100b,0100100b,1100010b,0100001b,0000001b,1101100b,0000000b,0100000b,1111111b
tab4:db 00010001b,01111101b,00100011b,00101001b,01001101b,10001001b,10000001b,00111101b,00000001b,00001001b,11111111b
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -