单片机课程设计报告 电子琴.doc_第1页
单片机课程设计报告 电子琴.doc_第2页
单片机课程设计报告 电子琴.doc_第3页
单片机课程设计报告 电子琴.doc_第4页
单片机课程设计报告 电子琴.doc_第5页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

电子音调发生器一、实验目的1. 了解计算机发声原理。 2. 熟悉定时器和键盘扫描电路的工作原理及编程方法。二、实验完成的功能1. 利用键盘17进行音调选择,即按下音符产生对应音调。2. 事先存储三首歌曲,并可进行选择播放。3. 谱曲功能:通过按键对LCD菜单选项进行选择,进入谱曲界面,通过按键17分别输入音高与几分音符类型,由按键输入若干数据完成谱曲。4. 在播放存储歌曲与谱曲播放时,对应音符及其节奏LCD显示对应频谱。5. 在播放音乐时按“返回”键出现返回界面,由键盘按“确认”键选择返回主菜单或循环播放。三、实验原理1. 音节由不同频率的方波产生,音节与频率的关系如表(1)所示。要产生音频方波,只要计算出某一音频的周期(1 / 频率),然后将此周期除以2,即为半周期的时间。利用计时器计时此半周期时间,每当计时到后就将输出方波的I/O(P1.7)反相,然后重复计时此半周期时间再对I/O反相,就可在P1.7脚得到此频率的方波。将P1.7经过驱动电路与蜂鸣器相连,随着P1.7口输出不同频率的方波,蜂鸣器便会发出不同的声音。音乐的节拍是由延时实现的,如果1拍的时间为0.4秒,1/4拍是0.1秒。只要设定延时时间,就可得到节拍的时间。延时实现基本延时时间,节拍值只能是它的整数倍。每个音节相应的定时器初值计算公式如下:(1/2)*(1/f)=(12/fose)*(216-x)即 x=216-(fose/24f)其中,f是音调频率,当晶振fosc=11.0592MHz时,音节“1”相应的定时器初值为x,则可得到x=63777D=F921H,其它的可同样得到。表(1) 音节与频率的关系 音调频率(Hz)X(HEX)1262F9212294F9E13330FA8C4349FAD85392FB686440FBE97494FC5Bi523FC8F在编写歌曲代码过程中,音高由三位数字组成:个位是表示17 这七个音符;十位是表示音符所在的音区:1-低音,-中音,-高音;百位表示这个音符是否要升半音: 0-不升,-升半音。音长最多由三位数字组成:个位表示音符的时值,其对应关系是: |数值(n): |0 |1 |2 |3 | 4 | 5 | 6 |几分音符: |1 |2 |4 |8 |16 |32 |64 音符=2n十位表示音符的演奏效果(0-2): 0-普通,-连音,-顿音,百位是符点位: 0-无符点,1-有符点。2键盘扫描将单片机P1.0P1.7(引脚18)与键盘上对应引脚相连,其中P1.0P1.3控制键盘的行,P1.4P1.7控制键盘的列,这次使用的键盘是4行4列,键盘上的第一行到第四行由8位十六进制代码的低四位控制,即第一行若有键按下,则8位十六进制代码的后四位为0x8,第二行有按键按下,则后四位代码为0x4,依此规律类推;键盘上的第一列到第四列由8位十六进制代码的高四位控制,即第一列若有键按下,则8位十六进制代码的前四位为0x8,第二列有按键按下,则前四位代码为0x4,依此规律类推。综上所述,可以根据8位十六进制的高四位和低四位数据,分别确定按下的键处于第几行第几列,从而确定按键的位置,实现键盘扫描的功能。 3LCD显示根据写命令函数wrcomd和写数据函数wrdata分别控制LCD的命令写入和数据写入。具体操作方法是由写命令函数wrcomd编程控制数据输入的行列,再由写数据函数wrdata编程写入需要在LCD上显示的数据或应执行的操作,结合两个命令一起控制LCD显示。四产品展示 五.实验程序#ifndef _DRIVEFUTION_H_#define _DRIVEFUTION_H_/*EEPROM函数*/*/* 关闭 ISP,IAP 功能 */ void ISP_IAP_disable(void) ISP_CONTR = 0X00; ISP_CMD = 0X00; ISP_TRIG = 0x00; /*字节读*/ uchar Byte_read(uint byte_addr) EA = 0; /关中断 ISP_CONTR = En_Wait_TIME; /开启ISP/IAP;并送等待时间 ISP_CMD = Read_COM; /送字节读命令字 ISP_ADDRH = (uchar)(byte_addr 8); /送地址高字节 ISP_ADDRL = (uchar)(byte_addr & 0X00FF); /送地址低字节 ISP_TRIG = 0X46; /送触发命令字 0X46、0XB9 ISP_TRIG = 0XB9; _nop_(); ISP_IAP_disable(); /关闭ISP/IAP功能 EA = 1; /开中断 return (ISP_DATA); /*字节编程*/ void Byte_program(uint byte_addr, uchar isp_iap_data) EA = 0; /关中断 ISP_CONTR = En_Wait_TIME; /开启ISP/IAP;并送等待时间 ISP_CMD = Prog_COM; /送字节编程命令字 ISP_ADDRH = (uchar)(byte_addr 8); /送地址高字节 ISP_ADDRL = (uchar)(byte_addr & 0X00FF); /送地址低字节 ISP_DATA = isp_iap_data; /送数据进ISP_DATA ISP_TRIG = 0X46; /送触发命令字 0X46、0XB9 ISP_TRIG = 0XB9; _nop_(); ISP_IAP_disable(); /关闭ISP/IAP功能 EA = 1; /开中断 /* 扇区擦除*/ void Sector_erase(uint sector_addr) EA = 0; /关中断 ISP_CONTR = En_Wait_TIME; /开启ISP/IAP;并送等待时间 ISP_CMD = Dele_COM; /送扇区擦除命令字 ISP_ADDRH = (uchar)(sector_addr 8); /送地址高字节 ISP_ADDRL = (uchar)(sector_addr & 0X00FF); /送地址低字节 ISP_TRIG = 0X46; /送触发命令字 0X46、0XB9 ISP_TRIG = 0XB9; _nop_(); ISP_IAP_disable(); /关闭ISP/IAP功能 EA = 1; /*写入函数*/void EEPROM_write(uint addr, uchar in_data) Sector_erase(addr); Byte_program(addr,in_data); /*EEPROM函数*/*/*音乐播放相关子函数*/*/void InitialSound(void) /初始化定时器BeepIO = 0;Sound_Temp_TH1 = (65535-(1/1200)*SYSTEM_OSC)/256;/ 计算TL1应装入的初值 (10ms的初装值)Sound_Temp_TL1 = (65535-(1/1200)*SYSTEM_OSC)%256;/ 计算TH1应装入的初值 TH1 = Sound_Temp_TH1;TL1 = Sound_Temp_TL1;TMOD |= 0x11;ET0 = 1;ET1 = 0;TR0 = 0;TR1 = 0;EA = 1;void BeepTimer0(void) interrupt 1 /音符发生中断函数BeepIO = !BeepIO;TH0 = Sound_Temp_TH0; TL0 = Sound_Temp_TL0;/*END*/*/*LCD操作子函数*/*/void wrcomd(char comd) /写入命令 cs = 0; _nop_(); rs = 0; _nop_(); e = 1; _nop_(); rw = 0; _nop_(); P0 = comd; _nop_(); rw = 0; _nop_(); _nop_(); rw = 1; _nop_(); _nop_(); _nop_(); _nop_();void wrdata(char data_wri) /往液晶中写入数据 cs = 0; _nop_(); rs = 1; _nop_(); e = 1; _nop_(); rw = 0; _nop_(); P0 = data_wri; _nop_(); rw = 0; _nop_(); _nop_(); rw = 1; _nop_(); _nop_(); _nop_(); _nop_(); void bmp(char data_write,int row_start,int row_end,uchar column_start,uchar column_end) /刷屏子函数 /初始化设置,对屏幕清零,默认值,为0,0,8,2,132 unsigned char i,j; int num_3; char num_0=0xb0; /uchar column_h,column_l; num_0+=row_start; for(i=row_start;i4); /设置列,先写入高4位再写入低四位 wrcomd(0x00|(0x0f&column_start); for(j=column_start;jnum_3;j+) wrdata(data_write); num_0+; void delay(long int time_delay) /延时子程序,执行time_delay个_nop_()延时 long int i;for(i=0;itime_delay;i+) _nop_();void write_word(char *p_word,int num,int pos_x,int pos_y,int width,int height) /写汉字/字符子函数 /对应参数 数据数组名,数组中位置,行位置,列位置,宽,高 char page; / 页号 unsigned int i,j,k,p; p = (unsigned int)num*2*width; /p确定汉字字模数据初始位置 i = height%8; k = (i)?(height/8+1):(height/8); page = 0xb0 + pos_y; for(i=0;i4); wrcomd(0x00|(0x0f&pos_x); for(j=0;j7|page-(unsigned char)0xb00) return; /*END*/*/* 键盘扫描函数*/*/*判断是否有键盘输入*/bit CheckState(void)/键盘状态判断子函数bit state=0;P1=0x0F; /键盘扫描if(P1!=0x0F)state=1; /检测是否有按键输入else state=0;return(state);/*获取键盘输入值*/uchar GetKeys(void)/键盘值获取子函数uchar column,line;scan=0xFE;while(scan&0x10)!=0) P1=scan;if(P1&0xF0)!=0xF0) /line 1 have key pressed column=(P1|0x0F); line=(scan|0xF0); key=column+line; return(key); else scan=(scan1)|0x01; return(0);/*应用子函数*/*/void csh(void) /初始化,清屏 int i; res = 0; delay(time_def); delay(time_def); res = 1; delay(time_def); cs = 0; /片选一直有效 delay(time_def); delay(time_def); for(i=0;i12;i+) /初始命令写入 wrcomd(tab1i); delay(time_def); bmp(0,0,8,0,132);void start_print(void) /开机显示画面子函数 int i,j; for(i=0;i4;i+) write_word(star_welcome,i,36+i*16,2,16,16); if(i+4)7) write_word(star_welcome,i+4,44+i*16,4,16,16); if(i+7)=0;j-) write_word(number,j,12+5*16,6,8,16); delay(5000); void menu_first_symbol(int choose) /菜单选择符刷新子函数,即“打钩项” bmp(0,0,8,4,18); write_word(menu_one,20,4,choose*2,16,16); /*音乐播放显示函数*/*/void music_display_one(unsigned char s,unsigned int x) /显示最底层子函数int i;bmp(0,2,8,18+x*16,34+x*16); for(i=3;i0;i-) if(s!=0) write_word(display,1,20+16*x,2*i,16,16); s=s-1; else write_word(display,0,20+16*x,2*i,16,16); /delay(200); void music_display_two(unsigned int p_x) /显示次底层子函数 int sign; sign=mc_sizep_x0; if(sign) if(!sizep_x) sign=0; mc_sizep_x0=sign;mc_sizep_x1=0; else music_display_one(sizep_x,p_x); mc_sizep_x1+=1; if(mc_sizep_x13) sizep_x-=1; else sizep_x+=1; /*/ else bmp(0,2,8,18+p_x*16,34+p_x*16); write_word(display,2,20+16*p_x,6,16,16); /delay(500); /*/void music_display_three(unsigned int mc) /音符状态置位函数 mc_sizemc-10=1; mc_sizemc-11=1; sizemc-1=1;void music_display_four(void) /显示次顶层子函数 int i; for(i=0;i7;i+) music_display_two(i); void music_display_five() /显示顶层子函数 int i; allsize=0; for(i=0;i7;i+) allsize+=mc_sizei0;music_display_four();/*void music_display(void) /显示主函数 int i; for(i=0;i= 2; /低音 if (SM=3) CurrentFre = 2; /高音Temp_T = 65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC);/计算计数器初值Sound_Temp_TH0 = Temp_T/256; Sound_Temp_TL0 = Temp_T%256; TH0 = Sound_Temp_TH0; TL0 = Sound_Temp_TL0 + 12; /加12是对中断延时的补偿 SLen=LengthTabLength%10; /算出是几分音符XG=Length/10%10; /算出音符类型(0普通1连音2顿音) FD=Length/100;LDiv=LDiv0/SLen; /算出连音音符演奏的长度(多少个10ms)if (FD=1) LDiv=LDiv+LDiv/2;if(XG!=1)if(XG=0) /算出普通音符的演奏长度 if (SLen0;i-) /发规定长度的音 while(TF1=0);TH1 = Sound_Temp_TH1;TL1 = Sound_Temp_TL1;TF1=0;display_between_musicplay(SL); /?要结合音长来控制其显示时间,弄清音长问题?if(LDiv3!=0)TR0=0; BeepIO=0;for(i=LDiv3;i0;i-) /音符间的间隔while(TF1=0);TH1 = Sound_Temp_TH1;TL1 = Sound_Temp_TL1;TF1=0;/*/*/void music_play_two_1(uchar *Sound,uint *NewFreTab,uint SoundLength,uint LDiv0,uint LDiv1) /播放原存储的音乐 uint xdata Point;uchar xdata Tone,Length,i; Point = 0;TR0 = 0; TR1 = 1;for(i=0;i4;i+) write_word(menu_one,i+1,4+(i+2)*16,0,16,16); while(Point SoundLength) Tone = SoundPoint; Length = SoundPoint+1; / 读出第一个音符和它时时值music_play_one(NewFreTab,Tone,Length,LDiv0,LDiv1);Point+=2; BeepIO = 0;while(allsize) music_display_five();void music_play_two_2(uint *NewFreTab,uint SoundLength,uint LDiv0,uint LDiv1) /播放谱曲存储的音乐 uint xdata Point;uchar xdata Tone,Length,i; Point = 0;TR0 = 0; TR1 = 1;for(i=0;i4;i+) write_word(menu_one,i+1,4+(i+2)*16,0,16,16);while(Point SoundLength) Tone = Byte_read(start_add+Point); Length = Byte_read(start_add+Point+1); / 读出第一个音符和它时时值music_play_one(NewFreTab,Tone,Length,LDiv0,LDiv1);Point+=2; BeepIO = 0;while(allsize) /显示末尾结束的状态 music_display_five(); /*void Play_Two(unsigned char *Sound,unsigned char Signature,unsigned char Octachord) unsigned int xdata NewFreTab12;/新的频率表unsigned char xdata i,j;unsigned int xdata LDiv0,LDiv1,SoundLength;menu_state=1;for(i=0;i 11)j = j-12;NewFreTabi = FreTabj*2;elseNewFreTabi = FreTabj;if(Octachord = 1)NewFreTabi=2;else if(Octachord = 3)NewFreTabi=2;LDiv0=12000/Speed; / 算出1分音符的长度(几个10ms)LDiv1= LDiv0/4; / LDiv为算出4分音符的长度 LDiv1= LDiv1-LDiv1*SOUND_SPACE; / LDiv最后为普通音最长间隔标准 SoundLength = 0;if(Sound!=Music_Memory) / while(SoundSoundLength != 0x00)/计算歌曲长度SoundLength+=2;for(i=0;i4;i+)write_word(menu_one,i+1,4+(i+2)*16,0,16,16); while(menu_state) / music_play_two_1(Sound,NewFreTab,SoundLength,LDiv0,LDiv1);bmp(0,0,8,2,132); for(i=0;i5;i+) write_word(restar,i,4+(i+2)*16,2,16,16); while(!CheckState();if(GetKeys()=0x11) /确认键返回,F键 menu_state=0;delay(1000);bmp(0,0,8,2,132); else while(Byte_read(start_add+SoundLength)!=0x00)/计算歌曲长度 SoundLength+=2; for(i=0;i4;i+) write_word(menu_one,i+1,4+(i+2)*16,0,16,16); while(menu_state) music_play_two_2(NewFreTab,SoundLength,LDiv0,LDiv1);bmp(0,0,8,2,132); for(i=0;i2) bmp(0,0,8,0,132);music_state=1;break;case 0x42: Byte_program(start_add+music_counter),0); write_word(number,0,4+(music_counter%48)%16)*8,2+(music_counter%48)/16)*2,8,16); +music_counter;break; case 0x88: Byte_program(start_add+music_counter),1); write_word(number,1,4+(music_counter%48)%16)*8,2+(music_counter%48)/16)*2,8,16); +music_counter;break; case 0x48: Byte_program(start_add+music_counter),2); write_word(number,2,4+(music_counter%48)%16)*8,2+(music_counter%48)/16)*2,8,16); +music_counter;break; case 0x28: Byte_program(start_add+music_counter),3); write_word(number,3,4+(music_counter%48)%16)*8,2+(music_counter%48)/16)*2,8,16); +music_counter;break; case 0x18: Byte_program(start_add+music_counter),4); write_word(number,4,4+(music_counter%48)%16)*8,2+(music_counter%64)/16)*2,8,16); +music_counter;break; case 0x84: Byte_program(start_add+music_counter),5); write_word(number,5,4+(music_counter%48)%16)*8,2+(music_counter%48)/16)*2,8,16); +music_counter;break; case 0x44: Byte_program(start_add+music_counter),6); write_word(number,6,4+(music_counter%48)%16)*8,2+(music_counter%48)/16)*2,8,16); +music_counter;break; case 0x24: Byte_program(start_add+music_counter),7); write_word(number,7,4+(music_counter%48)%16)*8,2+(music_counter%48)/16)*2,8,16); +music_counter;break; default:break; void Entry_Music(void) /输入乐谱播放函数 uchar gkey,i;bmp(0,0,8,2,132); while(menu_state)for(i=0;i4;i+) write_word(Music_Mry,i,4+(i+2)*16,0,16,16); while(!music_state) if(CheckState() if(music_state=0) ChangeKey(GetKeys(); bmp(0,2,8,2,132); InitialSound();Play_Two(Music_Memory,Signature,Octa);bmp(0,2,8,2,132); for(i=0;i4;i+) write_word(restar,i+5,4+(i+2)*16,2,16,16); for(i=0;i5;i+) write_word(restar,i,4+(i+2)*16,4,16,16); while(!CheckState(); gkey=GetKeys();delay(500);if(gkey=0x11) /确认键返回,F键 menu_state=0; delay(1000); bmp(0,0,8,2,132); /*/*菜单函数*/void m

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论