以上压缩包所有文件下载:
基于单片机的简易电子琴设计.rar
(240 KB, 下载次数: 150)
目录:
一.简易电子琴组成框图及其工作原理 4
二.系统总体方案与硬件设计 5
2.1单片机最小系统 5
2.2直流电源设计 5
2.3按键设计 5
2.4 LED灯设计 6
2.5发声模块 6
2.6总电路图 7
三.系统软件的编写 7
3.1电子琴软件实现基本原理 7
3.2发音原理 9
3.3参数计算 9
3.4 计算结果 9
3.5主程序中涉及的函数讲解: 10
3.6播放歌曲模块 13
3.7录音模块 16
四. 总结 18
五. 参考文献 18
六.设计心得 18
一、设计的目的
在本次设计老师所给的项目中觉得电子琴不错,音乐能陶冶人的情操,同时使人快乐,影响人的心情,而学过的单片机技术使我们可以利用软硬件来实现电子琴的功能,从而可以实现电子琴的微型化,可以用作玩具琴、音乐转盘以及音乐童车等等。并且可以进行一定功能的拓展。鉴于传统电子琴可以用键盘上的“1”到“A”键演奏从So到Do11个音,从而也可以通过单片机实现对十个按键的扩展,实现七个音符的低,中,高21个音调的显示播放和音乐的自动播放。
二、设计的内容及要求
音乐由不同的音阶组成,而不同的音阶又是由不同的频率发出的,因此产生不同的频率,就可以发出不同的音阶。在本次设计中,最主要的工作是程序编写,通过按键的键值,将其转化为不同频率的方波送到对应的发声口,使喇叭发声,本次设计采用的电脑音响。同时加入LED灯来模拟音乐频谱显示。硬件主要由单片机最小系统,键盘模块,发声模块,电源模块,LED显示模块组成。
一.简易电子琴组成框图及其工作原理
2.2直流电源设计本次设计直接采用+5v直流电源。 2.3按键设计按键采用4*6扫描;4根行线接P10-P13,六根列线接P14-P17以及P20,P21口共24个按键,0-20代表音符键,0-6代表低音1,2,3,4,5,6,7;7-13代表中音1,2,3,4,5,6,7;14-20代表高音1,2,3,4,5,6,7;21号按键表示播放歌曲键,当按下21号键,进入播放歌曲函数,当按下22号键时,播放下一首歌曲,当按下23键时,退出播放返回主程序。而在主程序中时,代表演奏状态,当按下23号键时,进入录音状态,此时有个绿色的指示灯会亮。而进入录音后,再按一次23键,指示灯灭,退出录音状态,返回主程序。 图2.3 按键模块 2.4 LED灯设计七个红色的LED代表按键的音符DO,RE,MI,FA,SO,LA,SI分别接到P0口的各个输入端口,音符DO时,一个LED亮,音符RE时,2个LED亮,以此类推。同时为了区分高中低音,三个八度LED显示不同,当低音音符播放时,LED闪亮,当是中音时,LED也闪亮,但是闪亮的频率更快,当是高音时,LED全亮,这是通过调节LED亮灭时间来实现。绿色LED指示当前状态,当电子琴处于录音时,LED亮,结束录音时,LED灯灭。 图2.4 LED灯显示模块 2.5发声模块采用电脑音响。
图2.5 发声模块电路
三.系统软件的编写3.1电子琴软件实现基本原理电子琴的基本原理:本设计采用单片机实现控制,软件设计部份的程序编写用汇编混合C语言来完成。声音的频谱范围约在几十到几千赫兹,若能利用程序来控制单片机的某个口线不断输出“高”“低”电平,则在该口线上就能产生一定频率的方波,讲该方波接上喇叭就能发出一定频率的声音,若再利用程序控制“高”“低”电平的持续时间,就能改变输出波形的频率从而改变音调。乐曲中,每个音符对应着确定的频率,下表给出各音符频率。如果单片机某个口线输出“高”“低”电平的频率和某个音符的频率一样,那么将此口线接上喇叭就可以发出此音符的声音。根据这个原理就能设计出,对于单片机来说要产生一定频率的方波大致是先将某口线输出高电平然后延迟一段时间再输出低电平,如此循环的输出就会产生一定频率的方波,通过改变延迟的时间就可以改变输出方波的频率。单片机内部有两个定时计数器T1和T0,单片机的定时计数器实际上是个计数装置,它既可以对单片机内部晶振驱动时钟计数,也可以对外部输入的脉冲计数,对内部晶振计数时称为定时器,对外部时钟计数时称为计数器。当对单片机内部晶振驱动时钟计数时,每个机器周期定时计数器的计数值就加,当计数值达到计数最大值时计数完毕并通知单片机。 软件设计思想:采用模块化的分层次设计方法,将软件系统功能由多个实现单一功能的子程序实现。这样便于调试、修改。
3.2发音原理若要产生音频脉冲,只要算出某一音频的周期(1/频率),再将此周期除以2,即为半周期的时间。利用定时器计时半周期时间,每当计时终止后就将P1.0反相,然后重复计时再反相。就可在P1.0引脚上得到此频率的脉冲。利用AT89C51的内部定时器使其工作计数器模式(MODE1)下,改变计数值TH0及TL0以产生不同频率的方法产生不同音阶。 3.3参数计算例如,频率为523Hz,其周期T=1/523=1912μs,因此只要令计数器计时956μs/1μs=956,每计数956次时将I/O反相,就可得到中音DO(523Hz)。计数脉冲值与频率的关系式是:N=fi÷2÷fr,式中,N是计数值;fi是机器频率(晶体振荡器为12MHz时,其频率为1MHz);fr是想要产生的频率。其计数初值T的求法如下:T=65536-N=65536-fi÷2÷fr。 3.4 计算结果(1)单片机12MHZ晶振,低、中、高音符频率与计数值T的关系如表所示: 表3.2 频率与计数值关系表
采用查表程序进行查表时,可以为这个音符建立一个表格,有助于单片机通过查表的方式来获得相应的数据:低音0-19之间,中音在20-39之间,高音在40-59之间。用单片机播放音乐,或者弹奏电子琴,实际上是按照特定的频率,输出一连串的方波。为了输出合适的方波,首先应该知道音符与频率的关系。 (2)音调数据表 曲调值 | DELAY |
| 曲调值 | DELAY | 调4/4 | 125ms |
| 调4/4 | 62ms | 调3/4 | 187ms |
| 调3/4 | 94ms | 调2/4 | 250ms |
| 调2/4 | 125ms |
表3.3 音调数据表 上表中的频率数值,有些过多,去掉不常用的黑键频率,只是把白键对应的数据存放在单片机中,即可满足绝大部分的应用需求。
定义音调数据表的程序如下: DW63628,63835,64021,64103,64260,64400,64524 低音区:1 2 3 4 5 6 7
DW64580,64683,64777,64820,64898,64968,65030 中音区:1 2 3 4 56 7
DW65058,65110,65157,65178,65217,65252,65283 高音区:1 2 3 4 56 7 把这个数据表,放在程序中,需要播音的时候,就从表中取出一个数据送到定时器,当定时器溢出中断的时候,再对输出引脚取反,那么,在扬声器中,即可听到上表中频率的声音。
3.5主程序中涉及的函数讲解:void YinFu_DiZhongGao_Flag(uchar keyval) { if(keyval<7) flag_yinfu_dizhonggao=1; // 低音 else if(keyval<14) flag_yinfu_dizhonggao=2; //中音 else if(keyval<21) flag_yinfu_dizhonggao=3; //高音 } 此函数是根据按下键值来确定音符是高音、中音还是低音flag_yinfu_dizhonggao=1代表低音,flag_yinfu_dizhonggao=2代表中音,flag_yinfu_dizhonggao=3代表高音。 而LED显示函数(定时器1中断服务函数)会根据flag_yinfu_dizhonggao的值来显示。 void Timer_Init() {
TMOD=0x11; //定时器T0,T1设置为方式1, TH1=0xD8; //10ms中断一次 TL1=0xF0; TH0=th0; TL0=tl0; IE=0x82; //开启总中断和定时器T0,T1溢出中断 ET1=1; IP=0x02; //T0优先于T1 } 定时器0用来产生不同方波频率,使音响发声。 定时器1用来控制LED显示,当工作在演奏模式时,按下音符键时,判断音符键是高音还是中音或者低音,当是高音时,LED全亮,占空比为1;当是中音时,LED快速闪烁,占空比为1/2;当是低音时,LED相对较慢的闪烁,占空比为1/4。 中断服务程序: void play_Tone() interrupt 1 using 0//定时器T0溢出中断,产生不同频率的矩形波 { TH0=th0; TL0=tl0; Beep=~Beep; }
void play_LED() interrupt 3 using 2 { if(Recordonoff)//开启录音后计时按键按下的时间 { TH1=0xB1; TL1=0xE0; Record_Timer++; } if(flag_yinfu_dizhonggao==1||flag_yinfu_dizhonggao==3)//低音或高音 { if((cont==3&&flag_yinfu_dizhonggao==1)||flag_yinfu_dizhonggao==3) //低音占空比为1/4、高音占空比为1 { led=LED_Dis[yuzhi]; } elseled=0x00; } if(flag_yinfu_dizhonggao==2) { if(cont1) //控制占空比为1/2 { cont1=~cont1; led=LED_Dis[yuzhi]; } else { led=0x00; cont1=~cont1; } } cont++; if(cont>3) cont=0; } 中断函数中的余值在主程序中是这样赋值的: yuzhi=(KeyNo+3)%7; //判断DO RE MI FA... 根据yuzhi判断DO、RE...当时DO时,亮一个LED灯,当时RE时,亮两个LED... //21个音符的频率对应的T值 uint codeTone_Delay_Table[]={63628,63835,64021,64103,64260, 64400,64524,64580,64684,64777,64820,64898,64968,65030,65058, 65110,65157,65178,65217,65252,65283}; void main() { ucharKeystate=0; Timer_Init(); led=0x00; //初始化led led_zhishi=0;指示LED灭(进入演奏状态,若进入录音状态则亮) while(1) { Keystate=KeyState();//如果有按键按下,返回1 if(Keystate) { key_scan(); if(KeyNo<21)//KeyNo存储按下键的键值 { yuzhi=(KeyNo+3)%7; //判断DO RE MI FA... th0=Tone_Delay_Table[KeyNo]/256;//赋初值,产生 //按键所对应的音符的频率 tl0=Tone_Delay_Table[KeyNo]%256; YinFu_DiZhongGao_Flag(KeyNo);//判断是高中低音 TR0=1; //Turn on timer TR1=1; } elseif(KeyNo==21) //进入播放歌曲状态 { PlayMusic();Delayms(2000); } elseif(KeyNo==23) //进入录音状态 { Recordonoff=~Recordonoff; Record_yinfu(); } } else { TR0=0; //关闭定时器 TR1=0; led=0x00; cont=0;//控制占空比变量,让LED以不同频率闪烁 }
Delayms(2);
四.总结 这次设计中,在仿真软件上实现了高、中、低21个音符的发声和音乐的自动播放。以AT89C51单片机为基础,增加键盘模块,显示模块,发声模块与电源模块。通过上网查阅各音符的频率,使用21个按键来输入不同的音调,再通过采用定时器T0与T1来改变高低电平输出的频率来模拟不同音阶发音的频率,然后传送到喇叭,就可以发出相应的声音。音阶有低、中、高之分,通过显示模块的LED灯来表现音符高低。 五.参考文献[1]胡桂珍,《C程序设计教程》,西南交通大学出版社 [2]潘育山,《 单片机原理及C51开发技术》,西南交通大学出版社 [3]王晓明,《电机的单片机控制》,北京航空航天大学出版社 [4]李广弟,朱月秀,冷祖祁,《单片机基础第3版》,北京航空航天大学出版社 六.设计心得 这次设计设计完成后,体会颇多,在学与做的过程中,取长补短,不断学习新的知识,吸取经验,达到进步的目的。通过自身的努力以及相关图书资料的帮助,逐渐熟悉了Keil uVision4、PROTEUS和C语言等软件的使用。本次设计我学习到不少单片机的知识,但由于自己的理论知识水平有限,实践知识和设计经验不足,在设计过程中难免存在一些问题。在解决问题的过程中,加深了自己对单片机应用的理解。
|