单片机简易电子琴程序

用51控制的带播放功能的简易电子琴。
P1口作为8个按键输入,其中P1.0-1.6作为七个音。P1.7是播放/弹奏切换按键。P3.3是喇叭输出。P2口连接七断数码管用于显示播放功能时的播放歌曲所在位置。
哪位高人有程序?最好c语言版。汇编也行!

;R5音调延时值;R6从内存中读到的数据 

;9H--TABLE1~11数据;20H--TL1初值;21H--TH1初值;22H--修正后的按键值;30H--TABLE1~11地址计数器 

;0AH--弹奏音调延时值;0BH--内存地址;0CH--读写到内存的数据;0DH--按键值;0EH--内存器件地址 

PORT1   EQU   P1

PORT2   EQU   P2

SCK     BIT   P3.0

SDA  BIT   P3.1

        ORG   0H

  SJMP  MAIN

  ORG   0BH

  LJMP  TIME0

  ORG   1BH

  LJMP  TIME1

  ORG   30H

;--------------------------------------------------------------------------

MAIN:   CLR   TR0

        CLR   TR1

  MOV   SP,#4FH

  MOV   R0,#100

  CLR   P3.4

  LCALL DELAY5

  MOV   9H,#0

  MOV   0AH,#0

  MOV   0BH,#0

  MOV   0CH,#0

  MOV   TMOD,#11H    

  MOV   IE,#8AH    

  MOV   0DH,#88H

;------------扫描放歌和弹奏建------------------------------------

XIAN:   JB    P3.2,QT1    ;没按下放歌建跳qt1

        SETB  P3.4    ;按下放歌建LED发光

  LCALL DELAY1

  LCALL DELAY1

  JNB   P3.2,$   ;放歌建没释放原地等待

  LCALL DELAY1

  LCALL DELAY1

Q1:     LCALL SAO

  CJNE  R0,#0,Q11

  SJMP  Q1

Q11:    LCALL TRANF

  JZ    MAIN

  MOV   0DH,A    ;0DH=按键值

  LJMP  SING0

QT1:    JB    P3.3,QT4      ;没按弹奏建跳QT3

        SETB  P3.4

  LCALL DELAY1

  LCALL DELAY1

  JNB   P3.3,$   ;弹奏键没释放原地等待

  LCALL DELAY1

  LCALL DELAY1

QT2:    LCALL SAO

  CJNE  R0,#0,QT3

  SJMP  QT2

QT3:    LCALL TRANF

  CJNE  A,#0BH,QT11 ;若按键值=11转(B键)MAIN;!=11键转QT11   

  LJMP  MAIN

QT11:   JC    MAIN   ;若按键值<11转MAIN;>11继续

        CJNE  A,#0CH,M4  ;若按键值!=12转M1;=12(C键)继续 ;即C键没按下转M1

        MOV   PORT1,#11101111B   

  JNB   P1.3,$   ;若C键没释放原地等待 

  MOV   0BH,#0

  LJMP  LOOP    ;输入乐曲存储并演奏 

M4:  LCALL DELAY1

        LCALL DELAY1

  LCALL RWX80     ;擦写内存数据;全部为1

  LJMP  MAIN

QT4:    LJMP  XIAN    ;返回重新扫描放歌和弹奏建

;--------------------------------------------------------------------------

RWX80:  CJNE  A,#0DH,MM2  ;A!=13(D键)转M2;若为D键继续;D键没按下转M2

        MOV   0EH,#0A2H  ;0EH=162=10100010B;0EH为24c16页地址

  SJMP  MM

MM2:     CJNE  A,#0EH,MM3  ;A!=14(E键)转M3;E键没按下转M3

        MOV   0EH,#0A4H  ;0EH=164=10100100B 

  SJMP  MM

MM3:     MOV   0EH,#0A6H  ;F键按下;0EH=166=10100110B

MM:     MOV   0BH,#0

        MOV   0CH,#0H

RWX801: LCALL RKX02

        LCALL WKX02

  INC   0BH        

  INC   0BH 

  INC   0BH 

  INC   0BH

  MOV   A,0BH

  CJNE  A,#0FFH,MM4

  MOV   0BH,#0

MM4:    INC   0CH 

  INC   0CH 

  INC   0CH

  INC   0CH

  CJNE   A,#0H,RWX801

  RET

;--------读数据------------------------------

RKX02:

        LCALL START

  MOV   A,#0A0H     ;24C16寻址10100000写

  LCALL WRBYT

  LCALL TACK

  MOV   A,0BH     ;发送24c16子地址

  LCALL WRBYT

  LCALL TACK

  LCALL START

  MOV   A,#0A1H    ;24C16寻址10100001读

  LCALL WRBYT

  LCALL TACK

  ;LCALL WRBYT

  ;LCALL TACK

  MOV   10H,R6

  LCALL RDBYT

  LCALL NOTACK

  ;LCALL WRBYT

  ;LCALL TACK

  MOV   11H,R6

  LCALL RDBYT

  LCALL NOTACK

  ;LCALL WRBYT

  ;LCALL TACK

  MOV   12H,R6  

  LCALL RDBYT

  LCALL TACK

  MOV   13H,R6

  LCALL NOTACK

  LCALL STOP

  RET

;---------写数据-----------------------

WKX02:

        MOV   R1,#10H

  LCALL START

  MOV   A,#0A0H

  LCALL WRBYT

  LCALL TACK

  MOV   A,0BH

  LCALL WRBYT

  LCALL TACK

  MOV   A,0CH

  LCALL WRBYT

  LCALL TACK

  MOV   R0,#4

WKX021: MOV   A,@R1

  LCALL WRBYT

  LCALL TACK

  INC   R1

  DJNZ  R0,WKX021

  LCALL STOP

  LCALL DELAY5

  LCALL DELAY5

  RET

;-------输入乐曲存储并演奏--------------------------------------------

LOOP:   CLR   TR0

        CLR   TR1

AAA:    JB    P3.3,LOOP4 ;弹奏键按下 向下执行存储乐曲并演奏 否则转LOOP4继续输入乐曲

        LCALL DELAY1

  LCALL DELAY1

  MOV   0CH,#0

  LCALL WBAY    ;存00结束乐谱 

  LCALL DELAY1

  MOV   0DH,#12

  LJMP  SING0     ;播放弹奏的乐曲 

LOOP4:  LCALL   SAO

  CJNE    R0,#0,KEYIN

  LJMP    LOOP

KEYIN:  LCALL TRANF

  SWAP  A

  MOV   09H,A

  SWAP  A

  CJNE  A,#0,ZZZ     ;非0键转ZZZ

  CLR   TR1

  CLR   TR0

  LJMP  ZZZZ      ;0键转ZZZZ

ZZZ: DEC   A    ;A为按键值;因从1键值音调序号对应TABLE频率表0位置;故减1

        MOV   22H,A   ;22H存修正后(A=A-1)的按键值

  CLR   C

  RLC   A    ;A*2因TABLE一个单元为2字节(1字),指向该单元的第1个字节 

  MOV   DPTR,#TABLE

  MOVC  A,@A+DPTR

  MOV   TH1,A   ;TH1赋初值

  MOV   21H,A   ;TH1初值存21H

  MOV   A,22H

  CLR   C

  RLC   A    ;A*2因TABLE一个单元为2字节(1字)

  INC   A    ;指向该单元的第2个字节  

  MOVC  A,@A+DPTR

  MOV   TL1,A  ;TL1赋初值 

  MOV   20H,A  ;TL1初值存20H

  MOV   TH0,#0C2H

  MOV   TL0,#0F6H

  SETB  TR0

  SETB  TR1

ZZZZ:   MOV   A,PORT1

        ORL   A,#0F0H

  CJNE  A,#0FFH,ZZZZ

  CLR   TR0

  CLR   TR1

  MOV   A,0AH     ;弹奏乐谱频率延迟值赋A

  CLR   C

  RRC   A

  CLR   C

  RRC   A

  CLR   C

  RRC   A   ;弹奏乐谱频率延迟值/8

  CJNE  A,#0FH,NODE

  SJMP  DDD

NODE:   JC    DDD

        MOV   A,#0FH  ;弹奏乐谱频率延迟值/8后;若>15则=15

DDD:    ORL   09H,A   ;

        MOV   0AH,#0

WWW: ;   MOV   A,09H

  MOV   0CH,A

  LCALL WBAY

  LCALL DELAY5

  INC   0BH

  LJMP  LOOP

;-----频率延时-----------------------------------------

DELAY:  MOV   R7,#125

DLY2:   MOV   R4,#02

DLY3:   MOV   R3,#248

        DJNZ  R3,$

  DJNZ  R4,DLY3

  DJNZ  R7,DLY2

  DJNZ  R5,DELAY

  RET

;---------延时----------------------

DELAY1: MOV   R7,#30

        MOV   R6,#0

S1:     DJNZ  R6,$

   DJNZ  R7,S1

  RET

DELAY5: MOV   R7,#10

        MOV   R6,#0

S5:     DJNZ  R6,$

   DJNZ  R7,S5

  RET

;-----扫描按键子程序----------

SAO:    MOV   R0,#4

        MOV   R3,#11101111B

  MOV   R2,#11111111B

NLINE1: MOV   A,R3

        MOV   PORT1,A

     MOV   A,PORT1

  ORL   A,#0F0H

  CJNE  A,#0FFH,KEYIN1

  MOV   A,R3

  RL    A

  MOV   R3,A

  DJNZ  R0,NLINE1

  RET

KEYIN1: LCALL DELAY1

  LCALL DELAY1

  LCALL DELAY1

  LCALL NOPEN

     RET

;-----按键延时-------------

NOPEN:  MOV   A,PORT1

  MOV   R2,A

        ORL   A,#0F0H

  CJNE  A,#0FFH,NOPEN1

  SJMP  NOPEN

NOPEN1: LCALL DELAY1

  LCALL DELAY1

  RET

;----------键盘码转换为按键值-----------------

TRANF:  MOV   B,#0

        MOV   A,R2 

C1:     RRC   A     

        JNC   C2 ;C=0跳C2

  INC   B  

  INC   B

  INC   B

  INC   B  ;B=B+4

  LJMP  C1

C2:     MOV   A,R2   

        RR    A

  RR    A

  RR    A

  RR    A

C3:     RRC   A

        JNC   C4

  INC   B

  LJMP  C3

C4:     MOV   A,B  ;B为按键值

        RET

;---------按键值散转表-------------------

SING0:  

        MOV   30H,#00H   ;30H为TABLE1~11地址计数器

NEXT:   MOV   A,0DH

        CJNE  A,#1,NN1

  MOV   DPTR,#TABLE1

  LJMP  WW

NN1:    CJNE  A,#2,NN2

   MOV   DPTR,#TABLE2

  LJMP  WW

NN2:    CJNE  A,#3,NN3

  MOV   DPTR,#TABLE3

  LJMP  WW

NN3:    CJNE  A,#4,NN4

  MOV   DPTR,#TABLE4

  LJMP  WW

NN4:    CJNE  A,#5,NN5

  MOV   DPTR,#TABLE5

  LJMP  WW

NN5:    CJNE  A,#6,NN6

  MOV   DPTR,#TABLE6

  LJMP  WW

NN6:    CJNE  A,#7,NN7

  MOV   DPTR,#TABLE7

  LJMP  WW

NN7:    CJNE  A,#8,NN8

  MOV   DPTR,#TABLE8

  LJMP  WW

NN8:    CJNE  A,#9,NN9

  MOV   DPTR,#TABLE9

  LJMP  WW

NN9:    CJNE  A,#10,NN10

  MOV   DPTR,#TABLE10

  LJMP  WW

NN10:   CJNE  A,#11,NN11

  MOV   DPTR,#TABLE11

  LJMP  WW

NN11:   CJNE  A,#12,NN12

  MOV   0EH,#0A1H

  MOV   0BH,#0

  LJMP  NN

NN12:   CJNE  A,#13,NN13

  ;MOV   0EH,#0A3H

  ;MOV   0BH,#0H

  LJMP  MAIN

NN13:   CJNE  A,#14,NN14

  ;MOV   0EH,#0A5H

  ;MOV   0BH,#0H

  LJMP  MAIN

NN14:   CJNE  A,#15,NN

  ;MOV   0EH,#0A7H

  ;MOV   0BH,#00H

  LJMP  MAIN

;--------------------------------

NN:     LCALL RBAY   ;读内存 

NNT:    MOV   A,R6   ;R6为从内存中读到的数据 

        LJMP  IIC

;-----------奏乐--------------------------------------------

WW:     MOV   A,30H

        JZ    WW0

  MOVC  A,@A+DPTR

  SJMP  IIC

WW0:    MOVC  A,@A+DPTR

        MOV   30H,#1

  MOV   31H,A   

  SJMP  WW

IIC:    MOV   R2,A   

        JZ    ENDF  ;A=00 结束标志跳ENDF程序重新开始

  ANL   A,#0FH  ;低4位为延时值 

  MOV   R5,A   ;R5延时值;频率延时(DELAY)程序用 

  MOV   A,R2

  SWAP  A

  ANL   A,#0FH  ;高4位为音调序号若 

  JNZ   SING   ;为0则 

  CLR   TR1   ;为休止符 

  SJMP  DLY1

SING:   DEC   A    ;频率表从0位置开始,音调序号表从1位置开始,0位置数据是解密数据     

        PUSH  ACC

  MOV   A,0DH

  CJNE  A,#11,BD  ;若>11(B)键,即为C~F键转BD0;若<=11(B)键转DE,音调序号+31H

  POP   ACC

  SJMP  DE

BD:     POP   ACC

        JNC   BD0

DE:     ADD   A,31H

BD0:    MOV   22H,A

        RL    A

  MOV   DPTR,#TABLE

  MOVC  A,@A+DPTR

  MOV   TH1,A

  MOV   21H,A

  MOV   A,22H

  RL    A

  INC   A

  MOVC  A,@A+DPTR

  MOV   TL1,A

  MOV   20H,A

  SETB  TR1

DLY1:   INC   R5

        ACALL DELAY

  INC   30H

  INC   0BH

  MOV   A,0DH    ;取按键值;判断是读内存键还是读乐谱序号键 

  CJNE  A,#0BH,NNBD  ;若按键值<11取下1个乐谱;若按键值为12~15(C~F)转NNBD读内存 

NEXT1:  LJMP  NEXT

NNBD:   JC    NEXT1

        LJMP  NN   ;读内存 

;--------程序重新开始---------------------------------------

ENDF:   CLR   TR1

        LJMP  MAIN

;--------T0中断服务弹奏频率延迟时间---------------------------------------------

TIME0:  INC   0AH    ;弹奏乐谱频率延迟值 

        MOV   TH0,#0C2H

  MOV   TL0,#0F6H    ;定时初值 =49910    计数次数为 2^16(65536)-49910=15626=16ms

  RETI

;--------T1中断服务发声-----------------------

TIME1:  PUSH  ACC

        PUSH  PSW

  MOV   TL1,20H

  MOV   TH1,21H

  CPL   P3.7

  POP   PSW

  POP   ACC

  RETI

;--------读数据--------------------

RBAY:   LCALL START

        MOV   A,#0A0H

  LCALL WRBYT

  LCALL TACK

  MOV   A,0BH

  LCALL WRBYT

  LCALL TACK

  LCALL START

        MOV   A,0EH

  LCALL WRBYT

  LCALL TACK

  LCALL RDBYT

  LCALL NOTACK

  LCALL STOP

  RET

;-------写数据-------------------

WBAY:   LCALL START

        MOV   A,#0A0H

  LCALL WRBYT

  LCALL TACK

  MOV   A,0BH

  LCALL WRBYT

  LCALL TACK

  MOV   A,0CH

  LCALL WRBYT

  LCALL TACK

  LCALL STOP

  RET

;---------写数据---------------

;WKX03:  MOV   R1,#10H

        ;LCALL START

  ;MOV   A,#0A2H

  ;LCALL WRBYT

  ;LCALL TACK

  ;MOV   A,0CH

  ;LCALL WRBYT

  ;LCALL TACK

  ;MOV   R0,#4

;WKX031: MOV   A,@R1

        ;LCALL WRBYT

  ;LCALL TACK

  ;INC   R1

  ;DJNZ  R0,WKX031

  ;LCALL STOP

  ;LCALL DELAY1

  ;LCALL DELAY1

  ;RET

;-------启动24C16读写时序------------------

START:  SETB  SDA

        NOP

  NOP

  NOP

  NOP

  SETB  SCK

  NOP

  NOP

  NOP

  NOP

  CLR   SDA

  NOP

  NOP

  NOP

  NOP

  CLR   SCK

  NOP

  NOP

  NOP

  NOP

  RET

;-------停止信号------------------

STOP:   CLR   SDA

  NOP

  NOP

  NOP

  NOP

        SETB  SCK

  NOP

  NOP

  NOP

  NOP

  SETB  SDA

  NOP

  NOP

  NOP

  NOP

  ;CLR   SCK

  ;NOP

  ;NOP

  ;NOP

  ;NOP

  RET

;-------应答信号-----------------

TACK: SETB  SDA

        ;CLR   SDA

        NOP

  NOP

  NOP

  NOP

  SETB  SCK

  NOP

  NOP

  NOP

  NOP

  CLR   SCK

  NOP

  NOP

  NOP

  NOP

  ;SETB  SDA

  ;NOP

  ;NOP

  ;NOP

  ;NOP

  RET

;-------------------------

CHACK:  SETB  SDA

  NOP

  NOP

  NOP

  NOP

        SETB  SCK

  NOP

  NOP

  NOP

  NOP

  MOV   C,SDA

  CLR   SCK

  NOP

  NOP

  NOP

  NOP

  RET

;-----------------------------

NOTACK: ;NOP

        SETB  SDA

  NOP

  NOP

  NOP

  NOP

  SETB  SCK

  NOP

  NOP

  NOP

  NOP

  CLR   SCK

  NOP

  NOP

  NOP

  NOP

  RET  

;------读IIC-24C16------------------

RDBYT:  MOV   R7,#8

     SETB  SDA

  NOP

  NOP

  NOP

  NOP

RDBYT1: SETB  SCK

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  MOV   C,SDA

  MOV   A,R6

  RLC   A

  MOV   R6,A

  CLR   SCK

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  DJNZ  R7,RDBYT1

  RET

;------写IIC-24C16---------------

WRBYT:  MOV   R7,#8

WRBYT1: RLC   A

  MOV   SDA,C

        ;JC    WRBYT2

  ;CLR   SDA

  ;NOP

  ;NOP

  ;NOP

  ;NOP

  SETB  SCK

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  CLR   SCK

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  DJNZ  R7,WRBYT1

  RET

;WRBYT2: SETB  SDA

  ;NOP

  ;NOP

  ;NOP

  ;NOP

        ;SETB  SCK

  ;NOP

  ;NOP

  ;NOP

  ;NOP

  ;CLR   SCK

  ;NOP

  ;NOP

  ;NOP

  ;NOP

  ;CLR   SDA

  ;NOP

  ;NOP

  ;NOP

  ;NOP

  ;DJNZ  R7,WRBYT1

  RET

;-------;TABLE为频率值  -------------------------------------

TABLE:  DW 0F88CH,0F95BH,0FA15H,0FA67H,0FB04H,0FB90H,0FC0CH ;低音1~7   

        DW 0FC44H,0FCACH,0FD09H,0FD34H,0FD82H,0FDC8H,0FE06H ;中音1~7

  DW 0FE22H,0FE56H,0FE85H,0FE9AH,0FEC1H,0FEE4H,0FF03H ;高音1~7

;--------TABLE1~11为音调序号和音调延时表调;数据高4位是-----------------------------------

;--------音调序号;低4位是音调延时值-----------------------------------------------------------------

;--------;兰花草---------------------------------------

TABLE1: DB 02H,42H,82H,82H,82H,84H,02H,72H,62H,72H,62H  

  DB 52H,48H,0B2H,0B2H,0B2H,0B2H,0B4H,02H,0A2H

  DB 12H,0A2H,0D2H,92H,88H,82H,0B2H,0B2H,0A2H,84H

  DB 02H,72H,62H,72H,62H,52H,44H,02H,12H,12H,62H

  DB 62H,52H,44H,02H,82H,72H,62H,52H,32H,48H,00

;-------;哈巴--------------------------------------------

TABLE2: DB 04H,42H,42H,42H,52H,64H,04H,62H,62H,62H,72H,84H,04H  

  DB 92H,92H,82H,72H,64H,04H,82H,82H,52H,62H,44H,04H

  DB 42H,42H,42H,52H,64H,04H,62H,62H,62H,72H,84H,04H

  DB 92H,92H,82H,72H,64H,04H,82H,82H,52H,62H,44H,04H,00H

;-------;生日快乐---------------------------------------

TABLE3: DB 04H,82H,01H,81H,94H,84H,0B4H,0A4H,04H 

  DB 82H,01H,81H,94H,84H,0C4H,0B4H,04H

  DB 82H,01H,0F4H,0D4H,0B4H,0A4H,94H

  DB 0E2H,01H,0E1H,0D4H,0B4H,0C4H,0B4H,04H,00H

;-------;不倒翁--------------------------------------------

TABLE4: DB 04H,84H,94H,88H,64H,54H,68H,84H,64H  

  DB 54H,44H,62H,82H,42H,62H,58H;1

  DB 84H,94H,88H,64H,54H,68H,84H,64H;2

  DB 54H,44H,52H,42H,52H,62H,48H,00

;-------;妹妹背着洋娃娃---------------------------------------

TABLE5: DB 04H,84H,02H,82H,64H,54H,64H,54H,48H,64H  

  DB 02H,52H,44H,24H,14H,24H,18H;1

  DB 24H,02H,22H,42H,24H,44H,54H,68H,54H;2

  DB 02H,52H,84H,84H,54H,64H,48H,00

;-------;两只老虎-------------------------------------------------

TABLE6: DB 04H,44H,54H,64H,44H,44H,54H,64H,44H,64H,74H,88H,64H,74H,88H;1  

  DB 82H,92H,82H,72H,64H,44H,82H,92H,82H

  DB 72H,64H,44H,44H,84H,48H,44H,14H,48H,00

;-------;三只小猫----------------------------------------------

TABLE7: DB 04H,62H,82H,82H,62H,98H,92H,0B2H,0B2H,82H,98H 

  DB 2H,82H,82H,52H,68H,92H,0B2H,0B2H,82H,98H

  DB 62H,82H,82H,62H,92H,92H,94H

  DB 92H,0B2H,0B2H,92H,84H,94H,0B8H,0B4H,04H,00

;-------;绿-------------------------------------------------------

TABLE8: DB 02H,42H,82H,82H,82H,84H,02H,72H,62H,72H,62H,52H,48H 

  DB 0B2H,0B2H,0B2H,0B2H,0B4H,02H,0A2H

  DB 12H,0A2H,0D2H,92H,88H,82H,0B2H,0B2H,0A2H,84H

  DB 02H,72H,62H,72H,62H,52H,44H,02H,12H

  DB 12H,62H,62H,52H,44H,02H,82H,72H,62H,52H,32H,48H,00

;-------;绿岛小夜曲-----------------------------------------------

TABLE9: DB 00H,0C2H,0D2H,0F2H,0D2H,0C4H,0D2H,0F2H  

  DB 0D2H,0C2H,0A2H,92H,0A8H

  DB 92H,0A2H,0C2H,0A2H,92H,82H,62H,82H,58H,58H

  DB 0C4H,22H,0D2H,0C4H,0A4H,92H,0A2H,92H,82H,92H,0A4H,092H

  DB 84H,82H,32H,54H,22H,62H,052H,058H

  DB 64H,22H,52H,64H,84H,92H,0A2H,92H,82H,92H,0A4H,0C2H

  DB 92H,94H,0A2H,0C4H,22H,0D2H,0C8H,0C8H

  DB 0D2H,0D4H,0C2H,0A2H,0A2H,92H,82H,92H,0A2H,0C2H,0A8H

  DB 92H,94H,82H,62H,52H,52H,82H,98H,98H

  DB 0A2H,0A4H,92H,0A2H,0C2H,0A4H,92H,0A2H,92H,82H,68H

  DB 52H,0C2H,0A2H,0F2H,0C2H,0D2H,0A2H,92H,88H,88H

  DB 0D2H,0D2H,0D2H,0C2H,0A2H,0A2H,22H

  DB 92H,94H,82H,62H,52H,62H,82H,98H,98H

  DB 0C2H,0D2H,0C2H,92H,0A2H,0A4H,0A2H

  DB 92H,94H,82H,64H,84H,0C8H,0D1H,0C1H,0A2H,0C2H,0D4H,0D2H,0E2H

  DB 0C2H,0D2H,0C2H,0A2H,98H

  DB 0A4H,92H,82H,64H,22H,82H,92H,0A1H,91H,82H,92H,0A4H,22H,0C2H

  DB 0D4H,22H,0A2H,94H,0A2H,92H,88H,88H,00

;---------------------------------------------------------------------------

TABLE10:DB 00H,04H,42H,52H,62H,42H,42H,52H,62H,42H,62H,72H,86H,62H,72H,86H;1

  DB 82H,92H,82H,72H,62H,42H,82H,92H,82H

  DB 72H,62H,42H,42H,82H,46H,42H,12H,48H,00

;----------------------------------------------------------------------------

TABLE11:DB 00H,23H,01H,63H,01H,51H,61H,41H,51H

  DB 64H,22H,92H,51H,61H,72H,64H

  DB 04H,63H,01H,93H,01H,81H,91H,0A1H,0A1H

  DB 94H,53H,61H,41H,51H,41H,31H,24H,04H

  DB 53H,61H,41H,51H,41H,31H,24H,04H,53H,61H,82H

  DB 92H,0AAH,02H,93H,0A1H,91H,81H,98H,04H,91H

  DB 81H,92H,04H,61H,51H,62H,04H,56H,42H,12H

  DB 22H,32H,32,28H,08H,00

;--------------------------------------------------------------------------

;TABLE12:

        ;DB 01H,00H

;---------------------

  END

温馨提示:答案为网友推荐,仅供参考
第1个回答  2009-04-26
你爽了,我正好有!
这是一款用51单片机控制的玩具电子琴,用到了51的定时器和键盘技术,它的汇编程序流程如下,很适合初学者学习制作。
说明:由单片机的P1.0口输出音频信号,在P1.0口接三极管以驱动喇叭,最好用两个三极管构成达林顿结构。P2口连接8个一端接地的按键作为输入,当然也需要连接8只10K的电阻至电源作为上拉电阻。P2.0~P2.7依次为Do、Re、Mi、Fa、So、La、Si、Do(高)音。

BUZZ EQU P1.0
ORG 0000H
LJMP MAIN
ORG 000BH
LJMP INT_T0
ORG 0100H
MAIN:
MOV SP,#60H ;初始化堆栈指针
MOV 30H,#00 ;定时器初值清零
MOV 31H,#00
MOV P1,#0FFH ;设置P1口为输入模式
MOV TMOD,#01H ;设置定时器0为工作模式1
SETB ET0 ;开定时器0中断
SETB EA ;开总中断
CLR TR0 ;关闭定时器0
START:
MOV R0,P2
CJNE R0,#0FFH,KEY1 ;键盘扫描
CLR TR0
SJMP START
KEY1:
CJNE R0,#0FEH,KEY2 ;K1键按下
MOV 30H,#0FBH ;设置音阶1
MOV 31H,#0E9H
LJMP SET_TIMER
KEY2:
CJNE R0,#0FDH,KEY3 ;K2键按下
MOV 30H,#0FCH ;设置音阶2
MOV 31H,#5CH
LJMP SET_TIMER
KEY3:
CJNE R0,#0FBH,KEY4 ;K3键按下
MOV 30H,#0FCH ;设置音阶3
MOV 31H,#0C1H
LJMP SET_TIMER
KEY4:
CJNE R0,#0F7H,KEY5 ;K4键按下
MOV 30H,#0FCH ;设置音阶4
MOV 31H,#0EFH
LJMP SET_TIMER
KEY5:
CJNE R0,#0EFH,KEY6 ;K5键按下
MOV 30H,#0FDH ;设置音阶5
MOV 31H,#045H
LJMP SET_TIMER
KEY6:
CJNE R0,#0DFH,KEY7 ;K6键按下
MOV 30H,#0FDH ;设置音阶6
MOV 31H,#92H
LJMP SET_TIMER
KEY7:
CJNE R0,#0BFH,KEY8 ;K7键按下
MOV 30H,#0FDH ;设置音阶7
MOV 31H,#0D6H
LJMP SET_TIMER
KEY8:
CJNE R0,#7FH,NOKEY ;K8按下
MOV 30H,#0FDH ;设置音阶8
MOV 31H,#0FBH
SET_TIMER:
SETB TR0 ;发声
SJMP START
NOKEY:
CLR TR0 ;无键按下
SJMP START
INT_T0: ;T0中断服务程序
MOV TH0,30H ;定时器赋初值
MOV TL0,31H
CPL BUZZ ;输出方波
RETI
END
第2个回答  2009-04-24
22. 电子琴
1. 实验任务
(1. 由4X4组成16个按钮矩阵,设计成16个音。
(2. 可随意弹奏想要表达的音乐。
2. 电路原理图

图4.22.1
3. 系统板硬件连线
(1. 把“单片机系统”区域中的P1.0端口用导线连接到“音频放大模块”区域中的SPK IN端口上;
(2. 把“单片机系统“区域中的P3.0-P3.7端口用8芯排线连接到“4X4行列式键盘”区域中的C1-C4 R1-R4端口上;
4. 相关程序内容
(1. 4X4行列式键盘识别;
(2. 音乐产生的方法;
一首音乐是许多不同的音阶组成的,而每个音阶对应着不同的频率,这样我们就可以利用不同的频率的组合,即可构成我们所想要的音乐了,当然对于单片机来产生不同的频率非常方便,我们可以利用单片机的定时/计数器T0来产生这样方波频率信号,因此,我们只要把一首歌曲的音阶对应频率关系弄正确即可。现在以单片机12MHZ晶振为例,例出高中低音符与单片机计数T0相关的计数值如下表所示
音符 频率(HZ) 简谱码(T值) 音符 频率(HZ) 简谱码(T值)
低1 DO 262 63628 # 4 FA# 740 64860
#1 DO# 277 63731 中 5 SO 784 64898
低2 RE 294 63835 # 5 SO# 831 64934
#2 RE# 311 63928 中 6 LA 880 64968
低 3 M 330 64021 # 6 932 64994
低 4 FA 349 64103 中 7 SI 988 65030
# 4 FA# 370 64185 高 1 DO 1046 65058
低 5 SO 392 64260 # 1 DO# 1109 65085
# 5 SO# 415 64331 高 2 RE 1175 65110
低 6 LA 440 64400 # 2 RE# 1245 65134
# 6 466 64463 高 3 M 1318 65157
低 7 SI 494 64524 高 4 FA 1397 65178
中 1 DO 523 64580 # 4 FA# 1480 65198
# 1 DO# 554 64633 高 5 SO 1568 65217
中 2 RE 587 64684 # 5 SO# 1661 65235
# 2 RE# 622 64732 高 6 LA 1760 65252
中 3 M 659 64777 # 6 1865 65268
中 4 FA 698 64820 高 7 SI 1967 65283
下面我们要为这个音符建立一个表格,有助于单片机通过查表的方式来获得相应的数据
低音0-19之间,中音在20-39之间,高音在40-59之间
TABLE: DW 0,63628,63835,64021,64103,64260,64400,64524,0,0
DW 0,63731,63928,0,64185,64331,64463,0,0,0
DW 0,64580,64684,64777,64820,64898,64968,65030,0,0
DW 0,64633,64732,0,64860,64934,64994,0,0,0
DW 0,65058,65110,65157,65178,65217,65252,65283,0,0
DW 0,65085,65134,0,65198,65235,65268,0,0,0
DW 0
2、音乐的音拍,一个节拍为单位(C调)
曲调值 DELAY 曲调值 DELAY
调4/4 125ms 调4/4 62ms
调3/4 187ms 调3/4 94ms
调2/4 250ms 调2/4 125ms
对于不同的曲调我们也可以用单片机的另外一个定时/计数器来完成。
下面就用AT89S51单片机产生一首“生日快乐”歌曲来说明单片机如何产生的。
在这个程序中用到了两个定时/计数器来完成的。其中T0用来产生音符频率,T1用来产生音拍。
5. 程序框图
贴不了.
7. C语言源程序
#include <AT89X51.H>
unsigned char code table[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
unsigned char temp;
unsigned char key;
unsigned char i,j;
unsigned char STH0;
unsigned char STL0;
unsigned int code tab[]={64021,64103,64260,64400,
64524,64580,64684,64777,
64820,64898,64968,65030,
65058,65110,65157,65178};

void main(void)
{
TMOD=0x01;
ET0=1;
EA=1;

while(1)
{
P3=0xff;
P3_4=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
switch(temp)
{
case 0x0e:
key=0;
break;
case 0x0d:
key=1;
break;
case 0x0b:
key=2;
break;
case 0x07:
key=3;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
}
TR0=0;
}
}

P3=0xff;
P3_5=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
switch(temp)
{
case 0x0e:
key=4;
break;
case 0x0d:
key=5;
break;
case 0x0b:
key=6;
break;
case 0x07:
key=7;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
}
TR0=0;
}
}

P3=0xff;
P3_6=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
switch(temp)
{
case 0x0e:
key=8;
break;
case 0x0d:
key=9;
break;
case 0x0b:
key=10;
break;
case 0x07:
key=11;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
}
TR0=0;
}
}

P3=0xff;
P3_7=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
switch(temp)
{
case 0x0e:
key=12;
break;
case 0x0d:
key=13;
break;
case 0x0b:
key=14;
break;
case 0x07:
key=15;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
}
TR0=0;
}
}
}
}

void t0(void) interrupt 1 using 0
{
TH0=STH0;
TL0=STL0;
P1_0=~P1_0;
}

根据自己的情况稍微改改就好了
第3个回答  2009-04-24
一般用4*4键盘实现比较节约资源,
我在实现的时候和你一样,用8个按键输入,
效果很好,程序可以到我Q空间查看。。。。

相关了解……

你可能感兴趣的内容

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 非常风气网