基于单片机的电子琴设计与实现课程设计详解
课程设计题目: 基于单片机的电子琴的设计与实现
所修课程名称: 《微机原理及应用》
徐晓峰
2024.1.2
目录
基于单片机的电子琴的设计与实现
一、设计目的
1、 基于PROTEUS完成硬件电路的设计,基于AT89S51单片机完成控制显示程序的设计。
2、 独立完成设计工作,重点要求创新,用不同的方式实现基于单片机的电子琴的设计工作。
3、 完成自己的PPT制作工作,独立答辩。
4、 提交设计报告。
二、题目分析
本次设计是利用单片机产生不同频率来达到音阶的控制,实现类似电子琴的功能。通过控制单片机频率的变化获得我们要求的音阶,实现高、中、低共21个音符的发音。
本设计在音阶播放的基础上,设立以下创新点:
1、 设立为双重模式,分别为弹奏模式和播放模式,通过按键进行切换,并通过LED显示当前模式。
2、 增加可视化LED显示功能,显示当前声音为何种高中低音符。
3、 可以随意的改写播放模式中的曲目,弹奏想要表达的音乐。
4、 能自动播放程序中编排的多首音乐,通过按键切换音乐内容。
5、 系统运行稳定,硬件电路简单,软件功能完善。
本设计应用单片机控制技术,采用AT89C51单片机为核心,根据本学期所学的单片机知识结合设计了一套单片机控制的电子琴系统。
电子琴是现代电子科技与音乐结合的产物,是一种新型的键盘乐器,它在现代音乐扮演着重要的角色。
三、总体方案
单片机音乐播放器控制系统结构简单,环节较少,因此,单片机音乐播放器除了播放音乐有按键外,其余的硬件组成大体相同。在实际电路中,对于单片机音乐播放器声音的读出除了蜂鸣器以外,还要配置合适的放大器播放出响亮的声音。
本次课程设计总体采用软件控制硬件的方式,用Keil软件编写相应C语言程序用于驱动和控制芯片的工作,同时应用Proteus仿真软件搭建仿真电路完成整体电路仿真。
四、 系统硬件设计
4.1总体设计框图
电路总体以AT89C51单片机为核心,由电源电路进行驱动,键盘电路进行控制,当按下键盘控制,单片机根据当前状态控制蜂鸣器发出声音,按下复位键后恢复初始状态。
图 1 总体设计框图
4.2总体电路
图 2 总体电路图
4.3 局部电路
4.3.1 晶振电路
晶振电路主要用于产生12M 的晶振,给单片机提供工作信号脉冲。如图所示,将两个电容C1、C2串联在AT89C51的18和19端口即XTAL1和XTAL2两个端口,再并联一个晶振器(如图中Y1),最后整体接地,构成晶振电路。
图 3 晶振电路
4.3.2复位电路
将如图所示电路接入AT89C51的9号端口RST端口,用于总电路的复位。
图 4 复位电路
4.3.3按键电路
用独立式键盘的7个按键分别对应相应的音符,当按下某一个按键时,产生一个相应音符,操作者按一定的节奏、规律进行输入时,信号经过单片机处理,然后经音频放大后经扬声器输出音频信号,产生乐曲。
图 5 音符按键电路
选择控制功能采用四个按键控制,分别为“功能切换”、“高音”、“中音”、“低音”。其中K1按键接入P3.2,K2按键接入P3.3,K3按键接入P3.4,K4按键接入P3.5。
图 6控制按键电路
4.3.4播放电路
本次采用无源蜂鸣器SPEAKER来音乐的读出,只需要将蜂鸣器一端接入P2.2另一端接地即可。
图 7 播放电路
4.3.5当前模式电路
通过控制LED灯的亮灭,观察当前处于何种状态。
图 8 当前模式电路
4.3.6数码管显示电路
图 9 数码管显示电路
图 10数码管显示配套的位移缓存器
74HC595是一个8位串行输入、平行输出的位移缓存器。平行输出是在12脚STCP的上升沿时,8位位移缓存器的数据存人到8位平行输出缓存器。当13脚串行数据输人端OE的控制信号为低使能时,平行输出端的输出值等于平行输出缓存器所存储的值。具有锁存功能。
OE置低电平,MR置高电平,在正常使用时STCP为低电平, OE为低电平。从DS每输入一位数据,串行输入时钟SHCP上升沿有效一次,直到八位数据输入完毕,输出时钟STCP上升沿有效一次,此时,输入的数据就被送到了输出端,数码管将接收数据显示出来。
LED 灯的显示原理:通过同名管脚上所加电平的高低来控制发光二极管是否点亮而显示不同的字形,全亮显示为8,采用共阴极连接驱动代码,代码表如下表1所示。
表1:驱动代码表
五、 各部分定性说明以及定量计算
5.1单片机发声概述
一般来说,单片机不像其他专业乐器那样能奏出多种音色的声音,即不包含相应幅度的谐振频率。单片机演奏的音乐基本都是单音频率。因此单片机演奏音乐比较简单,只需能清楚“音调”和“节拍”两个概念即可。音调表示一个音符唱多高的频率。节拍表示一个音符唱多长的时间。知道了一个音符的频率后,便可以让单片机发出相应频率的振荡信号,从而产生相应的音符声音。
通过单片机的定时器进行定时中断,在中断服务程序中将单片机上完结单片机IO口来回置高电平或者是低电平的,从而让扬声器发出声音。通过节拍计算出每个音符所需要的时间,采用循环延时的方法来实现控制一个音符唱多长的时间,从而构成一首完整的音乐。
音调主要由声音的频率决定。对一定强度的纯音,音调随频率的升降而升降;对一定顿率的纯音、低频纯音的音调随响度增加而下降,高频纯音的音调却随响度增加而上升。
音调的高低还与发声体的结构有关,因为发声体的结构影响了声音的顿率。大体上,2000 赫兹以下的低频纯音的音调随响度的增加而下降,3000赫兹以上高频纯音的音调随响度的增加而上升。
在音乐中音符1与音符2,音符2与音符3……等等之间正好相差一个倍频程,在音乐学中称它相差一个八度音。在一个八度内,有12个半音。由于人耳的听觉效果,这12个音阶的分度基本上是以对数的关系来划分的。只要知道12个音符的音高,也就是其基本频率,就可以根据音符之间的倍频关系得到其他音符的基本音调频率。
以标准高音A的频率F=440HZ,其对应的周期为:
T=1/F=1/440=2272us
因此需要在单片机IO端口输出周期为T=2272us的方波脉冲,也就是 t=T/2=2272/2=1136us
也就是说,单片机上定时器的中断出发时间为1136us。如果单片机采用定时器为工作方式1,它以振荡器的十二分频信号为计数脉冲。设外接晶振的振荡器频率为f,则定时器的预置初始值有以下公式来确定:
Temp=65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC);
TH=Temp/256;
TL=Temp%256;
5.2音乐的产生
一首音乐是许多不同的音阶组成的,而每个音阶对应着不同的频率,这样我们就可以利用不同的频率的组合,即可构成我们所想要的音乐了,当然对于单片机来产生不同的频率非常方便,我们可以利用单片机的定时/计数器TO来产生这样方波频率信号,因此,我们只要把一首歌曲的音阶对应频率关系设置正确即可。
若要产生音频脉冲,只要算出某一音频的周期,再将此周期除以2,即为半周期的时间。利用定时器计时半周期时间,每当计时终止后就将P1.0反相,然后重复计时再反相。就可在P1.0引脚上得到此频率的脉冲。
利用AT89C51的内部定时器使其工作计数器模式(MODE1)下,改变计数值TH0及 TL0以产生不同频率的方法产生不同音阶。
计数脉冲值与频率的关系式是:
N = fi÷2÷fr
式中,N是计数值;fi是机器频率(晶体振荡器为12MHz时,其频率为1MHz);fr是想要要产生的频率。
其计数初值T的求法如下:
T = 65536-N = 65536-fi÷2÷fr
例如:设K=65536,f=1MHz,求低音DO(261Hz)、中音DO (523Hz)、高音DO (1046Hz)的计数值。
T = 65536—N = 65536—fi÷2÷fr = 65536—1000000÷2÷fr = 65536—500000/fr
低音DO的T=65536—500000/262=63627;
中音DO的T=65536—500000/523=64580;
高音DO的T=65536-500000/1046=65059;
单片机12MHZ晶振,高中低音符与计数TO相关的计数值如表1所示
表2:音符频率表
程序中的全局变量FREQH 和 FREQL就是音符频率表,分别为数据的高8位和低8位,如下:
//音阶频率表 高八位
uchar code table2[]={
0xFC,0xFC,0xFD,0xFD,0xFD,0xFD,0xFE,//中音的高8位
0xF9,0xF9,0xFA,0xFA,0xFB,0xFB,0xFC, //低音的高8位
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF,//高音的高8位
};
//音阶频率表 低八位
uchar code table3[]={
0x8E,0xED,0x44,0x6B,0xB4,0xF4,0x2D, //中音的低8位
0x21,0xDB,0x87,0xD7,0x68,0xE8,0x5B, //低音的低8位
0x47,0x77,0xA2,0xB6,0xDA,0xFA,0x16, //高音的低8位
};
table2[]和 table3[]中分别为数据的高8位和低8位,分别用来初始化THO、TLO。
音乐的音拍,一个节拍为单位(C调)(如表2所示)
六、 系统软件设计
5.1软件部分解析
为了实现本次课程设计的功能,可以选择用C语言或者汇编语言来编写相应程序,但是由于汇编语言能实现功能较少,且编写复杂,而本次课程设计涉及的软件部分又较为繁琐,故采用相对来说更加便捷、清晰的C语言来编写。
本次设计大体功能共分为弹奏模式和播放模式。弹奏模式可以实现高、中、低共21个音符的发音,播放模式可以自动播放预先写入程序的音乐曲目。
本次软件部分可大致分为以下部分:
1 主函数
2 数据定义
3 初始化子函数
4 延时子函数
5 数码管显示子函数
6 高低音选择子函数
7 播放音乐子函数
8 演奏模式子函数
5.2 程序流程框图设计
图 11 程序流程框图
5.3主要模块代码分析
5.3.1 主函数
//主函数
void main()
{
init();
while(1)
{
if(flag==0)
display_music();
else
display_play();
}
}
5.3.2 延时子函数
//延时子函数
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=340;y>0;y--);
}
5.3.3 初始化子函数
//初始化子函数
void init()
{
beep=0;
D1=1;
D2=0;
EA=1;//开总中断
TCON=0x01;//外部中断0设置为边沿触发
EX0=1;//开外部中断0
ET0=1;
ET1=1;
TMOD=0x11;//定时器0,1工作在定时状态,均为方式1
}
5.3.4 数码管显示子函数
//数码管显示子函数
void display1()
{
in(table1[aa]); //再传段码
out();
W1=0;;
delay(1); //延迟时间2ms以内
W1=1;
in(table1[cc+1]); //再传段码
out();
W2=0;
delay(1); //延迟时间2ms以内
W2=1;
}
5.4.5 高低音选择子函数
//高低音选择子函数
void yinjie()
{
if(k10==0)
{
delay(5);
if(k10==0)
{
aa=10;
bb=0;//返回10为seg[10]显示C
}
}
if(k9==0)
{
delay(5);
if(k9==0)
{
aa=11;
bb=1;//返回11为seg[11]显示L
}
}
if(k11==0)
{
delay(5);
if(k11==0)
{
aa=12;
bb=2;//返回12为seg[12]显示H
}
}
if(aa==0)
{
aa=13;
}
}
5.5.6 播放音乐子函数
//播放音乐子函数
void display_music()
{
TH0=table2[table4[i]-1];
TL0=table3[table4[i]-1];
while(flag==0)
{
if(i<32)
{
TR0=1;
delay(57*table5[i]);
i++;
}
if(i==32)
{
i=0;
}
}
}
5.5.7 演奏模式子函数
//演奏模式子函数
void display_play()
{
TR0=0;
TR1=0;
yinjie();
WE2=1;//关数码管2
WE1=0;//开数码管1
P0=table1[aa];
if(aa!=13&&flag==1)
{
if(k1==0)
{
TH1=table2[7*bb+cc];
TL1=table3[7*bb+cc];
TR1=1;
while(k1==0)
{
cc=0;
display1();
}
}
if(k2==0)
{
TH1=table2[7*bb+cc];
TL1=table3[7*bb+cc];
TR1=1;
while(k2==0)
{
cc=1;
display1();
}
}
if(k3==0)
{
TH1=table2[7*bb+cc];
TL1=table3[7*bb+cc];
TR1=1;
while(k3==0)
{
cc=2;
display1();
}
}
if(k4==0)
{
TH1=table2[7*bb+cc];
TL1=table3[7*bb+cc];
TR1=1;
while(k4==0)
{
cc=3;
display1();
}
}
if(k5==0)
{
TH1=table2[7*bb+cc];
TL1=table3[7*bb+cc];
TR1=1;
while(k5==0)
{
cc=4;
display1();
}
}
if(k6==0)
{
TH1=table2[7*bb+cc];
TL1=table3[7*bb+cc];
TR1=1;
while(k6==0)
{
cc=5;
display1();
}
}
if(k7==0)
{
TH1=table2[7*bb+cc];
TL1=table3[7*bb+cc];
TR1=1;
while(k7==0)
{
cc=6;
display1();
}
}
}
}
七、 在设计过程中遇到的问题以及解决措施
在本次课程设计中仍然遇到了不少问题,主要情况有以下:
一是关于音乐的产生和播放。由于之前并未接触过利用单片机发声的相关学习和研究。尤其是需要产生一首完整的乐曲,这对我来说无疑是一个挑战。后面通过查阅相关资料。尝试不同程序和电路得到利用TO、T1口计数功能来产生播放音乐的办法。
二是用keil软件编写程序时头文件缺失。在我最开始的想法中需要用到C语言中左移函数(-crol-),但是可能是由于安装时未完全破解导致缺少相应头文件。以至于不得不放弃使用这个函数,改为利用查表的方式进行歌曲插放。
以上就是我在本次课程设计中遇到的两个较为典型的问题。
八、 设计心得体会
经过这次课程设计,我觉得自己学到了不少东西。归纳起来,主要有以下几点:
(1)通过这次课程设计,我能将所学到的专业知识与实践相联系,将所学到的知识充分运用到本次设计中。同时,我也认识到自己知识上不足的地方,体会到了所学理论知识的重要性,知识掌握得越多,设计得就更全面、更顺利、更好。
(2)进一步熟悉了单片机的知识。通过本次设计,我对单片机的基本原理、内部结构、各引脚功能、定时器和中断的应用都有了更深刻的理解。并且,能够以单片机为基础元件设计一个简单的系统。
(3)通过本次设计,熟悉了设计一个项目所必经的几个阶段。本次设计从理论研究到硬件原理图设计,从软件编程到最后的调试过程都由我独立完成。这不仅锻炼了我独立完成设计工作的能力,更重要的是了解了一个电子产品的设计流程。为将来投入工作增加了宝贵的经验,莫定了坚实的基础。
(4)提高了自己查找资料的能力。在设计过程中,我碰到了一些暂时无法解决的问题,于是我通过上网查阅资料,或是通过与老师同学交流一步步地解决了。从中我懂得了我们这个专业的知识面相当广泛,我们需要不断通过各种途径更新自己的知识,不断充实自己,同时要懂得与他人交流意见,积极听取别人的建议,懂得不断学习的重要性。
参考文献:
[1]欧伟明.单片机原理及应用(C51语言版》,电子工业出版社,2019[2]CSDN.单片机相关知识理论