版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
课程设计说明书题目: 基于单片机的电子琴设计院(系):电子工程与自动化学院专业:测控技术与仪器(卓越)2013年9月21日目录1摘要……………………12关键字…………………13设计任务及要求………14方案可行性论证………15程序框图………………26关键单元电路与程序介绍……………36.1复位与震荡电路………………36.24x4矩阵键盘…………………36.3数码管与LED灯………………46.4蜂鸣器…………66.5音乐相关知识…………………77调试过程………………118总结与体会……………119参考文献………………1110附录……………………1210.1设备与仪器……………………1210.2软件……………1210.3原件清单………1210.4原理图与PCB图………………1310.5总程序……………1410.6实物图……………31【摘要】:打造一个多功能电子琴,核心是一块单片机。单片机读取键值,为内置定时器赋初值,定时器每溢出一次,驱动蜂鸣器的引脚电平就取反一次,产生相应频率的方波,即音调;设好键值与数码管段码表的对应关系,键按下时,数码管显示对应音调。一首音乐储存在一个表中,表中的数据是音调与节拍,单片机读取音符的音调与节拍,根据音调赋予定时器初值,根据节拍决定定时器工作的时间,也就是蜂鸣器响的时间,一个接一个地读取音符,即可播放一首歌曲。节拍用led灯的点亮个数表示。单片机读取音乐表中的节拍,控制led灯的点亮个数,达到显示节拍的效果。特别要注意的是:该方案采用了两个定时器,T0、T1。T0作为驱动蜂鸣器的定时器,要给予高优先级,不然会被T1干扰,音质变差。【关键字】:单片机、stc89c52、电子琴、C51、keil。【设计任务及要求】:1.通过按键能够发出相应的音符并播放产生乐音,实现演奏;2.演奏的同时可数字显示当前的音调,利于培养乐感3.可以选定播放固定乐曲自动演奏,演奏时LED进行节拍指示;4.在自动演奏和奏乐的过程中按停止键则中断演奏;5.可以选择调节音或小。【方案可行性论证】:本课题采用stc89c52单片机作为核心器件,实现基本的音乐弹奏、音乐播放、音调显示和音乐节拍指示的功能。音乐弹奏:通过程序识别4x4矩阵键盘中按下的键的坐标(x,y),
然后根据(x,y)从计数初值表中读取对应的计数初值,赋值给定时器0,定时器产生对应频率的方波,达到播放对应音调的功能。音乐播放:先建立一个包含一首音乐的音调与节拍的表。其中,音调就是0x01(低音、do)、0x12(中音、re)、0x23(高音、mi)之类的数;节拍就是0x02(半拍),0x04(一拍)之类的数。然后,根据音调读取计数初值,再将计数初值赋给定时器T0->开启定时器T0->读取节拍并延时->关闭定时器T0。这样就发出了一个音,然后再读下一个音的初值与节拍,重复上一个操作即可。(具体实现方法见附录总程序)数码管显示音调:
①按键:读出按键坐标(x,y),用if语句来判断(x,y)该给数码管赋什么值,然后从ucharcodenum[]表中读取这个值赋给数码管(例如P0)。②播放歌曲时:读入音调,根据音调的值来判断num[i]这个表中的i,再把num[i]赋给P0口。4.led灯的节拍指示:采用定时器1来控制,作为节拍指示。①按键时:根据按下的时长来控制led的点亮个数,并且是按一定的时间间隔逐个点亮;释放按键时,led灯按一定的时间间隔逐个熄灭,从而达到一种比较简单的节拍指示效果。②播放音乐时:根据音符的节拍,控制点亮到哪一个灯,在点亮那个灯之前,前面的灯逐个等时距点亮。音符结束后,led灯全部一起熄灭。这样,达到了一个精确显示节拍的效果。开始开始【程序框图】:扫描键盘扫描键盘根据音调给T0赋初值开启T0T1是否停止播放读下一个音符关闭T0T1数码管与led数码管显示音调Led指示节拍否按节拍延迟算出音符的音调、节拍是否结束符关闭定时器P0口置0否否是按键是否释放开启定时器,并赋初值,蜂鸣器发声算出定时器初值数码管显示音调识别按键有矩阵键按下否否播放键按下读取歌曲是根据音调给T0赋初值开启T0T1是否停止播放读下一个音符关闭T0T1数码管与led数码管显示音调Led指示节拍否按节拍延迟算出音符的音调、节拍是否结束符关闭定时器P0口置0否否是按键是否释放开启定时器,并赋初值,蜂鸣器发声算出定时器初值数码管显示音调识别按键有矩阵键按下否否播放键按下读取歌曲是是是 是是【复位与震荡电路】:原件的参数如图所示。C1,C2可采用30pF无极性陶瓷电容;C3可采用10µF记性电解质电容。值得注意的是,晶振不能随便摸!尤其在通电工作的时候,触摸容易损坏。自从摸过一次后,震荡频率变得不稳定,蜂鸣器声音时好时坏。【4x4矩阵键盘】:键盘扫描的基本思路是:先得出触发按键的“行”,即横坐标x,再得出他的“列”,即纵坐标y。以下是获取横坐标x的代码:ucharkey_x()/*P1口高位接纵坐标(P1.7-P1.4)低位接横坐标(P1.3-P1.0)*/{ uchari; P1=0x0f; /*有按键按下后对应按键的横坐标电位被拉低(注意低电位引脚不能被高电位引脚抬高,只能是低电位拉低高电位)*/ if(P1_0==0) { delayms(5);//延时5ms去抖动 if(P1_0==0) i=1; } elseif(P1_1==0) { delayms(5); if(P1_1==0) i=2; } elseif(P1_2==0) { delayms(5); if(P1_2==0) i=3; } elseif(P1_3==0) { delayms(5); if(P1_3==0) i=4; } else i=0; return(i); //0表示按键未按下}获取y的方法与获取x的方法类似,具体可以参考附件总程序。得到触发按键的坐标(x,y)之后,可以通过x,y的值来确定按键的功能。例如x==1,y==1时(S1按下),可以让数码管显示1: if(x==1&&y==1) P0=led_table[1];或者更方便一点:if(x==1) P0=led_table[y];就能显示第一行的所有的数了。【数码管与LED灯】: 数码管: 在本课题中,数码管要显示A-G,1-7,1.-7.,所以段码比较另类。num[0]的值是没用到的,起占位作用。ucharcodenum[]={0x00, //共阴极数码管段选码0x77,0x7c,0x39,0x5e,0x79,0x71,0x3d, //a-g0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, //1-70x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87 //1.-7.};编写程序时,要根据实际情况来编写:比如16个按键不能够把低中高音都全部表示完全,只能选取合适的部分。我让第一行的按键触发低音4-7,第二行触发中音1-4,第三行触发中音5-7和高音1,第四行触发高音2-5。这样设置能弹奏大部分曲目。以下是控制数码管的代码片段: if(x==1) P0=num[3+y]; //低音4-7 elseif(x==2) P0=num[7+y]; //中音1-4 elseif(x==3) P0=num[11+y]; //中音5-7和高音1 elseif(x==4) P0=num[15+y]; //高音2-5LED灯: 因为LED灯要按一定的时间逐个点亮或者逐个熄灭,所以我用定时器1来控制它。定时器1每溢出一次并满足一定条件时flash变量就+1或者-1,然后从led_table[]这个表中读出相应的数赋给P2口。表:ucharcodeled_table[]={0xff,0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01,0x00};/*发光二极管闪烁表*/代码:if(x!=0&&y!=0&&flash<8) //最大加到8 ++flash; elseif(x==0&&y==0&&flash>0)//最小减到0 --flash; P2=led_table[flash];播放音乐时又有所不同: 播放音乐时,led灯要精确地显示当前音符的节拍,所以if语句里加了一条限制语句:flash<jiepai)代码:if(out==1&&flash<8&&flash<jiepai) /*out==1表示有歌曲发声时,(flash<jiepai)使led灯刚好指示节拍*/ ++flash; elseif(out==0&&flash>0) --flash; P2=led_table[flash]; 这样做,就能看得出音符的节拍了。只是,由于led灯的个数有限,所以大于二分音符(2拍)的节拍就无法看到了。因为8个灯全亮才表示二分音符。如果当初采用16个灯的话,就没有这个窘境了。【蜂鸣器】:蜂鸣器采用一个s8550NPN三极管驱动,一个可变电阻改变音量。三极管的选用要注意放大倍数,放大倍数太小会导致蜂鸣器声音很小。最初采用8050就造成了这个问题。 另外,采用P3.0口连接接蜂鸣器是一个错误。因为P3.0、P3.1是烧写程序用到的接口。倘若连接了其他器件,每次调试都要拔下烧写线,很不方便。【音乐相关知识】:【表6.5.1】音符频率对照表音符频率(HZ)简谱码(T值)音符频率(HZ)简谱码(T值)低1DO262636280xf88c#4FA#74064860#1DO#27763731中5SO784648980xfd82低2RE294638350xf95b#5SO#83164934#2RE#31163928中6LA880649680xfdc8低3M330640210xfa15#693264994低4FA349641030xfa67中7SI988650300xfe06#4FA#37064185高1DO1046650580xfe22低5SO392642600xfb04#1DO#110965085#5SO#41564331高2RE1175651100xfe56低6LA440644000xfb90#2RE#124565134#646664463高3M1318651570xfe85低7SI494645240xfc0c高4FA1397651780xfe9a中1DO523645800xfc44#4FA#148065198#1DO#55464633高5SO1568652170xfec1中2RE587646840xfcac#5SO#166165235#2RE#62264732高6LA1760652520xfee4中3M659647770xfd09#6186565268中4FA698648200xfd34高7SI1967652830xff03音调、节拍以及编码的确定方法:一般说来,单片机演奏音乐基本都是单音频率,它不包含相应幅度的谐波频率,也就是说不能像电子琴那样能奏出多种音色的声音。因此单片机奏乐只需弄清楚两个概念即可,也就是“音调”和节拍。其中节拍表示一个音符唱多长的时间。音调的确定:不同音高的乐音是用C、D、E、F、G、A、B来表示,这7个字母就是音乐的音名,它们一般依次唱成DO、RE、MI、FA、SO、LA、SI,即唱成简谱的1、2、3、4、5、6、7,相当于汉字“多来米发梭拉西”的读音,这是唱曲时乐音的发音,所以叫“音调”,即Tone。把C、D、E、F、G、A、B这一组音的距离分成12个等份,每一个等份叫一个“半音”。两个音之间的距离有两个“半音”,就叫“全音”。在钢琴等键盘乐器上,C–D、D–E、F–G、G–A、A–B两音之间隔着一个黑键,他们之间的距离就是全音;E–F、B–C两音之间没有黑键相隔,它们之间的距离就是半音。通常唱成1、2、3、4、5、6、7的音叫自然音,那些在它们的左上角加上﹟号或者b号的叫变化音。﹟叫升记号,表示把音在原来的基础上升高半音,b叫降记音,表示在原来的基础上降低半音。例如高音DO的频率(1046Hz)刚好是中音DO的频率(523Hz)的一倍,中音DO的频率(523Hz)刚好是低音DO频率(266Hz)的一倍;同样的,高音RE的频率(1175Hz)刚好是中音RE的频率(587Hz)的一倍,中音RE的频率(587Hz)刚好是低音RE频率(294Hz)的一倍。 1)要产生音频脉冲,只要算出某一音频的周期(1/频率),然后将此周期除以2,即为半周期的时间。利用定时器计时这半个周期时间,每当计时到后就将输出脉冲的I/O反相,然后重复计时此半周期时间再对I/O反相,就可在I/O脚上得到此频率的脉冲。 2)利用stc89c52的内部定时器使其工作在计数器模式MODE1下,改变计数值TH0及TL0以产生不同频率的方法。 此外结束符和休止符可以分别用代码00H和FFH来表示,若查表结果为00H,则表示曲子终了;若查表结果为FFH,则产生相应的停顿效果。 3)例如频率为523Hz,其周期T=1/523=1912us,因此只要令计数器计时956us/1us=956,在每次计数956次时将I/O反相,就可得到中音DO(523Hz)。 计数脉冲值与频率的关系公式如下: N=Fi2Fr N:计算值; Fi:内部计时一次为1us,故其频率为1MHz;其计数值的求法如下:T=65536-N=65536-Fi2Fr例如:设K=65536,F=1000000=Fi=1MHz,求低音DO(261Hz)。中音DO(523Hz)。高音的DO(1046Hz)的计算值T=65536-N=65536-Fi2Fr=65536-10000002Fr=65536-500000/Fr低音DO的T=65536-500000/262=63627中音DO的T=65536-500000/523=64580高音DO的T=65536-500000/1047=65059C调各音符频率与计数值T的对照表如表所示。低音频率T参数中音频率T参数高音频率T参数Do2621908229Do523956115Do10465757Do﹟2771805217Do﹟554903108Do﹟11095454Re2941701204Re587852102Re11755151Re﹟3111608193Re﹟62280497Re﹟12454848Mi3301515182Mi65975991Mi13184545Fa3491433172Fa69871686Fa13974343Fa﹟3701351162Fa﹟74067681Fa﹟14804141So3921276153So78463877So15683838So﹟4151205145So﹟83160272So﹟16613636La4401136136La88056868La17603434La﹟4641078129La﹟93253664La﹟18653232Si4941012121Si98850661Si19763030表表6.5.2C调各音符频率与计数值T的对照表节拍的确定:若要构成音乐,光有音调是不够的,还需要节拍,让音乐具有旋律(固定的律动),而且可以调节各个音的快满度。“节拍”,即Beat,简单说就是打拍子,就像我们听音乐不自主的随之拍手或跺脚。若1拍实0.5s,则1/4拍为0.125s。至于1拍多少s,并没有严格规定,就像人的心跳一样,大部分人的心跳是每分钟72下,有些人快一点,有些人慢一点,只要听的悦耳就好。音持续时间的长短即时值,一般用拍数表示。休止符表示暂停发音。一首音乐是由许多不同的音符组成的,而每个音符对应着不同频率,这样就可以利用不同的频率的组合,加以与拍数对应的延时,构成音乐。了解音乐的一些基础知识,我们可知产生不同频率的音频脉冲即能产生音乐。对于单片机来说,产生不同频率的脉冲是非常方便的,利用单片机的定时/计数器来产生这样的方波频率信号。因此,需要弄清楚音乐中的音符和对应的频率,以及单片机定时计数的关系。音乐的编码:每个音符采用2个字节。第一个字节表示音调,第二个字节表示节拍。音调字节中,高四位表示低中高音,0表示低音,1表示中音,2表示高音;低四位表示“音调”。比如:0x11表示中音do。节拍字节中,数值i表示代表着延迟i个十六分音符。比如:0x04,表示延时4个16分音符,即延时1个四分之一音符。在以四分音符为一拍的歌曲中,0x04就代表一拍。底下没有横线,右侧也没有横线的数字(音调),就用0x04表示他的延时。底下有一横线:0x02;右侧有一横:0x08;右侧两横:0x0c;右侧三横:0x10;右下角有一点:加上当前延时的一半。由于不同的歌曲有不同的播放速度,即曲速(单位——拍每分钟)。所以音乐编码表中的第0和第1元素用来表示曲速。我们可以找到任意歌曲的简谱图,然后根据上述规则编写出单片机识别的简谱表。例如:可以翻译成:ucharcodeymt[]={//玉满堂0x96,0x00,//曲速0x96表示150拍/分0x00,0x0a,0x05,0x02,0x15,0x02,0x12,0x02,0x13,0x04,0x13,0x02,0x15,0x02,0x12,0x04,0x12,0x02,0x13,0x02,0x12,0x10,0x13,0x04,0x13,0x02,0x12,0x02,0x13,0x04,0x15,0x02,0x16,0x02,0x15,0x0c,0x13,0x02,0x15,0x02,0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x15,0x02,0x13,0x02,0x15,0x0c,0x15,0x02,0x16,0x02,0x21,0x04,0x21,0x02,0x22,0x02,0x23,0x04,0x22,0x02,0x21,0x02,0x22,0x10,0x23,0x08,0x15,0x02,0x16,0x02,0x21,0x02,0x22,0x02,0x23,0x04,0x23,0x02,0x22,0x02,0x21,0x06,0x21,0x02,0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x13,0x04,0x15,0x10,0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x21,0x02,0x22,0x02,0x23,0x04,0x23,0x02,0x22,0x02,0x21,0x06,0x21,0x02,0x16,0x02,0x21,0x02,0x16,0x02,0x21,0x02,0x22,0x02,0x23,0x02,0x25,0x02,0x23,0x02,0x22,0x0c,0x21,0x02,0x22,0x02,0x23,0x06,0x15,0x02,0x16,0x02,0x21,0x02,0x22,0x02,0x23,0x04,0x23,0x02,0x22,0x02,0x21,0x06,0x21,0x02,0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x02,0x21,0x02,0x15,0x02,0x13,0x02,0x15,0x0c,0x13,0x02,0x15,0x02,0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x16,0x02,0x21,0x02,0x22,0x04,0x22,0x02,0x23,0x02,0x22,0x04,0x22,0x02,0x23,0x02,0x25,0x02,0x26,0x02,0x23,0x02,0x25,0x02,0x22,0x02,0x23,0x02,0x21,0x02,0x16,0x02,0x21,0x10,0xff};【调试过程】: 编写程序阶段,一个功能、一个模块地编写。先写好键盘扫描程序,然后再到数码管显示、蜂鸣器发声、led节拍指示。分部进行,个个击破。【总结体会】:本课题让我更深刻地认识到了单片机这种器件,特别是对单片机里面的定时器收获最多。而且这是我第一次焊双面板,意义不同凡响。有了这次经验,对以后做板子定有深远的影响。制作过程中,感触最深的是解决杂音问题。在弹奏与播放时,蜂鸣器声音不纯,有颤音,影响音乐美感。为此,我煞费苦心,花了很多时间找原因。想到了精简定时器中断程序里的代码和运算,但效果甚微。直到最后,忽然想到了定时器有优先级的说法。试了一下,将控制蜂鸣器的定时器T0设为高优先级。终于问题解决了!而且是如此的简单,但是过程却是又如此的艰辛,让人感觉不太值得。。不过,终归是值得的!【参考文献】:《单片微机原理、汇编与C51及接口技术》(朱定华戴颖颖李川香著)序号名称数量备注1四脚开关186x6mm212Mhz晶振1330pF陶瓷电容2410µF无极性电容1510K2.2K电阻910Kx9;2.2Kx16240电阻107NPN三极管1s85508七段共阴极数码管29无源蜂鸣器110电位器111发光二极管10红色x8黄x1绿x112排针3排13双面覆铜铜板115x10cm1440P杜邦线115单片机底座216电源开关117Stc89c52单片机1【附录】:设备与仪器:电脑、单片机开发板(或者单片机烧写器)软件:KeiluVision4、DXP09原件清单:原理图与PCB图:总程序:#include<reg52.h>#include<intrins.h>#defineucharunsignedchar#defineuintunsignedint#defineallsong4//歌曲总数按实际写sbitP1_0=P1^0;sbitP1_1=P1^1;sbitP1_2=P1^2;sbitP1_3=P1^3;sbitP1_4=P1^4;sbitP1_5=P1^5;sbitP1_6=P1^6;sbitP1_7=P1^7;sbitbeep=P3^0;sbitkey_play=P3^1;ucharx=0; /*矩阵键盘横坐标从1开始0为未按下的标志*/uchary=0; /*矩阵键盘纵坐标从1开始0为未按下的标志*/ucharflash=0; //控制led灯显示 的变量*/ucharf_l; /*按键发出音调的初值(低位)*/ucharf_h; //高位ucharsong_l; /*歌曲音调的初值(低位)*/ucharsong_h; //高位 ucharout=0; /*声音输出变量1表示有输出0表示无输出*/ucharyindiao; /*音调 定义为全局变量为了在播放时数码管能显示当前音调*/ucharyindiao_h; //音调的高四位ucharyindiao_l; //音调的低四位ucharjiepai; /*节拍(简而言之就是一个音调响的时间长度)*/ucharsong_id=1; //歌曲序号变量uchartemp_id=1; //歌曲临时序号uintwhich=2; /*简谱表里的第几个音从第2个开始第0个用来存曲速,第1个占位*/ucharsame=0; /*在暂停时选了同一首歌曲,用于跳出暂停循环*/ucharkey_x(); //获取键盘横坐标函数ucharkey_y(); //获取键盘纵坐标函数voidplay(); //播放歌曲函数voiddelayms(uintms);//延时xxms函数voiddelay(uintpai);//节拍延时函数voidkey_check(); //检查按键状态函数voiddisplay(); //数码管显示对应音调函数voidspeak(); /*按键后给定时器0赋对应音调的初值从而发出声音*/ucharchoose(); /*播放状态下选歌函数释放按键后才跳出函数,返回歌曲序号*/ucharchoose2(); /*暂停状态下选歌函数不用释放按键即可跳出函数,返回歌曲序号*/voidplay(); //播放歌曲函数ucharcodenum[]={0x00, //数码管段选码0x77,0x7c,0x39,0x5e,0x79,0x71,0x3d, //a-g0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, //1-70x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87 //1.-7.};ucharcodeled_table[]={0xff,0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01,0x00};/*发光二极管闪烁表*/ucharcodechuzhi[]={//音调对应的计数初值 0xff,0xff,//占0位 0xf8,0x8c,//低1(0x01) a-数码管显示方式 0xf9,0x5b,//2 b 0xfa,0x15,//3 c 0xfa,0x67,//4 d 0xfb,0x04,//5 e 0xfb,0x90,//6 f 0xfc,0x0c,//低7(0x07)g 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,/*占位0x08-0x0b(8-11)*/ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,/*占位0x0c-0x10 (12-16)*/ 0xfc,0x44,//中1(0x11)(17) 0xfc,0xac,//2 0xfd,0x09,//3 0xfd,0x34,//4 0xfd,0x82,//5 0xfd,0xc8,//6 0xfe,0x06,//中7(0x17)(23) 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,/*占位0x18-0x1b(24-27)*/ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,/*占位0x1c-0x20 (28-32)*/ 0xfe,0x22,//高1(0x21)1. (33) 0xfe,0x56,// 2 2. 0xfe,0x85,// 3 3. 0xfe,0x9a,// 4 4. 0xfe,0xc1,// 5 5. 0xfe,0xe4,// 6 6. 0xff,0x03//高7(0x27)7. (39) }; ucharcodeymt[]={//玉满堂0x96,0x00,//曲速0x96表示150拍/分0x00,0x0a,0x05,0x02,0x15,0x02,0x12,0x02,0x13,0x04,0x13,0x02,0x15,0x02,0x12,0x04,0x12,0x02,0x13,0x02,0x12,0x10,0x13,0x04,0x13,0x02,0x12,0x02,0x13,0x04,0x15,0x02,0x16,0x02,0x15,0x0c,0x13,0x02,0x15,0x02,0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x15,0x02,0x13,0x02,0x15,0x0c,0x15,0x02,0x16,0x02,0x21,0x04,0x21,0x02,0x22,0x02,0x23,0x04,0x22,0x02,0x21,0x02,0x22,0x10,0x23,0x08,0x15,0x02,0x16,0x02,0x21,0x02,0x22,0x02,0x23,0x04,0x23,0x02,0x22,0x02,0x21,0x06,0x21,0x02,0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x13,0x04,0x15,0x10,0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x21,0x02,0x22,0x02,0x23,0x04,0x23,0x02,0x22,0x02,0x21,0x06,0x21,0x02,0x16,0x02,0x21,0x02,0x16,0x02,0x21,0x02,0x22,0x02,0x23,0x02,0x25,0x02,0x23,0x02,0x22,0x0c,0x21,0x02,0x22,0x02,0x23,0x06,0x15,0x02,0x16,0x02,0x21,0x02,0x22,0x02,0x23,0x04,0x23,0x02,0x22,0x02,0x21,0x06,0x21,0x02,0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x02,0x21,0x02,0x15,0x02,0x13,0x02,0x15,0x0c,0x13,0x02,0x15,0x02,0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x16,0x02,0x21,0x02,0x22,0x04,0x22,0x02,0x23,0x02,0x22,0x04,0x22,0x02,0x23,0x02,0x25,0x02,0x26,0x02,0x23,0x02,0x25,0x02,0x22,0x02,0x23,0x02,0x21,0x02,0x16,0x02,0x21,0x10,0xff};ucharcodedl[]={//蝶恋0x8c,0x00,//曲速0x8c表示140拍/分0x13,0x04,0x13,0x04,0x13,0x04,0x12,0x04,0x13,0x08,0x12,0x04,0x13,0x04,0x12,0x04,0x12,0x04,0x06,0x08,0x06,0x04,0x07,0x04,0x11,0x08,0x12,0x04,0x11,0x04,0x07,0x08,0x06,0x04,0x05,0x04,0x06,0x10,0x13,0x04,0x13,0x04,0x13,0x04,0x12,0x04,0x13,0x0c,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x15,0x04,0x12,0x04,0x12,0x04,0x13,0x04,0x14,0x08,0x15,0x04,0x14,0x04,0x13,0x04,0x12,0x04,0x11,0x04,0x13,0x0f,0x13,0x0c,0x13,0x04,0x16,0x08,0x17,0x04,0x16,0x04,0x15,0x0c,0x13,0x04,0x15,0x0f,0x13,0x04,0x15,0x04,0x12,0x08,0x16,0x04,0x15,0x04,0x13,0x08,0x12,0x04,0x12,0x04,0x13,0x0c,0x12,0x08,0x16,0x04,0x16,0x0c,0x11,0x08,0x16,0x04,0x16,0x08,0x16,0x04,0x17,0x04,0x21,0x08,0x17,0x04,0x16,0x04,0x17,0x08,0x16,0x04,0x17,0x04,0x13,0x08,0x13,0x0c,0x13,0x04,0x16,0x08,0x17,0x08,0x16,0x04,0x15,0x0c,0x13,0x04,0x15,0x10,0x14,0x04,0x15,0x04,0x16,0x08,0x17,0x04,0x16,0x04,0x17,0x08,0x16,0x04,0x17,0x04,0x13,0x10,0x13,0x10,0x12,0x08,0x16,0x04,0x16,0x02,0x16,0x10,0x11,0x04,0x16,0x04,0x16,0x02,0x16,0x08,0x16,0x04,0x17,0x04,0x21,0x08,0x17,0x04,0x16,0x04,0x17,0x08,0x15,0x08,0x16,0x10,0x23,0x04,0x22,0x04,0x22,0x04,0x21,0x04,0x21,0x04,0x17,0x04,0x17,0x04,0x16,0x04,0x21,0x04,0x17,0x04,0x17,0x04,0x16,0x04,0x16,0x04,0x15,0x04,0x15,0x04,0x14,0x04,0x16,0x04,0x15,0x04,0x15,0x04,0x14,0x04,0x14,0x04,0x13,0x04,0x13,0x04,0x12,0x04,0x13,0x10,0x13,0x10,0xff};ucharcodesrkl[]={//生日快乐0x78,0x00,//曲速1200x15,0x02,0x15,0x02,0x16,0x04,0x15,0x04,0x21,0x04,0x17,0x04,0x00,0x04,0x15,0x02,0x15,0x02,0x16,0x04,0x15,0x04,0x22,0x04,0x21,0x08,0x15,0x02,0x15,0x02,0x25,0x04,0x23,0x04,0x21,0x04,0x17,0x04,0x16,0x08,0x16,0x04,0x00,0x04,0x24,0x02,0x24,0x02,0x23,0x04,0x21,0x04,0x22,0x04,0x21,0x08,0x21,0x08,0x00,0x08,0x15,0x02,0x15,0x02,//第二遍0x16,0x04,0x15,0x04,0x21,0x04,0x17,0x04,0x00,0x04,0x15,0x02,0x15,0x02,0x16,0x04,0x15,0x04,0x22,0x04,0x21,0x08,0x15,0x02,0x15,0x02,0x25,0x04,0x23,0x04,0x21,0x04,0x17,0x04,0x16,0x08,0x16,0x04,0x00,0x04,0x24,0x02,0x24,0x02,0x23,0x04,0x21,0x04,0x22,0x04,0x21,0x08,0x21,0x08,0x00,0x04,0xff};ucharcodetest[]={//测试0x78,0x00,//曲速0x78表示120拍/分 0x01,0x04,0x02,0x04,0x03,0x04,0x04,0x04,0x05,0x04,0x06,0x04,0x07,0x04,0x00,0x04,0x11,0x08,0x12,0x07,0x13,0x06,0x14,0x05,0x15,0x04,0x16,0x03,0x17,0x02,0x00,0x01,0x21,0x01,0x22,0x02,0x23,0x03,0x24,0x04,0x25,0x05,0x26,0x06,0x27,0x07,0x00,0x08,0xff,};voiddelayms(uintms) /*ms等于1时,延时1ms等于2时,延时2ms,以此类推*/{ uchara,b,c; //+3 while(ms--){ for(c=1;c>0;c--) // 1+2=3for(b=142;b>0;b--) // 1*(1+142*2))=285 for(a=2;a>0;a--); // 142*(1+2*2)=710 }}voiddelay(uintpai) /*pai是节拍pai若定义成uchar类型,当节拍>0x0c时,会造成数据溢出,产生失真。*/{ uchara,b,c; while(pai--) //延迟pai个6.25ms { for(c=1;c>0;c--) // 1+2=3 for(b=28;b>0;b--) // 1*(1+28*2)=57 for(a=110;a>0;a--); // 28*(1+110*2)=6188 } }ucharkey_x()/*P1口高位接纵坐标(P1.7-P1.4)低位接横坐标(P1.3-P1.0)*/{ uchari; P1=0x0f; /*有按键按下后对应按键的横坐标电位被拉低(注意低电位引脚不能被高电位引脚抬高,只能是低电位拉低高电位)*/ if(P1_0==0) { delayms(5);//延时5ms去抖动 if(P1_0==0) i=1; } elseif(P1_1==0) { delayms(5); if(P1_1==0) i=2; } elseif(P1_2==0) { delayms(5); if(P1_2==0) i=3; } elseif(P1_3==0) { delayms(5); if(P1_3==0) i=4; } else i=0; return(i); //0表示按键未按下}ucharkey_y(){ ucharj; P1=0xf0; if(P1_4==0) { delayms(5); if(P1_4==0) j=1; } elseif(P1_5==0) { delayms(5); if(P1_5==0) j=2; } elseif(P1_6==0) { delayms(5); if(P1_6==0) j=3; } elseif(P1_7==0) { delayms(5); if(P1_7==0) j=4; } else j=0; return(j);}voidkey_check()/*检查矩阵按键坐标、播放键的状态及播放键状态设置*/{ x=key_x(); y=key_y(); if(key_play==0) key_play=0;/*保持播放键引脚低电平,让其作为歌曲正在播放的标志*/ else key_play=1;/*保持播放键引脚高电平,让其作为歌曲未播放的标志*/ }voiddisplay() /*数码管显示相应的音调*/{ if(key_play==1)//按键弹奏时 { if(x!=0&&y!=0) { if(x==1) P0=num[3+y]; //低音4-7 elseif(x==2) P0=num[7+y]; //中音1-4 elseif(x==3) P0=num[11+y]; //中音5-7和高音1 elseif(x==4) P0=num[15+y]; //高音2-5 } else P0=0x00; } else//播放音乐时 { if(yindiao_h==0) /*yindiao变量的高四位表示低(0)中(1)高(2)音 */ P0=num[yindiao_l];/*yindiao变量的低四位表示“调”,数码管显示当前音调*/ elseif(yindiao_h==1) // 中音 P0=num[yindiao_l+7]; elseif(yindiao_h==2)//高音 P0=num[yindiao_l+14]; }}voidspeak() /*按键,为定时器0T0赋计数初值,让T0函数驱动蜂鸣器发出对应的音调*/{ if(x==1) { f_h=chuzhi[2*y+6]; //低音4-7 f_l=chuzhi[2*y+6+1]; } elseif(x==2) { f_h=chuzhi[(16+y)*2]; //中音1-4 f_l=chuzhi[(16+y)*2+1]; } elseif(x==3) { if(y<=3) { f_h=chuzhi[(20+y)*2]; //中音5-7 f_l=chuzhi[(20+y)*2+1]; } else { f_h=chuzhi[66]; //高音1 f_l=chuzhi[67]; } } elseif(x==4) { f_h=chuzhi[(33+y)*2]; //高音2-5 f_l=chuzhi[(33+y)*2+1]; } }voidtimer0()interrupt1//定时器0{ if(key_play==0) { TL0=song_l; TH0=song_h; beep=~beep; } else if(x!=0&&y!=0&&key_play==1)/*当有矩阵按键按下,并且不播放歌曲时*/ { TL0=f_l; //赋初值 TH0=f_h; // beep=~beep;/*蜂鸣器引脚电平取反,定时器每溢出一次电平取反一次,不同的计数初值对应不同的溢出时间,对应不同的方波频率*/ } }voidtimer1()interrupt3//定时器1 led灯起落{ TL1=0x00; TH1=0x54;/*定时器1高8位初值。控制led灯的起落快慢(数值不严格)*/ if(key_play==1)//不播放歌曲时 { if(x!=0&&y!=0&&flash<8) //最大加到8 ++flash; elseif(x==0&&y==0&&flash>0)//最小减到0 --flash; P2=led_table[flash]; } elseif(key_play==0) //播放歌曲时 { if(out==1&&flash<8&&flash<jiepai) /*out==1表示有歌曲发声时,(flash<jiepai)使led灯刚好指示节拍*/ ++flash; elseif(out==0&&flash>0) --flash; P2=led_table[flash]; } }ucharchoose() //播放状态下选歌{ uchari=0;//第i首歌初值0表示未选歌 ucharj; x=key_x(); y=key_y(); if(x==1&&y==1) i=1; //选第一首 elseif(x==1&&y==2) i=2; //选第二首 elseif(x==1&&y==3) i=3; elseif(x==1&&y==4) i=4; elseif(x==2&&y==1) i=5; elseif(x==4&&y==1)//上一首 i=13; elseif(x==4&&y==2)//用作暂停播放 i=14; elseif(x==4&&y==3) //下一首 i=15; elseif(x==4&&y==4) i=16; //用作停止播放 if(i==song_id) { which=2;//选同一首歌时,重播这首歌 } elseif(i>allsong&&i<13) /*如果按键号在最大歌曲序号和功能键之间,返回原歌曲序号*/ i=song_id; // elseif(i==0) //i等于初值说明未按键 i=song_id; //不按键选歌时,返回原歌曲的序号 while(1) //释放按键时才进行下一步 { x=key_x(); y=key_y(); if(x==1) j=y; elseif(x==2) j=4+y; elseif(x==3) j=8+y; elseif(x==4) j=12+y; if(x==0||(j>allsong&&j<13))/*释放按键或者按键号在最大歌曲序号和功能键之间时跳出循环*/ break; } return(i);}ucharchoose2() /*选歌 不用放开按键在暂停的状态下使用*/{ uchari=0; x=key_x(); y=key_y(); if(x==1&&y==1) //选第一首 i=1; elseif(x==1&&y==2) //选第二首 i=2; elseif(x==1&&y==3) i=3; elseif(x==1&&y==4) i=4; elseif(x==2&&y==1) i=5; elseif(x==4&&y==1) //上一首 i=13; elseif(x==4&&y==2) //用作暂停播放 i=14; elseif(x==4&&y==3) //下一首 i=15; elseif(x==4&&y==4) i=16; //用作停止播放 if(i==song_id) { same=1; which=2;/*选了同一首歌时,重播这首歌 (0,1用来存曲速了故从2开始)*/ } elseif(i>allsong&&i<13) /*如果按键号在最大歌曲序号和功能键之间,返回原歌曲序号*/ i=song_id; elseif(i==0) //i等于初值说明未按键 i=song_id;/*不按键选歌时,返回原歌曲的序号*/ return(i);}voidplay() //播放歌曲{ uintqusu;//歌曲播放速度(拍/分) uintpai2;/* pai2=(2400/qusu)*jiepai;送到delay()函数*/while(1){ while(1) { choose_id: temp_id=choose();//选歌/****************************↓↓↓↓↓暂停↓↓↓↓↓*****************************************/ if(temp_id==14) //如果按下暂停键 { delayms(500); //延时500ms while(1) { temp_id=choose2();/*choose2按下就起作用不必等到放开按键才起作用*/ if(temp_id==14)/*再次按下“暂停键”表示继续播放*/ { break; } elseif(temp_id==16)/*按下停止键,功能表现为:暂停播放时也能停止播放,回到播放前状态*/ { song_id=16; break; } elseif(temp_id==13) //上一首 { which=2; if(song_id==1) song_id=allsong;//播放最后一首 else --song_id; break; } elseif(temp_id==15)//下一首 { which=2; if(song_id==allsong) song_id=1;//播放第一首 else ++song_id; break; } elseif(temp_id!=song_id&&temp_id<=allsong)/*选了另一首歌曲屏蔽掉了未定义的按键 */ { which=2; /*从歌曲的第一个音播放(0,1用来存曲速了故从2开始) */ song_id=temp_id; break; } elseif(same==1) break; } same=0;//跳出循环后需重置为0 } /****************************↑↑↑↑↑暂停↑↑↑↑↑***************************************/ elseif(temp_id==13) //上一首 { which=2; if(song_id==1) song_id=allsong;//播放最后一首 else --song_id; } elseif(temp_id==15)//下一首 { which=2; if(song_id==allsong) song_id=1;//播放第一首 else ++song_id; } elseif(temp_id==16) { song_id=16; } elseif(temp_id!=song_id&&temp_id<=allsong)//选了另一首歌曲 { which=2; //从歌曲的第一个音播放 song_id=temp_id; } /**************************************************************************************/ nochoose: //不用选歌当正常放完一首歌时,跳到这里 if(song_id==3) { key_play=0; if(srkl[which]==0xff)/*遇到结束符跳出循环(内循环)停止播放*/ break; qusu=srkl[0]; yindiao=srkl[which];//音调 jiepai=srkl[which+1];//节拍 } else if(song_id==1) { key_play=0; if(ymt[which]==0xff)/*遇到结束符跳出循环(内循环)停止播放*/ break; qusu=ymt[0]; yindiao=ymt[which];//音调 jiepai=ymt[which+1];//节拍 } else if(song_id==2) { key_play=0; if(dl[which]==0xff)/*遇到结束符跳出循环停止播放*/ break; qusu=dl[0]; yindiao=dl[which];// jiepai=dl[which+1];// } elseif(song_id==4) { key_play=0; if(test[which]==0xff)/*遇到结束符跳出循环停止播放*/ break; qusu=test[0]; yindiao=test[which]; jiepai=test[which+1]; }/******************************************************************************/ elseif(song_id==16) { which=2; break; } else { key_play=1; gotochoose_id; /*如果既没有选歌又没有停止返回去做选择*/ }/********************************************************************************************/ yindiao_l=yindiao%16; //低四位调 yindiao_h=yindiao/16; /* 高四位。。是低音0中音1还是高音2 */ if(yindiao!=0)/*音调不为0。(当音调为0时表示这个音不响但依旧要占这个音的播放时间)*/ { song_h=chuzhi[yindiao*2]; song_l=chuzhi[yindiao*2+1]; TR0=1;/*给初值赋值后,开启定时器0 蜂鸣器开始发声*/ TR1=1; /*开启定时器1,led开始闪动*/ display();//数码管显示音调 out=1;/*正在发声的标志,定时器1得以控制led灯按一定的时间间隔逐个点亮*/ } else { TR0=0; out=0; TR1=0; P0=0x00; flash=0; P2=led_table[0]; } pai2=(2400/qusu)*jiepai; delay(pai2); /*延时=节拍数x125ms(决定着1个音的发声时间)*/ TR0=0; //蜂鸣器停止发声 P0=0x00; out=0; delayms(39);/*唱完一个音停xxms(决定每个音调之间的时间间隔根据个人喜好节奏来定*/ TR1=0;//led停止闪动 flash=0; P2=led_table[0]; which=which+2; //下一个音 }/*已经放完一首歌,或者停止播放 ,接下来判断是停止播放还是播放下一首*/ TR0=0; P0=0x00; out=0; flash=0; P2=led_table[0]; if(song_id==16)/*坐标(4,4)的键盘作为停止播放键*/ { while(1) { x=key_x(); if(x==0) break;/*松开按键才结束避免触发其他程序比如电子琴发声、led显示等 */ } key_play=1;/*播放键引脚置高电平,播放结束的标志 */ song_id=1;//第一首歌开始 which=2; //每首歌的最开始的一个音 break;/*跳出第二个循环(即结束play函数)*/ } elseif(song_id==allsong)/*当放到最后一首时,从第一首开始(当前共3首)*/ { song_id=1; which=2; delayms(1000);//一秒后从第一首开始播放 gotonochoose; } else { ++song_id;/*歌曲序号自动+1自动播放下一首歌*/ which=2; delayms(1000); gotonochoose;//不用选歌播放下一首 }}}voidmain(){ P0=0x00; P2=0xff; TMOD=0x11;/*定时器0定时器1都采用方式1(16位定时器方式)*/ IE=0x8a; PT0=1;/*设置定时器0为高优先级,避免被定时器1干扰,造成声音失真 */while(1){ key_check(); if(key_play==1&&x!=0&&y!=0) { TR1=1; display(); speak(); TR0=1; } elseif(key_play==0) { key_play=0; play(); /*play函数有循环语句,当按下停止键(16键)时才能跳出*/ } else { if(flash==0)/*当flash减到0时再关闭定时器1,即让led灯全部熄灭再关闭T1*/ TR1=0; TR0=0; P0=0x00; } } }【实物图】:【原理图、PCB、程序下载地址】:/s/19oaXJ (百度网盘)【版权声明】:共享文档、可自由转载,但仅限于学习交流!最后建议同学们,课设最好认真做,不可完全照搬他人。基于C8051F单片机直流电动机反馈控制系统的设计与研究基于单片机的嵌入式Web服务器的研究MOTOROLA单片机MC68HC(8)05PV8/A内嵌EEPROM的工艺和制程方法及对良率的影响研究基于模糊控制的电阻钎焊单片机温度控制系统的研制基于MCS-51系列单片机的通用控制模块的研究基于单片机实现的供暖系统最佳启停自校正(STR)调节器单片机控制的二级倒立摆系统的研究基于增强型51系列单片机的TCP/IP协议栈的实现基于单片机的蓄电池自动监测系统基于32位嵌入式单片机系统的图像采集与处理技术的研究基于单片机的作物营养诊断专家系统的研究基于单片机的交流伺服电机运动控制系统研究与开发基于单片机的泵管内壁硬度测试仪的研制基于单片机的自动找平控制系统研究基于C8051F040单片机的嵌入式系统开发基于单片机的液压动力系统状态监测仪开发模糊Smith智能控制方法的研究及其单片机实现一种基于单片机的轴快流CO〈,2〉激光器的手持控制面板的研制基于双单片机冲床数控系统的研究基于CYGNAL单片机的在线间歇式浊度仪的研制HYPERLINK"/detail.ht
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 民宿运营与管理-课件-第五章-民宿岗位设置与人员管理
- 小学2024年秋季学生1530安全教育记录表(全学期)
- 《电梯媒体IOTMedia》课件
- 外科护理学肠梗阻
- 《头痛的病因与治疗》课件
- 两位数乘两位数笔算综合自测练习题大全附答案
- 压力性损伤各期治疗
- 《周年纪念礼品》课件
- 物联网发展历程智慧养老技术概论
- 这次公开竞聘很多人都托了关系听说你也走后门了从
- 华能(天津)煤气化发电限公司2024年应届毕业生招聘高频难、易错点500题模拟试题附带答案详解
- 当前宏观形势及市场趋势分析:经济、政策与市场
- 2024-2025学年九年级化学人教版上册检测试卷(1-4单元)
- 2024秋九年级化学上册 2.2《氧气》说课稿 (新版)新人教版
- 汽车检测技术 课程设计
- 七年级语文上册18-我的白鸽课件
- 2024中国电子科技集团限公司在招企业校招+社招高频难、易错点500题模拟试题附带答案详解
- 新能源汽车运输合作协议
- 副校长试用期转正工作总结(5篇)
- 2024年玻璃钢通信管道项目可行性研究报告
- 《旅游大数据》-课程教学大纲
评论
0/150
提交评论