www.pudn.com > MUSIC_KEYI.rar > MUSIC_KEYI.ASM


;*******************************************************************************
; 基于AT89S51的多功能音乐演奏器的设计
;
;*******************************************************************************
M_BUF EQU 7FH ;曲目缓冲区
ALT_K EQU 0FH ;功能切换键号
NEXT_K EQU 0EH ;下一首功能键号
LAST_K EQU 0DH ;上一首功能键号
PAUSE_K EQU 0BH ;暂停功能键号
MUSIC_NUM EQU 03H ;总曲目数
F2 EQU 08H ;暂停标志位
TODAC EQU 6FH ;DAC0832缓冲区
;*******************************************************************************
ORG 0000H
LJMP MAIN ;转主程序
ORG 0003H
LJMP KEY_INT ;转键盘中断服务程序
ORG 000BH
LJMP T0_INT ;转定时器中断服务程序
;*******************************************************************************
; 主程序
;*******************************************************************************
MAIN:MOV M_BUF,#01H ;首先播放第一首乐曲
SETB PT0 ;设置定时器中断为高优先级
CLR PX0 ;设置外部中断0为低优先级
MAIN1:CLR EA ;关闭中断
CLR EX0
CLR ET0
CLR TR0 ;关闭定时器
MOV SP,#20H ;设置堆栈指针初值
MOV P1,#0FH ;键盘列线置低电平,准备读行线值
SETB EX0 ;开中断
SETB EA
JB F0,INT_WAIT ;功能判断
INT_MUSIC:LJMP MUSIC ;若F0=0,播放乐曲
INT_WAIT:SJMP $ ;若F0=1,等待电子琴键盘中断
;*******************************************************************************
; 乐曲发生子程序
;*******************************************************************************
MUSIC:MOV TMOD,#01H ;定时器工作在方式1
SETB ET0 ;定时器0中断允许
MOV A,M_BUF ;根据曲目缓冲区内容选曲
MT3:CJNE A,#03H,MT2
MOV DPTR,#MTAB3 ;MTAB3为第3首乐曲首地址
SJMP NEXT
MT2:CJNE A,#02H,MT1
MOV DPTR,#MTAB2 ;MTAB2为第2首乐曲首地址
SJMP NEXT
MT1:MOV DPTR,#MTAB1 ;MTAB1为第1首乐曲首地址
NEXT:CLR A ;准备查乐曲表
MOVC A,@A+DPTR ;查乐曲表音调部分
JZ REST ;若A=00H,则为休止符
CJNE A,#0FFH,CONTINUE ;若A=FFH,则为停止符
SJMP STOP
CONTINUE:MOV R2,A ;乐曲表音调部分暂存R2
LCALL COM_ADC ;取出电平均衡值
MOV A,R2
ANL A,#0FH ;乐曲表音调部分低四位表示高中低音
MOV B,#1CH ;7个基本音级要用28个字节表示
MUL AB ;高中低音乐曲表相对偏移首地址
MOV R3,A ;相对偏移首地址暂存R3
MOV A,R2 ;乐曲表音调部分送A
SWAP A ;高四位表示do、re、mi、fa、sol、la、si
ANL A,#0FH
RL A ;do、re、mi、fa、sol、la、si7个基本音级
RL A ;每个要四个字节表示
ADD A,R3 ;再加相对偏移首地址即为音调表中偏移地址
MOV R1,A ;音调表中偏移地址暂存R1
ADD A,#26H ;加查表指令到音调表首地址偏移量
MOVC A,@A+PC ;查音调表每个音调的第1个字节
MOV R2,A ;第1个字节为矩形波高电平定时初值高8位
MOV A,R1 ;音调表中偏移地址送A
ADD A,#22H
MOVC A,@A+PC ;查音调表每个音调的第2个字节
MOV R3,A ;第2个字节为矩形波高电平定时初值低8位
MOV A,R1 ;音调表中偏移地址送A
ADD A,#1EH
MOVC A,@A+PC ;查音调表每个音调的第3个字节
MOV R0,A ;第3个字节为矩形波低电平定时初值高8位
MOV A,R1 ;音调表中偏移地址送A
ADD A,#1AH
MOVC A,@A+PC ;查音调表每个音调的第4个字节
MOV R1,A ;第4个字节为矩形波低电平定时初值低8位
MOV TH0,R2 ;矩形波高电平定时初值送T0
MOV TL0,R3
SETB TR0 ;启动定时器0
SJMP METER
REST:CLR TR0 ;若为休止符关闭定时器0
METER:CLR A ;准备查乐曲表
INC DPTR ;乐曲表音调部分下一个字节为节拍部分
MOVC A,@A+DPTR ;查乐曲表节拍部分
MOV R4,A ;节拍部分表示乐曲中最小节拍的整数倍
METER1:LCALL DELAY ;调用最小节拍延时程序
DJNZ R4,METER1 ;本音调节拍时间为最小节拍的整数倍
INC DPTR ;准备查乐曲表的下一个音调
SJMP NEXT
STOP:CLR TR0 ;若为停止符关闭定时器0
SJMP MT1 ;重复演奏
;*******************************************************************************
; 音调表
;*******************************************************************************
MTAB:DW 0FCFAH,0F404H,0FD4DH,0F552H,0FD97H,0F67BH,0FDB9H;低音部分
DW 0F703H,0FDF8H,0F7FDH,0FE2FH,0F8DCH,0FE61H,0F9A2H;共28个字节
DW 0FE78H,0F9FDH,0FEA1H,0FAA4H,0FEC7H,0FB39H,0FED8H;中音部分
DW 0FB7DH,0FEF7H,0FBFAH,0FF13H,0FC69H,0FF2CH,0FCCCH;共28个字节
DW 0FF37H,0FCFAH,0FF4CH,0FD4DH,0FF5EH,0FD97H,0FF67H;高音部分
DW 0FDB9H,0FF76H,0FDF8H,0FF84H,0FE2FH,0FF91H,0FE61H;共28个字节
;*******************************************************************************
; 最小节拍延时子程序
;*******************************************************************************
DELAY:MOV 70H,#90H ;设晶振频率f=6MHz
DELAY1:MOV 71H,#00H
DJNZ 71H,$
DJNZ 70H,DELAY1
RET
;*******************************************************************************
; 定时器中断服务程序
;*******************************************************************************
T0_INT:JB F1, T0_INT1 ;F1=1,输出高电平;F1=0,输出低电平
MOV TH0,R0 ;矩形波低电平定时初值送T0
MOV TL0,R1
MOV P2,#00H
SJMP T0_INT2
T0_INT1:MOV TH0,R2 ;矩形波高电平定时初值送T0
MOV TL0,R3
MOV P2,TODAC ;从P2口送数给DAC0832
T0_INT2:CPL F1 ;轮流切换矩形波高、低电平定时初值标志位
RETI
;*******************************************************************************
; 键盘中断服务程序
;*******************************************************************************
KEY_INT:CLR EA ;关闭中断
MOV 7EH,A ;暂存A于7EH
MOV 7DH,DPH
MOV 7CH,DPL
POP 7BH
POP 7AH
KEY_SCAN:LCALL DL1 ;调用去抖动延时子程序
LCALL KS ;调用判别有无键闭合子程序
JNZ SCAN ;有键闭合转键盘扫描
MOV A,7EH
PUSH 7AH
PUSH 7BH
LJMP KEY_RET ;无键闭合,中断返回
SCAN:MOV R5,#0EFH ;扫描模式送R5,一列拉低其它三列为高电平
MOV R4,#00H ;从第0列开始扫描
SCAN1:MOV A,R5 ;扫描模式送A
MOV P1,A ;一列拉低其它三列为高电平,准备读行
MOV A,P1 ;读P1口
JB ACC.0,ROW1 ;转判第1行
MOV A,#00H ;第0行有键闭合,送0行首键值00H
SJMP KEY_CODE ;转计算键值
ROW1:JB ACC.1,ROW2 ;转判第2行
MOV A,#04H ;第1行有键闭合,送1行首键值04H
SJMP KEY_CODE ;转计算键值
ROW2:JB ACC.2,ROW3 ;转判第3行
MOV A,#08H ;第2行有键闭合,送2行首键值08H
SJMP KEY_CODE ;转计算键值
ROW3:JB ACC.3,NEXT_COL ;转判下一列
MOV A,#0CH ;第3行有键闭合,送3行首键值0CH
SJMP KEY_CODE ;行首键值加列号即为键值
NEXT_COL:INC R4 ;列计数器加1
MOV A,R5 ;判是否扫到最后一列
JNB ACC.7,KND ;仍无键入
RL A ;扫描模式左移1位
MOV R5,A
SJMP SCAN1
KND:MOV A,7EH
PUSH 7AH
PUSH 7BH
LJMP KEY_RET
KEY_CODE:ADD A,R4
CJNE A,#ALT_K,SCAN2 ;若为切换键
CPL F0
CLR A
PUSH ACC
PUSH ACC
LJMP KEY_RET1
SCAN2:JB F0,SOUND_K ;若F0=1,作为电子琴键盘处理
KEY_PAUSE:CJNE A,#PAUSE_K,NEXTSONG ;若F0=0,作为播放乐曲键盘处理
JBC F2,RUN1 ;暂停功能键处理
CLR ET0
PAUSE:SETB F2
MOV DPTR,#INT_WAIT
MOV A,7EH
MOV 6AH,7AH
MOV 6BH,7BH
MOV 68H,7CH
MOV 69H,7DH
PUSH DPL
PUSH DPH
LJMP KEY_RET1
NEXTSONG:CJNE A,#NEXT_K,DEC_K ;下一首功能键处理
MOV A,#MUSIC_NUM
CJNE A,M_BUF,INC_K
MOV M_BUF,#01H
SJMP KEY_SW0
INC_K:INC M_BUF
SJMP KEY_SW0
DEC_K:CJNE A,#LAST_K,RUN ;上一首功能键处理
MOV A,M_BUF
CJNE A,#01H,DEC_K1
MOV M_BUF,#MUSIC_NUM
SJMP KEY_SW0
DEC_K1:DEC M_BUF
SJMP KEY_SW0
RUN1:MOV 7AH,6AH
MOV 7BH,6BH
MOV DPH,69H
MOV DPL,68H
SETB ET0
RUN:MOV A,7EH
PUSH 7AH
PUSH 7BH
LJMP KEY_RET1
SOUND_K:ADD A,#03H
RL A
RL A
MOV R1,A
MOV DPTR,#MTAB
MOVC A,@A+DPTR
MOV R2,A
MOV TH0,R2
MOV A,R1
INC DPTR
MOVC A,@A+DPTR
MOV R3,A
MOV TL0,R3
MOV A,R1
INC DPTR
MOVC A,@A+DPTR
MOV R0,A
MOV A,R1
INC DPTR
MOVC A,@A+DPTR
MOV R1,A
MOV TMOD,#01H
SETB ET0
SETB TR0
SETB EA
OPEN_K:LCALL KS ;判键释放否
JNZ OPEN_K
LCALL DL1 ;调用去抖动延时子程序
LCALL KS ;判别有无键闭合子程序
JNZ OPEN_K
CLR ET0
CLR TR0
CLR EA
MOV DPTR,#INT_WAIT
PUSH DPL
PUSH DPH
SJMP KEY_RET
KEY_SW0:MOV DPTR,#MAIN1
PUSH DPL
PUSH DPH
KEY_RET1:MOV 6CH,A
OPEN_K2:LCALL KS ;判键释放否
JNZ OPEN_K2
LCALL DL1 ;调用去抖动延时子程序
LCALL KS ;判别有无键闭合子程序
JNZ OPEN_K2
MOV A,6CH
KEY_RET:SETB EA
RETI
;*******************************************************************************
; 判别有无键闭合子程序
;*******************************************************************************
KS:MOV P1,#0FH ;键盘列线置低电平,准备读行线值
MOV A,P1 ;读P1口
CPL A ;取反
ANL A,#0FH ;屏蔽高位
RET ;无键闭合返回00H,有键闭合返回非0值
;*******************************************************************************
; 去抖动延时子程序
;*******************************************************************************
DL1:MOV 73H,#0CH ;设晶振频率f=6MHz
DL:MOV 72H,#00H
DJNZ 72H,$
DJNZ 73H,DL
RET
;*******************************************************************************
; 电平均衡处理程序
;*******************************************************************************
COM_ADC: MOV 6EH,DPH
MOV 6DH,DPL
ANL A,#0FH ;取出高、中、低音
CJNE A,#02H,NEX_1
MOV DPTR,#MTAB4
AJMP NEX_3
NEX_1:CJNE A,#01H,NEX_2
MOV DPTR,#MTAB5
AJMP NEX_3
NEX_2:CJNE A,#00H,NEX_3
MOV DPTR,#MTAB6
NEX_3:MOV A,R2
ANL A,#0F0H
SWAP A
MOVC A,@A+DPTR
MOV TODAC,A
MOV DPH,6EH
MOV DPL,6DH
RET
;*******************************************************************************
; 电平均衡表
;*******************************************************************************
MTAB4:DB 6AH,78H,89H,94H,0AEH,0D1H,0FFH ;高音7个字节
MTAB5:DB 45H,48H,4CH,4EH,54H,5BH,65H ;中音7个字节
MTAB6:DB 3BH,3CH,3DH,3EH,3FH,41H,43H ;低音7个字节
;*******************************************************************************
; 乐曲表
;*******************************************************************************
MTAB1:DW 6002H,3102H,3102H,3102H,3106H,2102H ;兰花草
DW 1102H,2102H,1102H,7002H,6008H
DW 6102H,6102H,6102H,6102H,6106H,5102H
DW 3002H,5102H,5102H,4102H,3108H
DW 3102H,6102H,6102H,5102H,3106H,2102H
DW 1102H,2102H,1102H,7002H,6006H,3002H
DW 3002H,1102H,1102H,7002H,6006H,3102H
DW 2102H,1102H,7002H,5002H,6108H
MTAB2:DW 6102H,6101H,7101H,1202H,7102H,6104H,3104H ;踏浪
DW 6102H,6101H,7101H,1202H,7102H,6108H
DW 6102H,6101H,7101H,1202H,7102H,6104H,3104H
DW 6102H,6101H,7101H,1202H,7102H,6108H
DW 6002H,6001H,1101H,2102H,3101H,4101H,3104H,2104H
DW 6002H,6001H,1101H,2102H,3101H,4101H,3108H
DW 6002H,6001H,1101H,2102H,3101H,4101H,3104H,2104H
DW 3102H,3101H,2101H,1102H,7002H,6008H
DW 6102H,3101H,3101H,6102H,3101H,3101H,6104H,3102H,5101H,6101H
DW 5102H,3101H,2101H,1102H,5102H,3108H
DW 6002H,6001H,1101H,2102H,3101H,4101H,3104H,2104H
DW 3102H,3101H,2101H,1102H,7002H,6008H
DW 6102H,6101H,7101H,1202H,7102H,6104H,3104H
DW 6102H,6101H,7101H,1202H,7102H,6108H
DW 6102H,6101H,7101H,1202H,7102H,6104H,3104H
DW 6102H,6101H,7101H,1202H,7102H,6108H
DW 6102H,6101H,7101H,1202H,7101H,6101H,7104H,5104H
DW 4101H,2101H,4101H,6101H,5102H,4102H,3108H
DW 6102H,6101H,7101H,1202H,7102H,6104H,5104H
DW 4101H,2101H,4101H,6101H,5102H,7102H,6108H
MTAB3:DW 1104H,2104H,3104H,1104H ;两只老虎
DW 1104H,2104H,3104H,1104H
DW 3104H,4104H,5108H
DW 3104H,4104H,5108H
DW 5102H,6102H,5102H,4102H,3104H,1104H
DW 5102H,6102H,5102H,4102H,3104H,1104H
DW 1104H,5104H,1108H
DW 1104H,5004H,1108H
DB 0FFH
END