📄 yinxiang.asm
字号:
;-----------------------------------------------------------------------------
; 版权归新华龙电子公司所有
;-----------------------------------------------------------------------------
;
;文件名: YinXiang.asm
;
;编写人: LC
;
;编写时间:2005/03/10
;
;目标器件: C8051F02x
;
;编译工具: Silicon Laboratories IDE
;
;程序说明: 此程序将某段音乐用特定的频率播放出来
;P54--MUSIC
;ch--->R7 halfflg--->R5 lasttime--->R0
;------------------------------------------------------------------------------------
; 头文件包含
;------------------------------------------------------------------------------------
$include (C8051F020.inc)
ORG 0
LJMP main
ORG 0BH
LJMP timer0int
ORG 100H
;延时子程序
Delay:
PUSH 5 ;进栈
PUSH 6
PUSH 7
MOV R5,#00H
De_2:
MOV A,R5
CLR C
SUBB A,R0
JNC De_8
MOV R6,#00H
MOV R7,#00H
De_5:
CLR C
MOV A,R6
SUBB A,#09H
JNC De_4
INC R7
MOV A,R7
JNZ De_46
INC R6
De_46:
SJMP De_5
De_4:
INC R5
SJMP De_2
De_8:
POP 7 ;出栈
POP 6
POP 5
RET
;判定字符是否是数字键
;YES(C=1) NO(C=0)
isdigit:
MOV A,R7
CLR C
SUBB A,#30H
JC digit_1
MOV A,R7
SUBB A,#3AH
JNC digit_1
SETB C
RET
digit_1:
CLR C
RET
;判定字符是否是字母键
;YES(C=1) NO(C=0)
isalpha:
MOV A,R7
CLR C
SUBB A,#41H
JC alpha_2
MOV A,R7
SUBB A,#5BH
JNC alpha_2
LJMP alpha_3
alpha_2:
MOV A,R7
CLR C
SUBB A,#61H
JC alpha_1
MOV A,R7
SUBB A,#7BH
JNC alpha_1
alpha_3:
SETB C
RET
alpha_1:
CLR C
RET
;定时器0用来产生方波
timer0int:
PUSH ACC
MOV TH0,R3 ;定时初值
MOV TL0,R4
MOV A,P5
XRL A,#10H
MOV P5,A ;改变P5.4状态
POP ACC
RETI
;开定时器0
Sound:
SETB TR0 ;开定时器0
SETB ET0
RET
;停止发声
SoundOff:
PUSH ACC
CLR TR0 ;禁止定时0
CLR ET0
MOV A,P5
ORL A,#10H ;改变P5.4状态
MOV P5,A
POP ACC
RET
;依据音鸣取对应的频率
GetFreq:
PUSH DPH
PUSH DPL
CJNE R5,#00H,G_F_1 ;判定是全音/半音
MOV DPTR,#timreg ;取音频65536l-(OSFREQ/(24l*freq))表的收地址
MOV R1,DPH ;保存此地址到R1,R2
MOV R2,DPL
MOV DPTR,#notename ;取音名表的首地址
SJMP GLOOP
G_F_1:
MOV DPTR,#halftimreg ;取半音频65536l-(OSFREQ/(24l*freq))表的收地址
MOV R1,DPH ;保存此地址到R1,R2
MOV R2,DPL
MOV DPTR,#halfnotename ;取半音名表的首地址
GLOOP:
CLR A
MOVC A,@A+DPTR
CJNE A,#00H,G_F_2 ;音名是否等于0
MOV R1,#00H ;清R1
MOV R2,#00H ;清R2
POP DPL
POP DPH
RET
G_F_2:
CLR A
MOVC A,@A+DPTR ;读音名表读取音名
XRL A,R7
JZ G_F_END ;是否相同
INC DPTR
CLR C ;音名不相同地址指针指到下一音名位置
MOV A,R2
ADD A,#02H
MOV R2,A ;低地址保存到R2
JNC G_F_3
INC R1 ;高地址保存到R1
G_F_3:
LJMP GLOOP
G_F_END:
MOV DPH,R1 ;取音频65536l-(OSFREQ/(24l*freq))表的地址
MOV DPL,R2
CLR A ;读取65536l-(OSFREQ/(24l*freq)的值到R3(HIGH),R4(LOW)
MOVC A,@A+DPTR
MOV R3,A
CLR A
INC DPTR
MOVC A,@A+DPTR
MOV R4,A
POP DPL
POP DPH
RET
;/***************************************************************************************
;函数名称: void PORT_Init(void)
;功能描述: 初始化I/O
;输入: 无
;输出: 无
;全局变量: XBR2,P74OUT
;调用模块: 无
;***************************************************************************************/
PORT_Init:
MOV XBR2,#40H ;使能交叉开关和弱上拉
ORL P74OUT,#0ffH ;使能P6,P7推挽输出
RET
Play:
;无效看门狗
MOV WDTCN,#0deH
MOV WDTCN,#0adH
LCALL PORT_Init
MOV OSCICN,#014H ;使用内部晶振
MOV DPTR,#sing
LOOP:
CLR A
MOVC A,@A+DPTR ;是否' '字符
XRL A,#020H
JZ DEAL
CLR A
MOVC A,@A+DPTR
XRL A,#07CH ;是否'|'字符
JZ DEAL
CLR A
MOVC A,@A+DPTR
XRL A,#0DH ;是否'\r'字符
JZ DEAL
CLR A
MOVC A,@A+DPTR
CJNE A,#0AH,NEXT1 ;是否'\n'字符
DEAL:
INC DPTR
SJMP LOOP
NEXT1:
CLR A
MOVC A,@A+DPTR ;乐曲结束则播放完毕
JNZ NEXT2
LCALL SoundOff
RET
NEXT2:
CLR A
MOVC A,@A+DPTR ;半音标志
CJNE A,#023H,NEXT3
MOV R5,#01H ;半音R5=0x01
SJMP LOOP
NEXT3:
CLR A
MOVC A,@A+DPTR ;从音名获取频率
MOV R7,A
LCALL isdigit ;是否使数字
JC NEXT4
CLR A
MOVC A,@A+DPTR
MOV R7,A
LCALL isalpha ;是否使字母
JNC NEXT5
NEXT4:
LCALL GetFreq ;得到音频65536l-(OSFREQ/(24l*freq))的值
MOV R0,#010H ;赋延时变量到R0
SJMP NEXT6
NEXT5:
MOV R5,#00H
INC DPTR
LJMP LOOP
NEXT6:
INC DPTR
CLR A
MOVC A,@A+DPTR ;从下一个符号获取额外音长符号
LOOP2:
JZ NEXT7 ;非音长符号则下次处理
CLR A
MOVC A,@A+DPTR
MOV R7,A
LCALL isdigit ;是否数字键
JC NEXT7
CLR A
MOVC A,@A+DPTR
MOV R7,A
LCALL isalpha ;是否字母键
JNC NEXT8
AJMP NEXT7
NEXT8:
CLR A
MOVC A,@A+DPTR ;额外延时一拍
CJNE A,#02DH,NEXT9
MOV A,#08H
ADD A,R0
MOV R0,A
NEXT9:
CLR A
MOVC A,@A+DPTR ;额外延时半拍
CJNE A,#02EH,NEXT10
MOV A,#04H
ADD A,R0
MOV R0,A
NEXT10:
CLR A
MOVC A,@A+DPTR ;下划线相当于简谱中音名下面的下划线,延时减半
CJNE A,#05FH,NEXT11
MOV A,R0
CLR C
RRC A
MOV R0,A
NEXT11:
CLR A
MOVC A,@A+DPTR ;双下划线相当于简谱中音名下面的双下划线,延时减为1/4
CJNE A,#03DH,NEXT12
MOV A,R0
RRC A
RRC A
ANL A,#03FH
MOV R0,A
NEXT12:
INC DPTR ;取下一音名
CLR A
MOVC A,@A+DPTR
MOV R7,A
LJMP LOOP2
NEXT7:
PUSH 0
MOV A,R3
MOV R0,A
MOV A,R4 ;发声
ORL A,R0
POP 0
JZ NEXT13
LCALL Sound
SJMP NEXT14
NEXT13:
LCALL SoundOff ;关闭声音
NEXT14:
LCALL Delay ;延时
LCALL SoundOff
MOV R0,#01H
LCALL Delay ;两个引之间的间歇
LJMP LOOP
PLAY_END:
RET
;编谱说明,低音(简谱中数字下面有一个点的)1234567对应的为小写cdefgab
;中音(简谱中数字上下都没有点的)1234567对应的也为1234567
;高音(简谱中数字上面有一个点的)1234567对应的为大写CDEFGAB
;对于降音符b或声音符#一律用#+合适的音名例如#5
;一个音符本身为一拍,加下划线后为半拍加等号为1/4拍 如:65_ 4= 则音6为一拍,音5为半拍,音4为1/4拍
;下划线或等号连续书写则音长连续变短
;音符后加-或.表示延长。‘-’延长一拍‘.’延长半拍多加则延长连续增加
main:
MOV TMOD,#11H
SETB ET0
SETB EA
MOV SP,#80H ;置堆栈指针
MOV R0,#0AH
LCALL Delay ;延时
LCALL Play ;播放音乐
LCALL SoundOff ;关闭声音
AJMP $
RET
sing:
DB "g_g_ag 1b- g_g_ag 21- g_g_53 1ba 004_4_ 312 1--1 " ;生日快乐
DB 00H
;/*************音名***************/
notename:
DB 063H,064H,065H,066H,067H,061H,062H,031H,032H,033H,034H,035H,036H,037H,043H,044H,045H,046H,047H,041H,042H,000H
;/*************音名***************/
halfnotename:
DB 063H,064H,066H,067H,061H,031H,032H,034H,035H,036H,043H,044H,046H,047H,041H,000H
;音频65536l-(OSFREQ/(24l*freq))表
timreg:
DW 0FE22H,0FE56H,0FE85H,0FE9AH,0FEC1H,0FEE4H,0FF03H,0FF11H,0FF2BH,0FF43H,0FF4DH,0FF61H,0FF72H,0FF82H,0FF89H,0FF96H,0FFA1H,0FFA7H,0FFB0H,0FFB9H,0FFC1H
;半音频65536l-(OSFREQ/(24l*freq))表
halftimreg:
DW 0FE3DH,0FE6EH,0FEAEH,0FED3H,0FEF4H,0FF1FH,0FF37H,0FF57H,0FF29H,0FF7AH,0FF8FH,0FF9CH,0FFACH,0FFB5H,0FFBDH
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -