; 單片機音樂應用 ;
;******************************;
ORG 0000H ;主程序起始地址
JMP START ;跳至主程序
ORG 000BH ;TIMER0中斷起始地址
JMP TIM0 ;跳至TIMER0中斷起始地址
START: MOV TMOD,#00000001B ;設TIMER0在MODE1
MOV IE,#10000010B ;中斷使能
START0: MOV 30H,#00 ;起簡譜碼指針
NEXT: MOV A,30H ;簡譜碼指針載入A
MOV DPTR,#TABLE ;至TABLE取簡譜碼
MOVC A,@A+DPTR
MOV R2,A ;取到的簡譜碼暫存於R2
JZ END0 ;是否取到00(結束碼)?
ANL A,#0FH ;不是,則取低4位(節拍碼)
MOV R5,A ;將節拍碼存入R5
MOV A,R2 ;將取到的簡譜碼再載入A
SWAP A ;高低4位交換
ANL A,#0FH ;取低4位(音符碼)
JNZ SING ;取到的音符碼是否為0?
CLR TR0 ;是,則不發音
JMP D1 ;跳至D1
SING: DEC A ;取到的音符碼減1(不含0)
MOV 22H,A ;存入(22H)
RL A ;乘2
MOV DPTR,#TABLE ;至TABLE1取相對的高位字節計數值
MOVC A,@A+DPTR
MOV TH0,A ;取到的高位字節存入TH0
MOV 21H,A ;取到的高位字節存入(21H)
MOV A,22H ;再載入取到的音符碼
RL A ;乘2
INC A ;加1
MOVC A,@A+DPTR ;至TABLE1取相對的低位字節計數值
MOV TL0,A ;取到的低位字節存入TL0
MOV 20H,A ;取到的低位字節存入(20H)
SETB TR0 ;啟動TIMER0
D1: CALL DELAY ;基本單位時間1/4拍187毫秒
INC 30H ;取簡譜碼指針加1
JMP NEXT ;取下壹個碼
END0: CLR TR0 ;停止TIMER0
JMP START0 ;重復循環
TIM0: PUSH ACC ;將A的值暫存於堆棧
PUSH PSW ;將PSW的值暫存於堆棧
MOV TL0,20H ;重設計數值
MOV TH0,21H
CPL P1.0 ;將P1.0位反相
POP PSW ;至堆棧取回PSW的值
POP ACC ;至堆棧取回A的值
RETI ;返回主程序
DELAY: MOV R7,#02
D2: MOV R4,#125 ;要延長的時間(毫秒)數
D3: MOV R3,#248
DJNZ R3,$
DJNZ R4,D3
DJNZ R7,D2
DJNZ R5,DELAY ;決定節拍
RET
TABLE1: DW 64260,64400,64524,64580
DW 64684,64777,64820,64898
DW 64968,65030,65058,65110
DW 65157,65178,65217
TABLE: DB 82H,01H,81H,94H,84H
DB 0B4H,0A4H,04H
DB 82H,01H,81H,94H,84H
DB 0C4H,0B4H,04H
END