不知不觉上了挺久的网课,由于大学还没开学,所以有些实验课也得在家自己上。其中有个现代电子设计的实验课,老师给了一些课题,由于我跟我的小伙伴基础不太好所以就选择了比较简单的课题——基于单片机的电子琴设计。下面来记录一下最终的成果。
基于单片机的简易电子琴的设计与制作
一、摘要
单片机是电子、计算机及机电专业的一门重要的必修课程。要求我们掌握单片机的基本组成和工作原理、会变程序的一般编写方法、常用接口电路的软硬件设计方法,具备基本的单片机系统应用与开发能力。
随着科技的快速发展,单片机的应用日益普遍。单片机具有强大的控制功能和灵活的编程实现特性,它已经溶入现代人们的生活中,成为不可替代的一部分。本单片机系统设计应用单片机控制技术,用AT89C51单片机为核心控制元件根据本学期所学的单片机知识结合设计了一套单片机控制的电子琴系统。电子琴是现代电子科技与音乐结合的产物,是一种新型的键盘乐器,它在现代音乐扮演着重要的角色。
本次设计首先对单片机设计简易电子琴仔细分析,接着制作硬件电路和编写软件的程序,最后进行软硬件的调试运行。并且从原理图,主要芯片,各模块的原理和各个模块的程序调试来阐述。利用单片机产生不同频率来获得我们要求的音阶,实现高、中、低共21个音符的发音和显示和音乐播放时的控制显示,并且能自动播放程序中编排的音乐。系统运行稳定,其优点是硬件电路简单,软件功能完善,控制系统可靠,性价比高等,具有一定的使用和参考价值。
关键词:单片机、电子琴、AT89C51、独立键
二、课题主要任务
1、根据要求,设计以单片机为核心的多音阶电子琴系统,可随意弹奏想要表达的音乐;
2、针对要求控制的对象完成程序的编制;
3、硬件软件联调,完成题目所要求的功能;
4、有高中低三个音阶,并有显示电路。
三、实施方案
四、电路设计
(1)时钟电路
单片机内部具有一个高增益反相放大器,用于构成振荡器。通常在引脚XTALl和XTAL2跨接石英晶体和两个补偿电容构成自激振荡器,如结构图中X1、C1、C2。可以根据情况选择6MHz、12MHz或24MHz等频率的石英晶体,补偿电容通常选择30pF左右的瓷片电容。
(2)复位电路
单片机小系统常采用上电自动复位和手动按键复位两种方式实现系统的复位操作。上电复位要求接通电源后,自动实现复位操作。手动复位要求在电源接通的条件下,在单片机运行期间,用按钮开关操作使单片机复位。其结构如下图。上电自动复位通过电容C3充电来实现。手动按键复位是通过按键将电阻R1与VCC接通来实现。
(3)显示部分设计
数码显示方式:
数码显示有静态显示方式与动态显示方式两种。工作在静态显示方式时,数码管的位线与电源一直相连,数码管中的二极管均处于通电状态,即在静态工作方式下,显示电路中数码管的位选线是同时选通,而数码管的段选线是独立输入。
工作在动态显示方式时,数码管的位线在扫描控制电路的控制下按设定顺序导通,即电路中的数码管是逐个接通电源,数码管的段选线以并联方式与译码电路联接,即在动态工作方式下,数码管不是同时导通显示而是按照设定顺序分时导通显示。
八位数码管的结构:
本次课程设计的显示电路采用一位数码管进行显示,由于此设计采用的是共阳极的,为了显示字符,要为LED显示器段码,除了组成8字形的字符的 7段,另加上1个小数点位,共计8段, 因此提供给 LED 显示器的显示段码为1个字节。
(4)按键部分设计
键盘设计:
键盘在单片机应用系统中是一个关键的部件,它能实现向计算机输入数据,传送命令等功能,是人工干预计算机的主要手段。
键盘可以分为2类:独立连接式键盘和矩阵式键盘。本设计采用独立式键盘。
独立式按键是直接用I/O口线构成的单个按键电路,其特点是每个按键单独占用一根I/O口线,每个按键的工作不会影响其它I/O口线的状态。独立式按键电路配置灵活,软件结构简单,但每个按键必须占用一根I/O口线,然而,在按键较多时,I/O口线浪费较大,不宜采用。
(5)音调部分设计
(6)发音部分设计
五、pcb设计
五、程序设计
(1)系统软件的组成
①键盘扫描程序:检测是否有按键按下,有按键按下则记录按下键的键值,并跳转至功能转移程序;无按键按下,则返回键盘扫描程序继续检测。
②功能转移程序:对检测到的按键值进行判断,是琴键则跳转至琴键处理程序,是功能键则跳转至相应的功能程序,我们设计的功能程序有两种,即音色调节功能和自动播放乐曲的功能。
③琴键处理程序:根据检测到的按键值,查询音调表,给计时器赋值,使发出相应频率的声音。
④自动播放歌曲程序:检测到按键按下的是自动播放歌曲功能键后执行该程序,电子琴会自动播放事先已经存放的歌曲,歌曲播放完毕之后自动返回至键盘扫描程序,继续等待是否有按键按下。
(2)发音原理
若要产生音频脉冲,只要算出某一音频的周期(1/频率),再将此周期除以2,即为半周期的时间。利用定时器计时半周期时间,每当计时终止后就将P3.7反相,然后重复计时再反相。就可在P3.7引脚上得到此频率的脉冲。利用AT89C51的内部定时器使其工作计数器模式(MODE1)下,改变计数值TH0及TL0以产生不同频率的方法产生不同音阶。
(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
程序代码:见本文最后(自测可用)
六、调试
Proteus和Keil的联调:
使用步骤:
1、打开keil,建立工程,输入程序
2、编译和生成hex文件。
3、打开Proteus,设计硬件电路图。
4、导入hex文件。将鼠标置于电路图中AT89C51器件上,右击后再左击,在出现的窗口中找到Program File对话框,并填入hex文件对应的路径。
5、点击面板左下角的箭头,开始调试。
6、按下任意键,扬声器发出对应的声音,并在数码管上显示出键值
参考文献
[1]谢辉,黄淘,李焱. 单片机原理及应用. 重庆. 化学工业出版社,2010
[2]苏家健,曹柏荣,汪志锋. 单片机原理及应用技术. 北京:高等教育出版社,2003
[3]李朝青. 单片机原理及接口技术. 北京:北京航天航空大学出版色,2001
[4]潭浩强. C语言程序设计. 北京:清华大学出版社,2005
[5]李华. MCS51/98系列单片机原理与应用. 北京:机械工业出版社,2007
[6]谢自美等. 电子线路设计、实验、测试. 北京:华中科技大学出版社,2006
[7]周灵彬,张靖武. 单片机产品的PROTEUS设计与仿真. 电子工业出版社,2008
[8]赵鑫,蒋亮,齐兆群等. 数字电路设计. 北京:机械工业出版社,2005
程序代码:
#include
#define uchar unsigned char
uchar Th0,Tl0; //TH0,TL0
sbit open=P0^7;
sbit Beep=P3^7; //定义蜂鸣器端口
//定义琴键按钮
sbit key1=P1^0;
sbit key2=P1^1;
sbit key3=P1^2;
sbit key4=P1^3;
sbit key5=P1^4;
sbit key6=P1^5;
sbit key7=P1^6;
//定义音区按钮
sbit lkey=P0^0; //低音
sbit mkey=P0^1; //中音
sbit hkey=P0^2; //高音
uchar flag=0XFF; //模式,0表示音乐,ff表示按键
uchar key=0; //按键代号
uchar a;
uchar yinqu=1; //高中低音区代号,默认为中音区
//音乐音符
uchar code MusicCode[]={
0XFC,0X44,0XFC,0XAC,0XFD,0X09,0XFD,0X34,0XFD,0X82,0XFD,0XC8,0XFD,
0X06,0XFB,0X04,0XFB,0X90,0XFC,0X0C,0XFE,0X22,0XF9,0X5B,0XFA,0X15
};
//月亮代表我的心
uchar code Music[]={0X02,0X82,0X16,0X32,0X54,0X02,0X52,0XA6,0X32,0X54,0X02,0X52,
0X64,0X74,0XB6,0X64,0X52,0X5C,0X32,0X22,0X16,0X12,0X14,0X32,0X22,0X16,0X12,0X14,
0X22,0X32,0X26,0X12,0X94,0X22,0X32,0X2C,0X32,0X52,0X36,0X22,0X14,0X54,0XAC,0X92,
0XA2,0X96,0X0A,0X96,0X82,0X3C,0X54,0X36,0X22,0X14,0X54,0XAC,0X92,0XA2,0X16,0X12,
0X14,0X22,0X32,0X2C,0X02,0X82,0X16,0X32,0X56,0X12,0XA6,0X32,0X56,0X52,0X66,0X72,
0XB6,0X62,0X62,0X52,0X58,0X32,0X22,0X16,0X12,0X14,0X32,0X22,0X16,0X12,0X14,0X22,
0X32,0X1C,0XFF};
//按键音符
uchar code KeyCode[]={
0XFF,0XFF,
0xF8,0x8C,0xF9,0x5B,0xFA,0x15,0xFA,0x67,0xFB,0x04,0xFB,0x90,0xFC,0x0C,//低音
0xFC,0x44,0xFC,0xAC,0xFD,0x09,0xFD,0x34,0xFD,0x82,0xFD,0xC8,0xFE,0x06,//中音
0xFE,0x22,0xFE,0x56,0xFE,0x85,0xFE,0X9A,0XFE,0xC1,0xFE,0xE4,0xFF,0x02,//高音
};
//定义函数
void Run(void);
void KeyScan(void);
void PlayKey(void);
void delay_1ms(uchar i);
void PlayMusic(void);
void DisPlay(void) ;
//主程序
void main(void) {
P1=0XFF; //初始化
P0=0XFF;
open=0;
P2=0XFF;
TMOD=0X01; //定时器工作模式1 16位定时器
IT0=1; //外部中断0 下降沿触发 ,为0是p3.2引脚上的低电平触发外部中断
TR0=0; //定时器0的运行控制位
EX0=1; //外部中断0中断允许位,=1为允许
ET0=1; //允许T0中断
EA=1; //总中断打开
a=0;
while(1){
KeyScan(); //按键扫描
Run(); //功能程序
DisPlay(); //显示
}
}
//功能程序
void Run(void){
if(flag==0) {
P2=0X8E;
a=8; //让数码管显示F
PlayMusic(); //播放歌曲
}
else
PlayKey(); //琴键响应
}
//按键扫描
void KeyScan(void){
if(key1==0) //第一按键按下
{ delay_1ms(12); //延时12MS
if(key1==0) //确定按下
{key=1;a=key; }
}
else if(key2==0)
{ delay_1ms(12);
if(key2==0)
{key=2;a=key;}
}
else if(key3==0)
{ delay_1ms(12);
if(key3==0)
{key=3;a=key;}
}
else if(key4==0)
{ delay_1ms(12);
if(key4==0)
{key=4;a=key;}
}
else if(key5==0)
{ delay_1ms(12);
if(key5==0)
{key=5;a=key;}
}
else if(key6==0)
{ delay_1ms(12);
if(key6==0)
{key=6;a=key;}
}
else if(key7==0)
{ delay_1ms(12);
if(key7==0)
{key=7;a=key;}
}
else if(lkey==0) //低音模式键按下
{ delay_1ms(12);
if(lkey==0)
{yinqu=0;a=yinqu;}
}
else if(mkey==0) //中音模式键按下
{ delay_1ms(12);
if(mkey==0)
{yinqu=1;a=yinqu;}
}
else if(hkey==0) //高音模式键按下
{ delay_1ms(12);
if(hkey==0)
{yinqu=2;a=yinqu;}
}
else return;
}
//琴键处理程序
void PlayKey(void){
if(key==0) //无琴键按下
return;
else{
Th0=KeyCode[yinqu*14+key*2];
Tl0=KeyCode[yinqu*14+key*2+1];
TR0=1;
delay_1ms(187);
TR0=0;
key=0;
}
}
//定时器0中断
time0() interrupt 1
{
TH0=Th0;
TL0=Tl0;
Beep=~Beep;
}
//外部中断0
void interrupt0() interrupt 0
{ flag=~flag;
if(flag==0)
{
P2=0X8E;
a=8;
}
else{
P2=0XFF ;
a=9;
}
}
//延时
void delay_1ms(uchar i)
{ uchar j,k;
for(j=0;j
for(k=0;k<148;k++);
}
//播放音乐
void PlayMusic(void)
{ uchar yinfu,jiepai;
uchar i,j;
for(i=0;Music[i]!=0XFF;i++)
{ yinfu=(Music[i]>>4);
jiepai=(Music[i]&0X0F);
if(yinfu==0)
continue;
Th0=MusicCode[(yinfu-1)*2];
Tl0=MusicCode[(yinfu-1)*2+1];
TR0=1;
for(j=jiepai;j>0;--j)
{ delay_1ms(250);}
TR0=0;
if(flag!=0)
break;
}
}
//数码管显示
void DisPlay(void)
{
switch(a){
case 0: P2= 0XC0;break;
case 1: P2= 0XF9;break;
case 2: P2= 0XA4;break;
case 3: P2= 0XB0;break;
case 4: P2= 0X99;break;
case 5: P2= 0X92;break;
case 6: P2= 0X82;break;
case 7: P2= 0XF8;break;
case 8: P2= 0X8E;break; //播放显示F
default:P2=0XFF;break;
}
}