基于单片机的电子琴设计.docx
《基于单片机的电子琴设计.docx》由会员分享,可在线阅读,更多相关《基于单片机的电子琴设计.docx(22页珍藏版)》请在冰豆网上搜索。
基于单片机的电子琴设计
郑州航空工业管理学院
单片机课程设计说明书
届电子信息工程专业班级
题目基于单片机的电子琴设计
学号
姓名
指导教师
二О一年月日
一、电子琴的基本原理
1、本次设计的内容是:
具有7个基本音符的按键,能够弹奏简单乐曲;能够播放存贮在内存中的3首乐曲;每次按下一个8键可以播放一首歌。
2、整体工作原理:
采用STC89C52单片机作为主控芯片,设置了键盘、蜂鸣器等外围器件,另外还用到一些简单器件如:
四位数码管和PNP型三极管及电阻等。
利用按键实现音符和音调的输入;四位的数码管进行被操作的按键显示;用PNP型三极管实现低音频功率放大;最后用蜂鸣器发音。
主控芯片采用STC89C52单片机,它是大规模集成电路技术发展的产物,具有高性能、高速度、体积小、价格低廉、稳定可靠、应用广泛的特点,同时具有强大的控制功能和灵活的编程实现特性。
3、发音原理:
若要产生音频脉冲,只要算出某一音频的周期(频率),再将此周期除以2,即为半周期的时间。
利用定时器计时半周期时间,每当计时终止后就将P1.7反相,然后重复计时再反相。
就可在P1.7引脚上得到此频率的脉冲。
利用STC89C52的内部定时器使其工作计数器模式(MODE1)下,改变计数值TH0及TL0以产生不同频率的方法产生不同音阶。
例如,频率为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
例如:
设K=65536,fi=1MHz,求中音DO(261Hz)。
T=65536-N=65536-fi÷2÷fr=65536-1000000÷2÷fr=65536-500000/fr,中音DO的T=65536-500000/523=64580
单片机12MHZ晶振,中音符与计数T0相关的计数值如表所示:
音符
频率(HZ)
计数值(T值)
音符
频率(HZ)
计数值(T值)
低1DO
262
63628
#4FA#
740
64860
#1DO#
277
63737
中5SO
784
64898
低2RE
294
63835
#5SO#
831
94934
#2RE#
311
63928
中6LA
880
64948
低3MI
330
64021
#中6LA#
932
64494
低FA
349
64103
中7SI
968
65030
#4FA#
370
64185
低1DO
1046
65058
低SO
392
64260
#1DO#
1109
65085
#5SO#
415
64331
高2RE
1175
65110
低6LA
440
64400
#2RE#
1245
65134
#6LA#
466
64463
高3MI
1318
65157
低7SI
494
64524
高4FA
1397
65178
中1DO
523
64580
#4FA#
1490
65198
#1DO#
554
64633
高5SO
1568
65217
中2RE
587
64633
#5SO#
1661
65235
#2RE#
622
64884
高6LA
1760
65252
中3MI
659
64732
#6LA#
1865
65268
中4FA
698
64820
高7SI
1967
65283
用单片机播放音乐,或者弹奏电子琴,实际上是按照特定的频率,输出一连串的方波。
为了输出合适的方波,首先应该知道音符与频率的关系。
二、电子时钟的硬件设计
1、硬件原理图:
本系统有主控芯片STC89C52、发音单元、显示模块、按键模块组成。
硬件电路要以单片机作为主控芯片,实现按键输入音符和音调,两位数码管的显示以及低音频功率放大和蜂鸣器发音。
针对本设计的功能和用途,采用STC89C52单片机更好.
2、时钟电路
单片机内部具有一个高增益反相放大器,用于构成振荡器。
通常在引脚Xl和X2跨接石英晶体和两个补偿电容构成自激振荡器,结构图2 中X1、C1、C2。
可以根据情况选择6MHz、12MHz或24MHz频率的石英晶体,补偿电容通常选择30pF左右的瓷片电容。
图-时钟电路
3、键盘设计
键盘可以分为2类:
独立连接式键盘和矩阵式键盘。
本设计采用矩阵式按键,矩阵式键盘由行线和列线组成,按键位于行、列线的交叉点上。
矩阵式键盘中,行、列线分别连接到按键开关的两端,行线通过上拉电阻接到+5V上.当无键按下时,行线处于高电平状态;当有键按下时,行、列线将导通,此时,行线电平将由与此行线相连的列线电平决定。
这是识别按键是否按下的关键。
图-矩阵键盘
4、元件清单
原件名称
数量
焊接位置
电源部分
USB座
1
USB
USB线
1
双排针
(2)
1
CONN1
跳帽
2
104电容0.1uF
6
C2,5,6,7,8,9,11
LED灯
1
D1
电阻2K
1
R2
最小系统部分
40针座
1
U1
STC89C52
1
晶振12MHz
1
Y1
电容20pF
2
C3,C4
复位键
1
SW_RST
电阻10K
1
R1
蜂鸣器
1
LS1+
三极管9015(密码锁,电子琴)
5
Q1~Q4,Q9
电阻330
1
R3
键盘显示、通信部分
16针座
1
U2
MAX232
1
单排针(5)
1
UART
按键(密码锁,电子琴)
8
KEY1~KEY8
单排针(3)
1
SWITCH1
跳帽
1
4位LED(密码锁,电子琴)
1
DIGILED1
电阻4.7K
8
R14~R21
电阻330
8
R6~R13
5、发音部分设计
如下图所示,发音电路是由蜂鸣器、三极管、上拉电阻构成。
由三极管来驱动扬声器发音的,同时加上拉电阻增强驱动电流,提高驱动能力。
图4发音电路
6、硬件调试
硬件调试主要是针对单片机部分进行的调试。
在上电之前,先确保电路中不存在断路或短路情况,这一工作是整个调试工作的第一步,也是非常重要的一个步骤。
在这部分调试中主要使用的工具是万用表,用来完成检测电路中是否存在断路或者短路情况的任务。
注意焊点之间,确保焊点没有短接在一起,同时注意焊点的美观,确保没有开路以及短路的现象出现在确保硬件电路正常且无异常情况(断路或短路)的情况下方可上电调试,上电调试的目的是检验电路是否接错,同时还要检验原理是否正确,在本次设计中,上电调试主要是检测单片机控制部分、数码管点亮部分、和音频转换电路硬件调试,
三、电子时钟的软件设计
1、键盘扫描程序:
检测是否有按键按下,有按键按下则记录按下键的键值,并跳转至功能转移程序;无按键按下,则返回键盘扫描程序继续检测。
2、功能转移程序:
对检测到的按键值进行判断,是琴键则跳转至琴键处理程序,是功能键则跳转至相应的功能程序,我们设计的功能程序有两种,即音色调节功能和自动播放乐曲的功能。
3、琴键处理程序:
根据检测到的按键值,查询音调表,给计时器赋值,使发出相应频率的声音。
4、自动播放歌曲程序:
检测到按键按下的是自动播放歌曲功能键后执行该程序,电子琴会自动播放事先已经存放的歌曲,歌曲播放完毕之后自动返回至键盘扫描程序,继续等待是否有按键按下。
5、程序流程图
图5流程图
6、设计源程序:
/*说明*************************************************************************
曲谱存贮格式unsignedcharcodeMusicName{音高,音长,音高,音长....,0,0};末尾:
0,0表示结束(Important)
音高由三位数字组成:
个位是表示1~7这七个音符;十位是表示音符所在的音区:
1-低音,2-中音,3-高音;百位表示这个音符是否要升半音:
0-不升,1-升半音。
音长最多由三位数字组成:
个位表示音符的时值,其对应关系是:
|数值(n):
|0|1|2|3|4|5|6
|几分音符:
|1|2|4|8|16|32|64音符=2^n
十位表示音符的演奏效果(0-2):
0-普通,1-连音,2-顿音
百位是符点位:
0-无符点,1-有符点
调用演奏子程序的格式
Play(乐曲名,调号,升降八度,演奏速度);
|乐曲名:
要播放的乐曲指针,结尾以(0,0)结束;
|调号(0-11):
是指乐曲升多少个半音演奏;
|升降八度(1-3):
1:
降八度,2:
不升不降,3:
升八度;
|演奏速度(1-12000):
值越大速度越快;
***************************************************************************/
#define__SOUNDPLAY_H_REVISION_FIRST__
#include
//**************************************************************************
#defineSYSTEM_OSC12000000//定义晶振频率12000000HZ
#defineSOUND_SPACE4/5//定义普通音符演奏的长度分率,//每4分音符间隔
sbitBeepIO=P1^7;//定义输出管脚
unsignedintcodeFreTab[12]={262,277,294,311,330,349,369,392,415,440,466,494};//原始频率表
unsignedcharcodeSignTab[7]={0,2,4,5,7,9,11};//1~7在频率表中的位置
unsignedcharcodeLengthTab[7]={1,2,4,8,16,32,64};
unsignedcharSound_Temp_TH0,Sound_Temp_TL0;//音符定时器初值暂存
unsignedcharSound_Temp_TH1,Sound_Temp_TL1;//音长定时器初值暂存
//**************************************************************************
voidInitialSound(void)
{
BeepIO=1;
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;
}
voidBeepTimer0(void)interrupt1//音符发生中断
{
BeepIO=!
BeepIO;
TH0=Sound_Temp_TH0;
TL0=Sound_Temp_TL0;
}
//**************************************************************************
voidPlay(unsignedchar*Sound,unsignedcharSignature,unsignedOctachord,unsignedintSpeed)
{
unsignedintNewFreTab[12];//新的频率表
unsignedchari,j;
unsignedintPoint,LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength;
unsignedcharTone,Length,SL,SH,SM,SLen,XG,FD;
for(i=0;i<12;i++)//根据调号及升降八度来生成新的频率表
{
j=i+Signature;
if(j>11)
{
j=j-12;
NewFreTab[i]=FreTab[j]*2;
}
else
NewFreTab[i]=FreTab[j];
if(Octachord==1)
NewFreTab[i]>>=2;
elseif(Octachord==3)
NewFreTab[i]<<=2;
}
SoundLength=0;
while(Sound[SoundLength]!
=0x00)//计算歌曲长度
{
SoundLength+=2;
}
Point=0;
Tone=Sound[Point];
Length=Sound[Point+1];//读出第一个音符和它时时值
LDiv0=12000/Speed;//算出1分音符的长度(几个10ms)
LDiv4=LDiv0/4;//算出4分音符的长度
LDiv4=LDiv4-LDiv4*SOUND_SPACE;//普通音最长间隔标准
TR0=0;
TR1=1;
while(Point{
SL=Tone%10;//计算出音符
SM=Tone/10%10;//计算出高低音
SH=Tone/100;//计算出是否升半
CurrentFre=NewFreTab[SignTab[SL-1]+SH];//查出对应音符的频率
if(SL!
=0)
{
if(SM==1)CurrentFre>>=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=LengthTab[Length%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(SLen<=4)
LDiv1=LDiv-LDiv4;
else
LDiv1=LDiv*SOUND_SPACE;
else
LDiv1=LDiv/2;//算出顿音的演奏长度
else
LDiv1=LDiv;
if(SL==0)LDiv1=0;
LDiv2=LDiv-LDiv1;//算出不发音的长度
if(SL!
=0)
{
TR0=1;
for(i=LDiv1;i>0;i--)//发规定长度的音
{
while(TF1==0);
TH1=Sound_Temp_TH1;
TL1=Sound_Temp_TL1;
TF1=0;
}
}
if(LDiv2!
=0)
{
TR0=0;BeepIO=1;
for(i=LDiv2;i>0;i--)//音符间的间隔
{
while(TF1==0);
TH1=Sound_Temp_TH1;
TL1=Sound_Temp_TL1;
TF1=0;
}
}
Point+=2;
Tone=Sound[Point];
Length=Sound[Point+1];
}
BeepIO=1;
}
//**************************************************************************
#endif
#include
#include"SoundPlay.h"
//*****************************Music******************************************************
unsignedcharcodesound1[]={0x15,0x02,0x00,0x00};//1
unsignedcharcodesound2[]={0x16,0x02,0x00,0x00};//2
unsignedcharcodesound3[]={0x17,0x02,0x00,0x00};//3
unsignedcharcodesound4[]={0x18,0x02,0x00,0x00};//4
unsignedcharcodesound5[]={0x19,0x02,0x00,0x00};//5
unsignedcharcodesound6[]={0x1A,0x02,0x00,0x00};//6
unsignedcharcodesound7[]={0x1B,0x02,0x00,0x00};//7
unsignedcharkey;
//挥着翅膀的女孩
unsignedcharcodeMusic_Girl[]={0x17,0x02,0x17,0x03,0x18,0x03,0x19,0x02,0x15,0x03,
0x16,0x03,0x17,0x03,0x17,0x03,0x17,0x03,0x18,0x03,
0x19,0x02,0x16,0x03,0x17,0x03,0x18,0x02,0x18,0x03,
0x17,0x03,0x15,0x02,0x18,0x03,0x17,0x03,0x18,0x02,
0x10,0x03,0x15,0x03,0x16,0x02,0x15,0x03,0x16,0x03,
0x17,0x02,0x17,0x03,0x18,0x03,0x19,0x02,0x1A,0x03,
0x1B,0x03,0x1F,0x03,0x1F,0x03,0x17,0x03,0x18,0x03,
0x19,0x02,0x16,0x03,0x17,0x03,0x18,0x03,0x17,0x03,
0x18,0x03,0x1F,0x03,0x1F,0x02,0x16,0x03,0x17,0x03,
0x18,0x03,0x17,0x03,0x18,0x03,0x20,0x03,0x20,0x02,
0x1F,0x03,0x1B,0x03,0x1F,0x66,0x20,0x03,0x21,0x03,
0x20,0x03,0x1F,0x03,0x1B,0x03,0x1F,0x66,0x1F,0x03,
0x1B,0x03,0x19,0x03,0x19,0x03,0x15,0x03,0x1A,0x66,
0x1A,0x03,0x19,0x03,0x15,0x03,0x15,0x03,0x17,0x03,
0x16,0x66,0x17,0x04,0x18,0x04,0x18,0x03,0x19,0x03,
0x1F,0x03,0x1B,0x03,0x1F,0x66,0x20,0x03,0x21,0x03,
0x20,0x03,0x1F,0x03,0x1B,0x03,0x1F,0x66,0x1F,0x03,
0x1B,0x03,0x19,0x03,0x19,0x03,0x15,0x03,0x1A,0x66,
0x1A,0x03,0x19,0x03,0x19,0x03,0x1F,0x03,0x1B,0x03,
0x1F,0x00,0x1A,0x03,0x1A,0x03,0x1A,0x03,0x1B,0x03,
0x1B,0x03,0x1A,0x03,0x19,0x03,0x19,0x02,0x17,0x03,
0x15,0x17,0x15,0x03,0x16,0x03,0x17,0x03,0x18,0x03,
0x17,0x04,0x18,0x0E,0x18,0x03,0x17,0x04,0x18,0x0E,
0x18,0x66,0x17,0x03,0x18,0x03,0x17,0x03,0x18,0x03,
0x20,0x03,0x20,0x02,0x1F,0x03,0x1B,0x03,0x1F,0x66,
0x20,0x03,0x21,0x03,0x20,0x03,0x1F,0x03,0x1B,0x03,
0x1F,0x66,0x1F,0x04,0x1B,0x0E,0x1B,0x03,0x19,0x03,
0x19,0x03,0x15,0x03,0x1A,0x66,0x1A,0x03,0x19,0x03,
0x15