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