资源描述
单片机原理及系统课程设计
评语:
考勤10分
守纪10分
过程30分
设计汇报30分
答辩20分
总成绩(100)
专 业: 自动化
班 级:
姓 名:
学 号:
指导老师:
兰州交通大学自动化和电气工程学院
年 12 月 30 日
基于单片机16键电子琴
一、电子琴设计目标、要求和设计方法
1.1设计目标
现代乐器中,电子琴是高新科技在音乐领域一个代表,表现了人类电子技术和艺术完美结合。电子琴自动伴奏稳定性、正确性,和鲜明强弱规律、随人设置速度要求,全部更便于大家由易到难、深入浅出正确掌握歌曲节奏和乐曲风格,对其节奏稳定性和正确性训练能起到很大作用。
1.2设计要求
本设计关键是用AT89C52单片机为关键控制元件,设计一个微缩版电子琴。单片机和按键组成主控制模块,在主控制模块上设置有9个按键,分别达成不一样目标。本系统关键为了完成电子琴三大功效:电子琴弹奏和音乐播放及录音。
1.3电子琴设计方法
1.3.1设计工具
表1软件介绍
软件名称
设计作用
Keil uVision4
编写程序和编译
PROTEUS
绘制硬件电路图、数字仿真
Microsoft Visio
绘制程序流图和框图
1.3.2设计思绪
(1)功效按键触发外部中止,以完成不一样曲目标切换。
(2)设置定时器产生不一样频率方波,I/O口输出,经功放后扬声器发声。
(3)采取4×4矩阵键盘弹奏16个音(低XI到高DO)。
二、 电子琴设计方案及原理
2.1设计总体方案
本系统采取AT89C52为主控芯片。输入电路有16个琴键按键,经过按键随意按下所要表示音符,作为电平送给主体电路,中央处理器经过识别,解码输出音符,在扬声器中发出有效声音。1个音乐按键用于播放音乐和切换歌曲,经过按键触发中止,重置定时器初值,于另一个扬声器中发出有效音响。
总设计框图以下图1所表示。
单
片
机
时钟复位电路
数码管显示电路
琴键控制电路
音频播放电路
音乐切换电路
图1基于单片机电子琴电路原理框图
2.2发声原理
利用AT89C52内部定时器使其工作计数器模式(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是想要产生频率。
三、 电子琴硬件设计
基于单片机AT89C51电子琴电路由琴键控制电路、数码管显示电路、音频播放电路、时钟-复位电路、音乐切换电路和电源电路六部分所组成。
3.1琴键控制电路
琴键控制电路作为人机联络输入部分,也是间接控制数码显示和音频功放关键组成部分。键盘根据连接方法能够分为独立式和矩阵式键盘两类。
3.1.1矩阵式键盘
图2所表示为4X4矩阵式键盘电路,由一个4X4行、列结构能够组成一个16个按键键盘。
矩阵中无按键按下时,行线为高电平;当有按键按下时,行线电平状态将由和此行线相连列线电平决定。列线电平假如为低,则行线电平为低;列线电平假如为高,则行线电平也为高,这是识别按键是否按下关键所在。
图2矩阵式键盘
3.1.2独立式键盘
独立式键盘特点是一键一线,各键相互独立,每个键各接一条I/O口线,经过检测I/O输入线电平状态,可判定出被按下按键。
3.1.3 方案比较
表2键盘类型比较
键盘类型
优点
缺点
独立式
电路简单,编程简单
占用I/O口线多
矩阵式
占用I/O口线较少
编程比较复杂
因为此次设计琴键控制电路需要16个按键,故单纯从I/O口线占用角度比较,独立式需要占用16条I/O口线,而矩阵式却只需8条。故选择矩阵式键盘电路比较合理。
3.2数码管显示电路
LED(Light Emitting Diode)发光二极管缩写。LED数码管是由发光二极管组成。常见LED数码管为“8”字型,累计8段。通常来说分共阳极和共阴极两种接法。
3.2.1LED数码管静态显示
静态显示方法即不管多少位LED数码管,同时处于显示状态。假如送往各个LED数码管所显示字符段码一经确定,则对应I/O口锁存器锁存段码输出将维持不变,直到送入另一个字符段码为止。
3.2.2LED数码管动态显示
静态显示方法就是不管在任何时刻只有一个LED数码管处于显示状态,即单片机采取“扫描”方法控制各个数码管轮番显示。
3.3.3方案比较
对于以上两种数码管驱动电路优缺点比较如表3所表示。因为静态驱动方法显示无闪烁,亮度较高,编程简单,加上此次设计数码管显示电路只需要2个数码管,且分别接两部分管脚,故选择静态驱动方法来显示数码管更为合理。图3所表示为数码管显示电路,采取静态驱动方法和共阳极接法。
表3数码管显示方法比较
驱动方法
优点
缺点
静态显示
显示无闪烁,亮度较高,
编程简单
数码管越多,所需电流越大,电源要求越高
动态显示
电路简单,数码管越多,
优势越显著
不如静态显示亮度高, 可能出现闪烁现象
图3数码管静态显示电路
3.3音乐切换电路
经过按键拉低电平,触发中止0。
3.4音频播放电路
使用两个扬声器,一个作为琴键输出,一个作为乐曲输出。
3.5时钟复位电路
3.5.1时钟电路
时钟频率直接影响单片机速度,时钟电路质量也直接影响单片机系统稳定性。常见时钟电路有两种方法,一个是内部时钟方法,另一个是外部时钟方法。 本设计采取内部时钟方法做时钟电路。
3.5.2复位电路
在单片机实用系统中,通常有两种复位操作形式:上电复位和手动复位。 上电复位在单片机系统每次通电时实施。手动复位在系统出现操作错误或程序运行犯错时使用。 因为本设计需要,同时采取这两种复位方法。
整体电路图以下图4所表示。
图4整体硬件设计
四、 电子琴软件设计
系统功效实现通常包含硬件部分和软件部分,一旦硬件确定下来,软件要实现功效也随之确定。而为使编程思绪清楚,应先绘制程序步骤图。
4.1 系统硬件接口定义
表4系统硬件接口定义
引脚名
接口说明
备注
P0.0~P0.7
琴键数码管和单片机通信
数码管显示电路
P2.0~P2.7
曲目数码管和单片机通信
数码管显示电路
P3.2(INT0)
外部中止源输入端
音乐切换电路
P1.0~P1.7
矩阵键盘接口
琴键控制电路
P3.0,P3.7
控制扬声器
音频播放电路
4.2主函数
主函数步骤图图5所表示。利用模块化思想,主函数只实施初始化函数、键盘扫码函数、音频处理函数和数码管显示函数。
图5主函数步骤图
4.3初始化函数
初始化步骤框图图6所表示。该函数对所需I/O口、外部中止0、定时器0、定时器T1和数码管进行初始化配置。
TMOD=0x11; //T0方法1,T1方法1
IP=0x01; //INT0中止优先级最高
EA=1;ET0=1;ET1=1;EX0=1; //许可中止
TR0=0; //关定时器0
P1=0xbf; //键盘初始化
flag=0; //标志位置0
图6初始化步骤图
4.4数码管显示及音频处理函数
依据键值扫描函数读取键码,扬声器发声并结合数码管显示出来。
图7数码管显示步骤图
4.5中止函数
中止函数用到了外部中止和定时器中止。外部中止步骤框图图8所表示,当按键按下时,外部信号触发外部中止,实施键值扫描函数,读取对应键值。定时中止步骤框图图9所表示,定时器溢出中止后,进行重装载初值,同时实施对应音频控制操作。
4.6键值扫描函数
将输入端置为高电平,输出端置为低电平。这么,当按键没有按下时,全部输入端无改变,代表无键按下。一旦有键按下,则输入线就受输出线影响被拉低,这么,经过读入输入线状态就可得悉是否有键按下了。步骤图图10所表示。
图8外部键盘中止步骤图 图9定时器中止步骤图
图10键值扫描步骤图
五、 电子琴系统仿真
5.1部分仿真结果
表5仿真结果
按键编号
发声音调
数码管显示
备注
0
低XI
0,-
1
中DO
1,-
2
中RI
2,-
无
播放曲目及停止
1,2,或-
反复按切换音乐
图11音乐显示为“-”或不显示时候,琴键按下DO有效
图12按音乐键,播放音乐1,琴键弹奏无效
5.2调试中出现问题及处理
电子琴设计并非一帆风顺,在这期间碰到了很多问题,下面谈多个关键问题。首先是数码管显示乱码问题,原本认为是数码管字形码表代码有错,检验几遍发现代码基没错,以后结合硬件图一看,才知道硬件图中数码管是共阳极接法,软件中数码管字形码表是共阴极。其二是按键引入中止检测时碰到问题,按音乐键后琴键无法发声和显示,浪费了很多时间,最终发觉是程序判定条件有问题。其三是扬声器发出音调不对,甚至没有声音,这个问题以后还是不能处理,最终放弃了LM386功放电路,直接接扬声器,不过造成了部分琴键发声带杂音。
六、 总结
在此次设计八路多功效抢答器课设过程中,我利用AT89C52单片机及外围接口实现电子琴,利用单片机定时器/计数器定时和计数原理实现对弹奏和播放功效,利用Proteus和Keil软件设计出试验电路,完成了课设任务。
在此次课设中,我意识到将理论知识和实践相结合关键性,对于单片机这么课程,仅仅经过了解书本上知识是远远不够,我经过查资料和搜集相关文件,培养了自学能力,经过利用软件仿真和焊接电路,在很大程度上提升了我动手能力。我们在课设过程中,碰到了很多问题,比如我在仿真过程中错把共阴极数码管字模看成共阳极使用,使得数码管无法正常显示,经过查资料我明白了共阴极数码管是高电平驱动,公共端是负极,共阳极数码管是低电平驱动,公共端是正极,类似问题出现了很多,我们经过一一排查,最终完成了课设任务,结果表明,有付出必有收获,把握关键、攻克难关,活学活用对于牢靠掌握知识,是很有用。
在此次课设中,我学到了很多,也经过不停纠正自己错误,意识到本身不足,我对知识掌握还没有实现深层次了解记忆,我相信这些教训全部为我以后学习奠定了良好基础,时刻切记团体合作、坚持和努力关键性。
参考文件
[1] 王思明,张金敏,苟军年.单片机原理及应用系统设计[M].北京:人民邮电出版社,.
[2] 冯育长,邹小兵.单片机系统设计和实例指导[M]. 西安:西安电子科技大学出社,.
[3] 彭伟.单片机C语言程序设计实训100例[M].北京:电子工业出版社,.
[4] 单丹,马淑云.基于AT89C51单片机电子琴设计[J].中国高新技术企业,.
附录
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
//共阳极数码管
Uchar code LED[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xbf};
sbit beep=P3^0;
uchar key; //键号
sbit buzzer=P3^7;
uchar dis_buf;
uchar flag;
//音符延时表
uint code Tone_Delay_Table[]=
{64524,64580,64684,64777,64820,64896,64966,65030,65058,65110,65157,65178,65217,65252,65283,65316};
//音调和节拍
uchar code Song1_Tone[]=
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0xff};
uchar code Time1_Tone[]=
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xff};
uchar code Song2_Tone[]=
{3,5,5,3,2,1,2,3,5,3,2,3,5,5,3,2,1,2,3,2,1,1,0xff};
uchar code Time2_Tone[]=
{2,1,1,2,1,1,1,2,1,1,1,2,1,1,2,1,1,1,2,1,1,1,0xff};
uchar code Song3_Tone[]={1,1,5,5,6,6,5,4,4,3,3,2,2,1,0xff};
uchar code Time3_Tone[]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xff};
//定义按键序号
uchar keyno;
//音乐片段索引,音符索引
uchar song_index=0;
uchar tone_index=0;
//音符指针,延时指针
uchar *tone_pointer,*delay_pointer;
//从目前数组中取出音符位置
uchar i =0;
//毫秒延时
void delayms(uint ms)
{
uchar t;
while(ms--) for(t=0;t<120;t++);
}
//按键产生外部中止
void Key_Press() interrupt 0
{
TR0=0;
//切换歌曲
song_index=(song_index+1)%3;
switch(song_index)
{
case 2:tone_pointer=Song1_Tone;
delay_pointer=Time1_Tone;
break;
case 1:tone_pointer=Song2_Tone;
delay_pointer=Time2_Tone;
break;
case 0:tone_pointer=0;
delay_pointer=0;
break;
}
//重新开始
i=0;
TR0=1;
flag=1;
}
//T0中止播放
void play_music() interrupt 1
{ if(song_index!=0){
TH0=Tone_Delay_Table[tone_index]/256;
TL0=Tone_Delay_Table[tone_index]%256;
buzzer=~buzzer;}
else{buzzer=0;}
}
/*void key_scan()
{
uchar temp,k;
//高四位置0,放入四行
P1=0x0f;
delayms(2);
//按键后00001111变成0000xxxx,x中1个为0,3个仍为1
//以下亦或操作把3个1变成0,唯一0变成1
temp=P1^0x0f;
//判定按键发生于0-3列哪一列
switch(temp)
{
case 1:k=0;break;
case 2:k=1;break;
case 4:k=2;break;
case 8:k=3;break;
default:return;
}
//底四位置0,放入四列
P1=0xf0;
delayms(2);
//按键后11110000变成xxxx0000,x为1个0,三个仍为1
//高四位移动至底四位,唯一0变1,其它为0
temp=(P1>>4)^0x0f;
//对0~3行分别赋起始值0,4,8,12
switch(temp)
{
case 1:k+=0;break;
case 2:k+=4;break;
case 4:k+=8;break;
case 8:k+=12;break;
default:return;
}
keyno=k;
} */
//矩阵键盘扫描子程序
void key_scan(void)
{ uchar temp;
P1=0x0F; //低四位输入
delayms(2); //稍稍延时
temp=P1; //读P1口
temp=temp&0x0F; //取低四位
temp=~(temp|0xF0);
if(temp==1) //检测按下键所在列号,在第一列
key=0;
else if(temp==2) //在第二列
key=1;
else if(temp==4) //在第三列
key=2;
else if(temp==8) //在第四列
key=3;
else
key=16; //不然显示-
P1=0xF0; //高四位输入
delayms(2);
temp=P1; //读P1口
temp=temp&0xF0;
temp=~((temp>>4)|0xF0);
if(temp==1) //检测按下键所在行号,在第一行
key=key+0;
else if(temp==2) //在第二行
key=key+4;
else if(temp==4) //在第三行
key=key+8;
else if(temp==8) //在第四行
key=key+12;
else
key=16; //不然显示-
/* 依据行号和列号得到按下键号 */
dis_buf=LED[key]; //查表得键值
}
//T1中止,发声DO RI MI 。。。。
void play() interrupt 3
{
TH1=Tone_Delay_Table[key]/256;
TL1=Tone_Delay_Table[key]%256;
beep=~beep;
}
//主程序
void main()
{
TMOD=0x11; //T0方法1,T1方法1
IP=0x01; //INT0中止优先级最高
EA=1;
ET0=1;
ET1=1;
EX0=1; //许可中止
TR0=0;
P1=0xbf;
flag=0;
while(1)
{ //if(flag==0){
P1=0xf0;//发送扫描码
if(P1!=0xf0)//有键按下
{
if(song_index!=2&&song_index!=1)
{
key_scan();
P0 = dis_buf; //键值赋给P0口,显示
TR1=1;
}
}
else
{
TR1=0;//停止播放
} //}
if(flag==1&&song_index!=0)
{
delayms(2);
tone_index=tone_pointer[i];
if(tone_index==0xff)
{
i=0;
delayms();
continue;
}
TR0=1;
delayms(delay_pointer[tone_index]*240);
TR0=0;
i++;
switch(song_index)
{
case 2:P2=LED[2];
break;
case 1:P2=LED[1];
break;
case 0:P2=0xbf;
break;
}
}
}
}
展开阅读全文