⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sldiy16-11.asm

📁 AVR单片机应用开发指南及实例,包含许多实例,挺不错
💻 ASM
字号:
;********************************************
;SL-DIY-08-16  实验十一
;I/O端口的又一应用-声音输入处理。
;请修改以上程序,如何用声控来启动。
;PB2的声控开关控制发音
;********************************************
;*ATmega16      8MHz     
;*双龙电子   www.sl.com.cn
;*	   teny	2005.11.12
;*********   teny@sl.com.cn   **************
;********************************************

.include "m16def.inc"
.org	$000
	rjmp	reset11

.def	TEMPDH	=r2
.def	TEMPDL	=r3
.def	CNT	=r10
.def	SCNN	=r11
.def	KEYN	=r12
.def	SCNK	=r13
.def	SCNDP	=r14
.def	KSNI	=r15

.def	TEMP	=r16
.def	TEMP1	=r17
.def	TEMP2	=r18
.def	TEMP3	=r19
.def	SCNTT	=r26	;

.def	MUSN	=r22
.def	TONL	=r21
.def	TONH	=r20

.def	PLYTON	=r25
.def	TONSET	=r24
.def	TONLNG	=r23

 
.cseg
.org	OVF0addr	;TIM1_OVF定时器1溢出中断处理入口地址
	RJMP	OUTPM	;转定时器1溢出中断处理,发音周期到, 
			;则跳转到发音输出态   

.cseg			;跳过中断区
.org	0x010		;定时器1溢出中断处理程序。
			;发音周期到,重新装入计数值,并由PC0输出
OUTPM:	OUT	TCNT1H,TONH	;重新将TONH新计时值载入TCNT1H内
	OUT	TCNT1L,TONL	;重新将TONH新计时值载入TCNL1H内
	SBIS	PORTC,0		;先检测PC0是否为1而跳转    
	RJMP	SETOP1		;若PC0口为0,则跳转到SETOP1,令PC0转为1
SETOP0:	CBI	PORTC,0		;若PC0为1,则令PC0转为1  
	LDI	MUSN,$00	;同时令MUSN为00值  
	RETI			;回中断前主程序,并令可再次中断返回

SETOP1:	SBI	PORTC,0		;若PC0为1,则令PC0转为1
	LDI	MUSN,$01	;同时令MUSN为01值      
	RETI			;回中断前主程序,并令可再次中断返回

.cseg	
.org	0x020			;

reset11:	
	ldi r17,$02		;栈指针置为$025f
	ldi r16,$5f
	out sph,r17
	out spl,r16
	wdr			;在使用看门狗计时器前需重设看门狗计时器
	ldi	temp,$0F	;WDTCR地址$21设定以TEMP缓冲,令WDE=D3=1
	out	WDTCR,temp	;并令预除为2048ms,设定WDE=D3=1,输出到WDTCR内
	LDI	MUSN,$00	;令MUSN为00值
	ldi	temp,$00	;令TEMP暂存器放入00
	OUT	TCCR1A,TEMP	;将TEMP=00输出到TCCR1A内,禁止比较器及PWM动作 
	OUT	TCCR1B,TEMP	;将TEMP=00输出到TCCR1A内,停止TC1计时及捕捉  ?
	LDI	TEMP,(1<<CS11)	;将02值预存入SRAM的$100内,作TC1的TCCR1B控制
	STS	$0100,TEMP	;令为计时预除8  
	CLI			;关中断
	ldi	r16,(1<<TOIE1)	;
	out	timsk,r16	;令TOIE1=1触发中断
	ldi	temp,$00	;PB口输入,带上拉电阻
	out	ddrb,temp
	LDI	TEMP,$FF	;
	OUT	DDRC,TEMP 	;PA口输出
	out	portc,temp
	out	portB,temp
	CLR	TEMP2		;暂存器清零
	CLR	TEMP1		;暂存器清零
	CLR	KSNI		;暂存器清零
	LDI	SCNTT,$02
	CLR	TONLNG		;暂存器清零
start11:	
	in r16,pinb		;读取PB口管脚状态,看是否有开关合上
	sbrs r16,2		;若PB2的开关合上,启动演奏乐曲  
	rcall	yin
	rjmp	start11		;若无键按下循环检测

yin:	
	push r16
	WDR			;关看门狗
	LDI	ZH,HIGH(yinyue*2)	;启动演奏则令数据装入Z指针
	LDI	ZL,LOW(yinyue*2)	;音乐演奏乐谱存放在YINYUE1*2的起始地址
NEXMUT1:	LPM		;将Z指针所指程序存储器乐曲依次取音符码及节拍码置于R0
	MOV	PLYTON,R0	;将取出的第一个音符码装入PLYTON作周期控制   
	LD	R0,Z+		;Z指针加1 
	LPM			;将Z所指程序存储器乐曲,依次取节拍码置于R0
	MOV	TONLNG,R0	;将取出的第一个节拍码装入PLYTON作节拍控制
	OR	R0,PLYTON	;将此R0节拍码与音符码PLYTON作OR运算
	LD	R0,Z+		;Z指针加1 
	BRNE	PLAYM1		;若音符码及节拍码非全为00值,则跳到PLAYM1演奏
	LDI	TEMP,$00	;若音符码及节拍码全为零(0000),则为乐曲结束标记
	OUT	TCCR1B,TEMP	;将TEMP=00输出到TCCR1B内,停止TC1计时及捕捉
	CLI			;关中断?
	SBI	PORTC,0		;令PC0=1,将喇叭输出OFF
	pop r16
	ret		;乐曲演奏完,调用返回
PLAYM1:	PUSH	ZH	;进栈保存数据  
	PUSH	ZL	;进栈保存数据
	TST	PLYTON	;检测PLYTON是否为0
	BREQ	MUSTD1	;若为0,则跳至MUSTD1作节拍等待
	LDI	ZH,HIGH(mustab*2)	;乐曲码装入Z地址
	LDI	ZL,LOW(mustab*2)	;计时器值存放于MUSTAB*2起始地址
	MOV	TEMP,PLYTON		;将乐曲码PLYTON装入TEMP寄存器内
	DEC	TEMP		;寄存器TEMP减1 
	LSL	TEMP		;寄存器TEMP左移即*2
	ADD	ZL,TEMP		;将正确的计时器控制乐曲码的存表位移,且使TEMP加入ZL
	LDI	TEMP,$00	;令TEMP=00,以便让ZH与进位标志位相加    
	ADC	ZH,TEMP		;将ZH与TEMP=00以及进位标志位C相加,得到真正的Z地址
	LPM		;将Z所指的PROM的预存乐曲码计时长度低位值装入R0 
	MOV	TONL,R0		;将乐曲码计时长度低位值R0装入TONL内 
	OUT	TCNT1L,R0	;将乐曲码计时长度低位值R0装入TCNT1L内  
	LD	R0,Z+		;Z指针加1 
	LPM			;将Z所指PROM的乐曲码的计时节拍码置于R0
	MOV	TONH,R0		;将节拍高位值R0装入TONH和TCNT1H内
	OUT	TCNT1H,R0	;
	POP	ZL		;出栈将ZL,ZH由堆栈指针依次取回
	POP	ZH
	LDS	TEMP,$0100	;将SRAM地址$0100 的内容装入TEMP内
	OUT	TCCR1B,TEMP	;将原$0100的SRAM内容输出到TCCR1B,控制TC1
	SEI			;内容02令TC1为计时预除8,开中断  
MUSTD1:	RCALL	PLYDEL		;调用延时子程序,延时0.2S 
	DEC	TONLNG		;将节拍码TONLNG减1   
	BRNE	MUSTD1		;若节拍码TONLNG不为0则转回,再发音;为0则顺执
	RJMP	NEXMUT1		;继续到NEXMUT1取乐曲码和节拍码   


PLYDEL:	LDI	TEMP,185	;延时子程序,185*1ms,即PLYDEL=185ms为十进制时间常数
DT3:	LDI	TEMP1,04	;送时间常数4*250us=1ms,DT3=1ms 
DT2:	LDI	TEMP2,250	;250为十进制时间常数,250*8*125ns=250ms,DT2=250us
DT1:	WDR	;1T
	WDR	;2T
	WDR	;3T
	WDR	;4T
	WDR	;5T
	DEC	TEMP2	;6T,TEMP-1
	BRNE	DT1	;8T,TEMP2不为0(则共执行250*8*T=250us)转
	DEC	TEMP1	;为0按顺序执行  
	BRNE	DT2	;TEMP1-1
	DEC	TEMP	;TEMP1不为0(则共执行250*4us=1ms)转,为0按顺序执行
	BRNE	DT3	;TEMP-1
	RET		;TEMP不为0(则共执行185*1ms=185ms)转,为0按顺序执行
			;子程序返回  

yinyue:		;生日快乐歌	
	.DB 20,02,00,01,20,01,22,04,20,04
	.DB 25,04,24,04,00,04
	.DB 20,02,00,01,20,01,22,04,20,04
	.DB 27,04,25,04,00,04
	.DB 20,02,00,01,20,01,32,04,29,04
	.DB 25,04,24,04,22,04
	.DB 30,02,00,01,30,01,29,04,25,04
	.DB 27,04,25,04,00,04
	.DB 20,02,00,01,20,01,22,04,20,04
	.DB 25,04,24,04,00,04
	.DB 20,02,00,01,20,01,22,04,20,04
	.DB 27,04,25,04,00,04
	.DB 20,02,00,01,20,01,32,04,29,04
	.DB 25,04,24,04,22,04
	.DB 30,02,00,01,30,01,29,04,25,04
	.DB 27,04,25,04,00,04
		;万水千山总是情
	.db 17,04,18,04,20,06,20,02,22,04,20,04,17,12,15,04	;
	.db 13,06,17,02,15,04,13,04,10,12,10,04,8,8,13,04	;
	.db 15,04,17,04,20,04,22,04,17,04,15,15,15,04,00,04	;
 	.db 17,04,18,04,20,06,20,02,22,04,20,04,17,12,15,04	;
	.db 13,06,17,02,15,04,13,04,10,12,10,04,8,8,13,06	;
	.db 17,02,15,06,13,02,13,04,10,04,13,15,13,8,17,04	;
	.db 20,04,22,12,25,10,22,04,18,04,20,06,22,02,20,12	;
	.db 17,04,20,8,17,04,20,04,22,12,25,04,25,04,22,04	;
	.db 22,04,20,04,17,12,15,04,13,06,17,02,15,04,13,04	;
	.db 12,04,13,15,13,15	;
 	.db 00,00
.cseg		;
mustab:			;音符表
	;约定:低音为数字后一点表示,高音为数字前一点表示,
        ; 半音为#号,'为隔开音符
	
	;1    2   3    4   5    6   7    8   9  
	;1. '#1. '2. '#2. '3.  '4. '#4. '5. '#5.

	;10  11  12  13   14  15  16  17  18  
	;6. '#6. '7. '1  '#1  '2 '#2  '3  '4 

	.DW 63627,63730,63835,63927
	.DW 64020,64102,64185,64259
	.DW 64330,64399,64463,64523
	.DW 64579,64632,64683,64731
	.DW 64776,64819

	;19  20  21  22  23  24  25   26  27 
	;#4  '5 '#5  '6 '#6  '7 '.1 '#.1 '.2

	;  28  29  30   31  32   33  34   35  36 
	;'#.2 '.3 '.4 '#.4 '.5 '#.5 '.6 '#.6 '.7

	.DW 64859,64897
	.DW 64933,64967,64999,65029
	.DW 65057,65084,65109,65133
	.DW 65156,65177,65197,65216
	.DW 65243,65251,65267,65282
		


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -