OUT BIT P2.0 ;定义音频输出端口,p2.0
N EQU 3 ;歌曲总数
OUT_NUM EQU P1 ;数码管显视当前所放歌曲曲数
ORG 0000H
AJMP MAIN
ORG 0003H
AJMP LAST_SONG ;外部中断0用于接上一曲歌按键
ORG 000BH
AJMP F_T0 ;定时器0用于定时,作音符发生器用
ORG 0013H
q4: AJMP NEXT_SONG ;外部中断1接下一曲歌按键
ORG 001BH
AJMP START_PAUSE ;定时器1用计数,这里用作中断,接开始/暂停键,初值为0ffH,方式2
ORG 0030H
MAIN: MOV SP,#60H
MOV DPTR,#TABLE ;DPRT指向每首歌曲的入口地址的地址。
MOV R0,#30H ;R0中存入数据30H,这里在以30H开始的单元存放每首歌曲的入口地址,其中30H,31H存放
;歌曲的节拍入口地址,32H,33H存放歌曲音符入口地址,每首歌占用四个存储存单元。
MOV R5,#00H ;R5中存放表TABLE中正在执行操作的序号
MOV R6,#1 ;R6存放正在设置入口信息的歌曲数
SET_TAB: MOV A,R5 ;设置每首歌曲的入口信息,存放在以30H开始的存储单元中。
MOVC A,@A+DPTR
MOV @R0,A
INC R5
INC R0
MOV A,R5
MOVC A,@A+DPTR
MOV @R0,A
INC R5
INC R0
MOV A,R5
MOVC A,@A+DPTR
MOV @R0,A
INC R0
INC R5
MOV A,R5
MOVC A,@A+DPTR
MOV @R0,A
INC R0
INC R5
INC R6 ;设置完一首歌曲后,歌曲数加一
CJNE R6,#N+1,SET_TAB ;是否设置完,没有便继续,否则进行下面的操作
;*********************************** 对中断,计数器的相关参数进行设置
MOV TMOD, #61H ;计数器0工作方式1,计数器1工作方式2
MOV TH1,#0FFH ;给计数器1置初值0FFH,又由于是工作方式2,所以
MOV TL1,#0FFH ;计数器计数为1,相当于一外部中断。
SETB ET1 ;允许计数器1中断
SETB ET0 ;允许计数器具0中断
CLR PT0 ;计数器0为低优先级
SETB PT1 ;计数器1为高优先级
SETB IT0 ;外部中断0为跳沿触发
SETB PX0 ;高优先级
SETB IT1 ;外部中断1为跳沿触发
SETB PX1 ;高优先级
SETB EX1 ;允许外部中断1中断
SETB EX0 ;允许外部中断定0中断
SETB EA ;开中断总开关
SETB TR1 ;定时器1开始工作,作中断用
SETB OUT ;音频输出端口初始化
;*********************************** ;设置结束
CLR F0 ;设置F0=0,用来作暂停/播放的标置位用
MOV 22H,#01H ;22H单元中存放正在播放的歌曲编号
MOV DPTR,#OUT_TAB ;将正在播放的歌曲编号送数码管显视
MOV A,22H
MOVC A,@A+DPTR
MOV OUT_NUM,A
MOV R7,#00H ;R7中存放歌曲总信息的入口地址
START0:MOV R4,#00H ;R4存放当前正在播放歌曲的第几个节拍数
MOV R0,#30H ;30H开始的单元中存放歌曲的入口信息
MOV A,R7 ;将歌曲的节拍表的入口地址送到DPTR
ADD A,R0
MOV R0,A
MOV DPH,@R0
INC R0
MOV DPL,@R0
INC R0
MOV A,R4
INC R4
MOVC A,@A+DPTR ;取出第一节拍数,其实第一个节拍不是歌曲的第一个节拍,而是表示几分音符
;****************************************************
MOV 26H,A ;将取出的音符数+节拍数保存在职26H单元中
NEXT: MOV R0,#30H ;开始取出歌曲的第一个数据
MOV A,R7
ADD A,R0
MOV R0,A
MOV DPH,@R0
INC R0
MOV DPL,@R0
INC R0
MOV A,R4
INC R4
MOVC A,@A+DPTR ;放在A中
;****************************************************
JZ END0 ;若为0,则表示为休止符,不唱,本次音符不唱,
MOV R1,A ;不为0,取出节拍数
ANL A,#0FH
MOV R2,A
MOV A,R1
SWAP A
ANL A,#0FH
JNZ SING ;音符不为0,唱
CLR TR0 ;为0,不唱,关频率发生器
SJMP SING1
SING: DEC A ;开始唱,进行相应的数据处理
MOV R3,A
RL A
MOV DPH,@R0
INC R0
MOV DPL,@R0
INC R0
MOVC A,@A+DPTR
MOV 21H,A
MOV TH0,A
MOV A,R3
RL A
INC A
MOVC A,@A+DPTR
MOV 20H,A
MOV TL0,A
SETB TR0 ;开唱
SING1:LCALL DELAY ;每个音符唱多久
JB F0,FOR ;是否暂停,
AJMP NEXT ;没有暂停,继续
FOR: CLR TR0 ;暂停,不唱
JB F0,$ ;等待播放
AJMP NEXT ;开始播放
END0: CLR TR0 ;不唱
MOV A,22H ;唱完处理
CJNE A,#N,WW ;是不是全部歌曲都唱完
MOV 22H,#01H ;全部唱完,则从第一首开始再唱
MOV R7,#00H
MOV OUT_NUM,#06H ;数码管显视第一首歌曲编号
AJMP WWW
WW: MOV A,R7 ;没有全部唱完,唱下一首,歌曲的入口信息调整
ADD A,#4
MOV R7,A
INC 22H
CLR EA
PUSH DPH
PUSH DPL
MOV A,22H
MOV DPTR,#OUT_TAB
MOVC A,@A+DPTR
MOV OUT_NUM,A ;数码管显视相应的歌曲编号
POP DPL
POP DPH
WWW: SETB EA
AJMP START0 ;开始下一首的演唱
F_T0: MOV TH0,21H ;定时器0置初值
MOV TL0,20H
CPL OUT ;频率产生
RETI
NEXT_SONG: PUSH ACC ;下一曲中断程序处理,保护现场
PUSH DPH
PUSH DPL
CLR EA ;关中断
MOV A,22H
CJNE A,#N,Q ;是最后一首吗?
MOV R7,#00H ;是最后一首,则R7指向第一首,演唱第一首
MOV 22H,#01H
AJMP BACK
Q: INC 22H ;不是最后一首,唱下一首,R7内容加4,歌曲数加1
MOV A,R7
ADD A,#4
MOV R7,A
BACK: MOV R4,#00H ;数码管显视相应的歌曲编号
MOV A,22H
MOV DPTR,#OUT_TAB
MOVC A,@A+DPTR
MOV OUT_NUM,A
;********************************************
MOV B,R0 ;对下首要演唱的歌曲的几分拍进行调整,同时对R0中的内容进行保护
MOV R4,#00H
MOV R0,#30H
MOV A,R7
ADD A,R0
MOV R0,A
MOV DPH,@R0
INC R0
MOV DPL,@R0
INC R0
MOV A,R4
INC R4
MOVC A,@A+DPTR
MOV 26H,A ;结果存入26H单元中
DEC R4
MOV R0,B ;恢复R0中的内容
;********************************************
POP DPL ;恢复现场
POP DPH
POP ACC
SETB EA
RETI ;中断返回
LAST_SONG: PUSH ACC ;上一曲中断程序处理开始,保护现场
PUSH DPH
PUSH DPL
CLR EA ;关中断
MOV A,22H ;曲目数送A
CJNE A,#1,QQ ;是否是第一首
MOV 22H,#N ;是第一首歌曲
MOV B,#4 ;将R7指向最后一首歌曲
MOV A,#N-1
MUL AB
MOV R7,A
AJMP BACK2 ;处理结束
QQ: DEC 22H
MOV A,R7 ;R7减4
SUBB A,#4
MOV R7,A
BACK2: MOV R4,#00H
MOV A,22H
MOV DPTR,#OUT_TAB
MOVC A,@A+DPTR
MOV OUT_NUM,A ;数码管显视相应歌曲的编号
;********************************************
MOV B,R0 ;对下首要演唱的歌曲的几分拍进行调整,同时对R0中的内容进行保护
MOV R4,#00H
MOV R0,#30H
MOV A,R7
ADD A,R0
MOV R0,A
MOV DPH,@R0
INC R0
MOV DPL,@R0
INC R0
MOV A,R4
INC R4
MOVC A,@A+DPTR
MOV 26H,A ;结果存入26H单元中
DEC R4
MOV R0,B ;R0中的内容恢复
END;
完整版见附件
一个汇编的播放器.zip
(19.48 KB, 下载次数: 11)
|