《单片机课程设计单片机演奏乐曲试验.doc》由会员分享,可在线阅读,更多相关《单片机课程设计单片机演奏乐曲试验.doc(19页珍藏版)》请在三一办公上搜索。
1、单片机课程设计课程设计题目:单片机演奏乐曲试验课程设计组: 08电子信息工程姓名: 单片机演奏乐曲实验摘要:本文是应用16F877A单片机原理和控制理论来设计音乐盒的硬件电路,并利用16单片机语言进行程序设计。通过控制单片机内部的定时器来产生不同频率的方波,驱动喇叭发出不同音调的音乐,再利用延迟来控制发音时间的长短。该程序通过把乐谱转化成相应的定时常数来驱动发音设备演奏出悦耳动听的音乐。这种控制电路结构简单,可靠性高,应用性强;软件程序适应范围广,对于不同的音乐只需要改变相应的定时常数即可。关键词:16F877A单片机 汇编语言单片机控制电路的设计本设计中用到了16F877A单片机,蜂鸣器。蜂
2、鸣器硬件电路控制如下图音乐产生的方法:一首音乐是许多不同的音阶组成的,而每个音阶对应着不同的频率,这样我们就可以利用不同的频率的组合,即可构成我们所想要的音乐了,当然对于单片机来产生不同的频率非常方便,我们可以利用单片机的定时/计数器T0来产生这样方波频率信号,因此,我们只要把一首歌曲的音阶对应频率关系弄正确即可。现在以单片机12MHZ晶振为例,例出高中低音符与单片机计数T0相关的计数值如下表4.1所示:表4.1高中低音符与单片机计数T0相关的计数值音符对应的PR2值音符对应的PR2值M_1119M_2105M_394M_579M_670H_159L_5158L_6141如表4.2所示:音乐的
3、音拍,一个节拍为单位(C调)表4.2音乐的音拍曲调值DELAY曲调值DELAY调4/4125ms调4/462ms调3/4187ms调3/494ms调2/4250ms调2/4125ms对于不同的曲调我们也可以用单片机的另外一个定时/计数器来完成。发音部分代码在程序中实现,靠单片机的一个管脚输出,考虑到声音可能不够大所以我们加入了功放电路,利用LM386来对声音信号进行放大。音频输出信号由ADU OUT引出,信号可经功放电路LM386输出到扬声器或耳机。软件流程图程序代码如下所示:;乐曲名:友谊天长地久*;文件名“3.ASM”;功能:单片机演奏乐曲实验;*#include p16f877a.inc
4、 #DEFINE youyi 0X2100;乐谱编号#define L_5.158#defineL_6.141#defineM_1.119#defineM_2.105#defineM_3.94#defineM_5.79#defineM_6.70#defineH_1.59#defineM_0.0; tone8=158,141,119,105,94,79,70,59;声调的高低,实际上是PWM的周期值;计算方法是CCP的时钟1MHz除以预分频比16,再除以要产生的频率,最后再减去1。PORTD_D EQU 20H ;显示缓冲器COUNTCOUNT1 EQU 21HCOUNT2 EQU 22HCOU
5、NT3 EQU 23HCOUNT4 EQU 24HSAVEW EQU 25H ;W保护寄存器SAVES EQU 26H ;STATUS保护寄存器COUNT5 EQU 27H ;节拍数H EQU 28H ;地址寄存器HANG EQU 29H ;行寄存器LIE EQU 30H ;列寄存器TMP1 EQU 31H ;TMP1缓存寄存器Byte EQU 32H ;缓存Count6 EQU 33H ;节拍数Count7 EQU 34H ;节拍数DD_RAM_ADDREQU 35H ; 第一行显示地址寄存器DD_RAM_UL EQU 36H ; 第二行显示地址寄存器COUNT EQU 37HCount E
6、QU 38H ;计数寄存器Count2 EQU 39H;*;* 定义 LCD数据& 控制I/O口 ;*#defineLCD_DB7 PORTB,3 ;占用的I/O口定义 #defineLCD_DB6 PORTB,2 ;LCD的DB6与RB2连接,其它类推#defineLCD_DB5 PORTB,1 ;#defineLCD_DB4 PORTB,0 ;#define LCD_EN PORTC,0#define LCD_RS PORTC,1#defineLCD_DB7_DIRTRISB,3 ;对应的方向寄存器定义#defineLCD_DB6_DIRTRISB,2 ;#defineLCD_DB5_DI
7、RTRISB,1 ;#defineLCD_DB4_DIRTRISB,0 ;#defineLCD_EN_DIRTRISC,0 ;#defineLCD_RS_DIRTRISC,1 ; ;*LCD 模块命令*#defineDISP_ON0x00C ; 开显示#defineDISP_ON_C0x00E ; 开显示, 开指针#defineDISP_ON_B0x00F ; 开显示, 开指针,开闪烁#defineDISP_OFF0x008 ; 关显示#defineCLR_DISP0x001 ; 清显示的操作数#defineENTRY_INC0x006 ; 操作数#defineENTRY_INC_S0x007
8、 ; 操作数#defineENTRY_DEC0x004 ; 操作数#defineENTRY_DEC_S0x005 ; 操作数;* ORG youyi DE L_5,L_5,M_1,M_1,M_1,M_1,M_1,M_1,M_1,M_3,M_3,M_2,M_2,M_2,M_2DE M_1,M_2,M_2,M_3,M_3,M_1,M_1,M_1,M_1,M_1,M_3,M_3,M_5,M_5,M_6DE M_6,M_6,M_6,M_6,M_6,M_6,M_6,M_6,M_6,M_5,M_5,M_5,M_5,M_3,M_3DE M_3,M_1,M_1,M_2,M_2,M_2,M_2,M_1,M_2,
9、M_2,M_3,M_3,M_1,M_1,M_1DE M_1,L_6,L_6,L_6,L_5,L_5,M_1,M_1,M_1,M_1,M_1,M_1,M_1,M_1,M_6DE M_6,M_5,M_5,M_5,M_5,M_3,M_3,M_3,M_1,M_1,M_2,M_2,M_2,M_2,M_1DE M_2,M_2,M_6,M_6,M_5,M_5,M_5,M_5,M_3,M_3,M_3,M_5,M_5,M_6,M_6DE M_6,M_6,M_6,M_6,M_6,M_6,H_1,H_1,M_5,M_5,M_5,M_5,M_3,M_3,M_3DE M_1,M_1,M_2,M_2,M_2,M_2,M_
10、1,M_2,M_2,M_3,M_3,M_1,M_1,M_1,M_1DE L_6,L_6,L_6,L_5,L_5,M_1,M_1,M_1,M_1,M_1,M_1,M_0,M_0,M_0,M_0;* ORG 0x000 NOP ;空指令 GOTO MAIN ORG 0x004 ;中断入口 BANKSEL SAVEW MOVWF SAVEW SWAPF STATUS,W CLRF STATUS MOVWF SAVES ;中断保护 GOTO CCPINT ;*TABLE*TABLE1 ;取第一行的显示码TMR2 COUNT ADDWF PCL,1 ;地址偏移量加当前PC值 RETLW I ;T RET
11、LW n ;M RETLW n ;R RETLW o ;2 RETLW v ;空格 RETLW a ;空格 RETLW t ;C RETLW o ;O RETLW r ;U RETLW ;N RETLW ;T RETLW V ;N RETLW 1 ;T RETLW . ;N RETLW 5 ;T RETLW 00H;*TABLE1*TABLE ;取第二行显示TIME: ms ADDWF PCL,1 ;地址偏移量加当前PC值 RETLW H ;T RETLW e ;I RETLW l ;M RETLW l ;E RETLW o ;: RETLW ;空格 RETLW P ;空格 RETLW I ;
12、空格 RETLW C ;空格 RETLW ! ;空格 RETLW 00H;*TABLE2*TABLE2 ADDWF PCL,1 RETLW 30H ;0 RETLW 31H ;1 RETLW 32H ;2 RETLW 33H ;3 RETLW 34H ;4 RETLW 35H ;5 RETLW 36H ;6 RETLW 37H ;7 RETLW 38H ;8 RETLW 39H ;9;*主程序开始*MAIN CALL LCD_DISPAY BANKSEL TRISD ;选择体1 CLRF TRISD ;PORTD为输出端口 MOVLW 07H ; MOVWF OPTION_REG ;1:256
13、 BANKSEL T1CON CLRF COUNT5 MOVLW 30H ;分频器为1:8,关闭TMR1 MOVWF T1CON ; BCF PIR1,TMR1IF ;溢出标志位清零 CLRF TMR1H CLRF TMR1L MOVLW 0xEE ;设定TMR1低位初值 ADDWF TMR1L ; MOVLW 0x85 ;设定TMR1高位初值 ADDWF TMR1H ; BSF T1CON,0 ;启动TMR1 BANKSEL TRISC ;跳到体1 BCF TRISC,2 ;CCP1为输出状态 BANKSEL EEADR ;跳到体2 MOVLW youyi ;将地址存到W寄存器 MOVWF
14、EEADR ;将地址送入EEPROM地址寄存器 BANKSEL EECON1 ;选定BANK3 BCF EECON1,EEPGD ;选择EEPROM作为非易失性存储器操作对象 BSF EECON1,RD ;启动一次读EEPROM的操作 BANKSEL EEDATA ;跳到体2 MOVF EEDATA,W ;由于EEPROM的读出操作花费的时间很短,此时EEPROM BANKSEL PR2 ;跳到体1 MOVWF PR2 ;将W的值存到PR2 BANKSEL T2CON ;跳到体0 MOVLW 0x07 ;预分频1:16,后预分频1:1 MOVWF T2CON ;开定时器2 MOVLW 0x0C
15、 ;将0x0C存到W寄存器 MOVWF CCP1CON ;使用8位PWM方式 BANKSEL PR2 ;跳到体1 MOVF PR2,0 ;将PR2值存到W寄存器 BANKSEL CCPR1L ;跳到体0 MOVWF CCPR1L ;将W存到CCPR1L MOVLW B11111100 ;屏蔽低两位 ANDWF CCPR1L,1 RRF CCPR1L,1 ;CCPR1L右移一位 RRF CCPR1L,1 ;CCPR1L右移一位 RRF CCPR1L,1 ;CCPR1L右移一位 BANKSEL PIE1 ;跳到体1 BSF PIE1,TMR1IE ;启动TMR1中断 BSF INTCON,PEIE
16、 ;开启外设中断 BSF INTCON,GIE ;开启全局中断 BANKSEL PORTD ;选择体0 CLRF PORTD MOVLW 01H ;显示缓冲器赋初值 MOVWF PORTD_D LOOP ;CALL DELAY_500ms ;延时500ms ;RLF PORTD_D ;显示缓冲器循环左移 GOTO LOOP ;等待中断;*CCPINT中断子程序*CCPINT BTFSS PIR1,TMR1IF ;判断是否是TMR1中断 GOTO JMP4 ;否,跳出中断 BCF PIR1,TMR1IF ;是,清中断标志位 MOVLW 30H ;分频器为1:8,关闭TMR1 MOVWF T1CO
17、N ; CLRF TMR1H ;清TMR1H CLRF TMR1L ;清TMR1L MOVLW 0xEE ;设定TMR1低位初值 ADDWF TMR1L ; MOVLW 0x85 ;设定TMR1高位初值 ADDWF TMR1H ; BSF T1CON,0 ;启动TMR1 BANKSEL EEADR ;跳到体2 MOVLW youyi ;将地址存到W寄存器 MOVWF EEADR ;将地址送入EEPROM地址寄存器 BANKSEL COUNT5 ;跳到体0 MOVF COUNT5,0 ;将COUNT存到W寄存器 BANKSEL EEADR ;跳到体2 ADDWF EEADR,1 ;EEADR=E
18、EADR+COUNT BANKSEL EECON1 ;选定BANK3 BCF EECON1,EEPGD ;选择EEPROM作为非易失性存储器操作对象 BSF EECON1,RD ;启动一次读EEPROM的操作 BANKSEL EEDATA ;跳到体2 MOVF EEDATA,W ;由于EEPROM的读出操作花费的时间很短,此时EEPROM BANKSEL PR2 ;跳到体1 MOVWF PR2 ;将W存到PR2 BANKSEL CCPR1L ;跳到体0 MOVWF CCPR1L ;将W存到CCPR1L MOVLW B11111100 ;将11111100存到W寄存器 ANDWF CCPR1L,
19、1 ;屏蔽低两位 RRF CCPR1L,1 ;CCPR1L左移一位 RRF CCPR1L,1 ;CCPR1L左移一位 RRF CCPR1L,1 ;CCPR1L右移一位 MOVLW .149 ;将149存到W寄存器 SUBWF COUNT5,0 ;W=COUNT-149 BTFSS STATUS,C ;判断是否有借位 GOTO JMP1 ;有,跳到JMP1 GOTO JMP2 ;无,跳到JMP2JMP1 INCF COUNT5,1 ;COUNT=COUINT+1 GOTO JMP ;跳到JMPJMP2 CLRF COUNT5 ;COUNT清零JMP MOVLW B00000000 ;送.0到W寄
20、存器 XORWF PORTD,0 ;判断PORTD是否为0 BTFSS STATUS,Z GOTO JMP3 ;否,跳到JMP1 MOVF PORTD_D,0 ;是,将PORTD_D的值 MOVWF PORTD ;送到PORTD GOTO JMP4JMP3 CLRF PORTD ;PORTD清零 BCF STATUS,C ;清楚其他操作对C的影响 RLF PORTD_D ;显示缓冲器循环左移 BTFSC STATUS,C GOTO JMP5 GOTO JMP4 JMP5 MOVLW 01H ;显示缓冲器赋初值 MOVWF PORTD_D JMP4 SWAPF SAVES,W MOVWF STA
21、TUS SWAPF SAVEW,F SWAPF SAVEW,W ;恢复中断 RETFIE;*700ms延时子程序*DELAY_500ms MOVLW .5 MOVWF COUNT3LOOP1 MOVLW D133 ;设置外部循环次数 MOVWF COUNT1 ;LOOP2 MOVLW D249 ;设置内部循环次数 MOVWF COUNT2 ;LOOP3 DECFSZ COUNT2 ,1 ;内部循环变量自减1,为0则跳转 GOTO LOOP3 ; DECFSZ COUNT1,1 ;外部循环变量自减1,为0则跳转 GOTO LOOP2 ; DECFSZ COUNT3,1 ;外部循环变量自减1,为0
22、则跳转 GOTO LOOP1 ; RETURN ;返回主程序;*LCD_DISPAY显示子程序*LCD_DISPAY BANKSEL H ;选择体0 MOVLW 0xC0 ;LCD第二行首地址 MOVWF DD_RAM_UL MOVLW 0x80 ;LCD第一行首地址 MOVWF DD_RAM_ADDR CALL LCD_INTF ;调LCD初始化子程序 MOVLW .0 ;第一行显示TMR2 COUNT MOVWF HANG ;的位置 MOVLW .2 MOVWF LIE CALL ADRESS ;调地址转换子程序 CALL SET_CURSOR ;调设置光标子程序 CALL DISPLAY
23、 ;调第一行显示子程序 MOVLW .1 ;第二行显示TIME:XXXXms MOVWF HANG ;的位置行和列 MOVLW .0 MOVWF LIE CALL ADRESS ;调地址转换子程序 CALL SET_CURSOR ;调设置光标子程序 CALL DISPLAY1 ;调第二行显示子程序 ;CALL WATCH_CHANGE ;调WATCH_CHANGE子程序 MOVLW .1 ;设置时间显示位置行和列 MOVWF HANG MOVLW .7 MOVWF LIE CALL ADRESS ;调地址转换子程序 CALL SET_CURSOR ;调设置光标子程序 ;CALL DISPLAY
24、_WATCH ;调时间显示子程序 RETURN ;子程序返回;*LCD_INTF初始化子程序* LCD_INTF BSF STATUS,RP0 ;Bank 1 BCF STATUS,RP1 ;初始化相关I/O引脚 BCF LCD_DB7_DIR BCF LCD_DB6_DIR BCF LCD_DB5_DIR BCF LCD_DB4_DIR BCF LCD_EN_DIR BCF LCD_RS_DIR BCF STATUS,RP0 ;Bank 0 BCF LCD_RS BCF LCD_EN ;清数据线 MOVLW0x28 ;设置工作方式 CALLSendCmd ;四位数据总线,两行显示,5X7点阵
25、字符 BSF LCD_EN BCF LCD_EN MOVLWDISP_ON ;开显示 CALLSendCmd MOVLWENTRY_INC ;设置指针移动方式 CALLSendCmd CALLclrLCD ;清屏 MOVLW 0X80 ;设定行值 CALL SendCmd RETURN ;子程序返回;*ADRESS地址转换子程序*ADRESS BTFSS HANG,0 ;判断行是否为1 GOTO J1 ;是,跳到J1 MOVF LIE,0 ;否,将列值送到W寄存器 ADDWF DD_RAM_UL,0 ;第二行首地址加上列值 GOTO J2J1 MOVF LIE,0 ;将列值送到W寄存器 ADD
26、WF DD_RAM_ADDR,0 ;第一行首地址加上列值 J2 MOVWF H ;将地址存到H寄存器 RETURN ;子程序返回;*SET_CURSOR设置光标位置子程序* SET_CURSOR BANKSEL H MOVF H,0 ;设置光标位置 CALL SendCmd MOVLW DISP_ON ; 开显示 CALL SendCmd RETURN ;子程序返回;*DISPLAY第一行显示子程序*DISPLAY CLRF COUNT ;清0查表偏移地址 WRITE_A MOVFW COUNT ;COUNT值送到W寄存器 CALL TABLE ;查表,显示TMR2 COUNT MOVWF TMP1 ;送暂存器 INCF COUNT,1 ;偏移地址加1 MOVFW TMP1 ;TMP1值送到W寄存器 XORLW 00H ;判断是否显示完所有数据 BTFSC STATUS,Z ;(约定表格做后一个00H做为结束标志) GOTO $+4 ;全部显示完成 MOVFW TMP1 ;TMP1值送到W寄存器 CALL putcLCD ;没有显示完,把当前查表所得数据送LCD显示 GOTO WRITE