基于单片机的电子琴设计大学论文.docx
《基于单片机的电子琴设计大学论文.docx》由会员分享,可在线阅读,更多相关《基于单片机的电子琴设计大学论文.docx(14页珍藏版)》请在冰豆网上搜索。
基于单片机的电子琴设计大学论文
基于单片机的电子琴设计
摘要
本论文设计一个基于单片机的简易电子琴。
电子琴是现代电子科技与音乐结合的产物,是一种新型的键盘乐器。
它在现代音乐扮演着重要的角色,单片机具有强大的控制功能和灵活的编程实现特性,它已经融入现代人们的生活中,成为不可替代的一部分。
本文的主要内容是用AT89C51单片机为核心控制元件,设计一个电子琴。
以单片机作为主控核心,与键盘、扬声器等模块组成核心主控制模块,在主控模块上设有16个按键和扬声器。
本系统运行稳定,其优点是硬件电路简单,软件功能完善,控制系统可靠,性价比较高等,具有一定的实用和参考价值。
本文主要对使用单片机设计简易电子琴进行了分析,并介绍了基于单片机电子琴系统硬件组成。
利用单片机产生不同频率来获得我们要求的音阶,最终可随意弹奏想要表达的音乐。
并且本文分别从原理图,主要芯片,各模块原理及各模块的程序的调试来详细阐述。
一首音乐是许多不同的音阶组成的,而每个音阶对应着不同的频率,这样我们就可以利用不同的频率的组合,即可构成我们所想要的音乐了,当然对于单片机来产生不同的频率非常方便,我们可以利用单片机的定时/计数器T0来产生这样方波频率信号,因此,我们只要把一首歌曲的音阶对应频率关系弄正确即可。
1总体设计
1.1系统硬件连线
系统硬件连线如图1-1所示,发声模块,键盘模块,单片机最小系统模块连接如图:
图1-1
1.把“单片机系统”区域中的P1.0端口用导线连接到“音频放大模块”区域
SPKIN端口上;
2.把“单片机系统”区域中的P3.0-P3.7端口用8芯排线连接到“4X4行列式键盘”区域中的C1-C4 R1-R4端口上;
3.把“单片机系统”区域中的P0.0/AD0-P0.7/AD7端口用8芯排线连接到“四路静态数码显示模块”区域中的任一个a-h端口上;要求:
P0.0/AD0对应着a,P0.1/AD1对应着b,……,P0.7/AD7对应着h。
1.2主要芯片简介
1.2.1AT89S51简介
AT89S51是一个低功耗,高性能CMOS8位单片机,片内含4kBytesISP(In-systemprogrammable)的可反复擦写1000次的Flash只读程序存储器,器件采用ATMEL公司的高密度、非易失性存储技术制造,兼容标准MCS-51指令系统及80C51引脚结构,芯片内集成了通用8位中央处理器和ISPFlash存储单元,功能强大的微型计算机的AT89S51可为许多嵌入式控制应用系统提供高性价比的解决方案。
AT89S51具有如下特点:
40个引脚(引脚图如图1-2所示),4kBytesFlash片内程序存储器,128bytes的随机存取数据存储器(RAM),32个外部双向输入/输出(I/O)口,5个中断优先级2层中断嵌套中断,2个16位可编程定时计数器,2个全双工串行通信口,看门狗(WDT)电路,片内时钟振荡器。
此外,AT89S51设计和配置了振荡频率可为0Hz并可通过软件设置省电模式。
空闲模式下,CPU暂停工作,而RAM定时计数器,串行口,外中断系统可继续工作,掉电模式冻结振荡器而保存RAM的数据,停止芯片其它功能直至外中断激活或硬件复位。
同时该芯片还具有PDIP、TQFP和PLCC等三种封装形式,以适应不同产品的需求。
图1-2单片机
1.2.1.1主要功能特性
兼容MCS-51指令系统
32个双向I/O口
2个16位可编程定时/计数器
全双工UART串行中断口线
2个外部中断源
中断唤醒省电模式
看门狗(WDT)电路
灵活的ISP字节和分页编程
4k可反复擦写ISPFlashROM
4.5-5.5V工作电压
时钟频率0-33MHz
128*8bit内部RAM
低功耗空闲和省电模式
3级加密位
软件设置空闲和省电功能
2硬件设计内容
2.14X4矩阵键盘识别
组成键盘的按键有机械式、电容式、导电橡胶式、薄膜式多种,但不管什么形式,其作用都是一个使电路接通与断开的开关。
目前微机系统中使用的键盘按其功能不同,通常可分为编码键盘和非编码键盘两种基本类型。
编码键盘:
键盘本身带有实现接口主要功能所需的硬件电路。
不仅能自动检测被按下的键,并完成去抖动、防串键等功能,而且能提供与被按键功能对应的键码(如ASCII码)送往CPU。
所以,编码键盘接口简单、使用方便。
但由于硬件电路较复杂,因而价格较贵。
非编码键盘:
键盘只简单地提供按键开关的行列矩阵。
有关按键的识别、键码的确定与输入、去抖动等功能均由软件完成。
目前微机系统中,一般为了降低成本大多数采用非编码键盘。
键盘接口必须具有去抖动、防串键、按键识别和键码产生4个基本功能。
(1)去抖动:
每个按键在按下或松开时,都会产生短时间的抖动。
抖动的持续时间与键的质量相关,一般为5—20mm。
所谓抖动是指在识别被按键是必须避开抖动状态,只有处在稳定接通或稳定断开状态才能保证识别正确无误。
去抖问题可通过软件延时或硬件电路解决。
(2)防串键:
防串键是为了解决多个键同时按下或者前一按键没有释放又有新的按键按下时产生的问题。
常用的方法有双键锁定和N键轮回两种方法。
双键锁定,是当有两个或两个以上的按键按下时,只把最后释放的键当作有效键并产生相应的键码。
N键轮回,是当检测到有多个键被按下时,能根据发现它们的顺序依次产生相应键的键码。
(3)被按键识别:
如何识别被按键是接口解决的主要问题,一般可通过软硬结合的方法完成。
常用的方法有行扫描法和线反转法两种。
行扫描法的基本思想是,由程序对键盘逐行扫描,通过检测到的列输出状态来确定闭合键,为此,需要设置入口、输出口一个,该方法在微机系统中被广泛使用。
线反转法的基本思想是通过行列颠倒两次扫描来识别闭合键,为此需要提供两个可编程的双向输入/输出端口。
(4)键码产生:
为了从键的行列坐标编码得到反映键功能的键码,一般在内存区中建立一个键盘编码表,通过查表获得被按键的键码。
用AT89S51的并行口P1接4×4矩阵键盘,以P1.0-P1.3作输入线,以P1.4-P1.7作输出线。
2.1.1系统硬件连线设计
键盘模块硬件连线如图1-5所示:
(1)把“单片机系统”区域中的P3.0-P3.7端口用8芯排线连接到“4X4行列式键盘”区域中的C1-C4 R1-R4端口上;
(2)把“单片机系统”区域中的P0.0/AD0-P0.7/AD7端口用8芯排线连接到“7段数码显示模块”区域中的任一个a-h端口上;要求:
P0.0/AD0对应着a,P0.1/AD1对应着b,……,P0.7/AD7对应着h。
2.1.2按键扫描
(1)4×4矩阵键盘识别处理,每个按键有它的行值和列值,行值和列值的组合就是识别这个按键的编码。
矩阵的行线和列线分别通过两并行接口和CPU通信。
每个按键的状态同样需变成数字量“0”和“1”,开关的一端(列线)通过电阻接VCC,而接地是通过程序输出数字“0”实现的。
(2)键盘处理程序的任务是:
确定有无键按下,判断哪一个键按下,键的功能是什么;还要消除按键在闭合或断开时的抖动。
两个并行口中,一个输出扫描码,使按键逐行动态接地,另一个并行口输入按键状态,由行扫描值和回馈信号共同形成键编码而识别按键,通过软件查表,查出该键的功能。
电路图如下
图1-6矩阵键盘电路
3软件设计内容
3.1音乐产生的方法
3.1.1原理
一首音乐是许多不同的音阶组成的,而每个音阶对应着不同的频率,这样我们就可以利用不同的频率的组合,即可构成我们所想要的音乐了,当然对于单片机来产生不同的频率非常方便,我们可以利用单片机的定时/计数器T0来产生这
样方波频率信号,因此,我们只要把一首歌曲的音阶对应频率关系正确即可。
若要产生音频脉冲,只要算出某一音频的周期(1/频率),再将此周期除以2即为半周期的时间。
利用定时器计时半周期时间,每当计时终止后就将P1.0反相,然后重复计时再反相。
就可在P1.0引脚上得到此频率的脉冲。
利用AT89C51的内部定时器使其工作计数器模式(MODE1)下,改变计数值TH0及TL0以产生不同频率的方法产生不同音阶,例如,频率为523Hz,其周期T=1/523=1912μs,因此只要令计数器计时956μs/1μs=956,每计数956次时将I/O反相,就可得到中音DO(523Hz)。
计数脉冲值与频率的关系式(如式1-1所示)是:
N=fi÷2÷fr(1-1)
式中,N是计数值;fi是机器频率(晶体振荡器为12MHz时,其频率为1MHz);fr是想要产生的频率。
其计数初值T的求法如下:
T=65536-N=65536-fi÷2÷fr
例如:
设K=65536,fi=1MHz,求低音DO(262Hz)、中音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晶振,高中低音符与计数T0相关的计数值如表1-2所示
表1-2音符频率表
音符
频率(HZ)
简谱码(T值)
音符
频率(HZ)
简谱码(T值)
低1 DO
262
63628
#4FA#
740
64860
#1 DO#
277
63731
中5SO
784
64898
低2 RE
294
63835
#5SO#
831
64934
#2RE#
311
63928
中6LA
880
64968
低3M
330
64021
#6
932
64994
低4FA
349
64103
中7SI
988
65030
#4FA#
370
64185
高1DO
1046
65058
低5SO
392
64260
#1DO#
1109
65085
#5SO#
415
64331
高2RE
1175
65110
低6LA
440
64400
#2RE#
1245
65134
#6
466
64463
高3M
1318
65157
低7SI
494
64524
高4FA
1397
65178
中1DO
523
64580
#4FA#
1480
65198
#1DO#
554
64633
高5SO
1568
65217
中2RE
587
64684
#5SO#
1661
65235
#2RE#
622
64732
高6LA
1760
65252
中3M
659
64777
#6
1865
65268
中4FA
698
64820
高7SI
1967
65283
我们要为这个音符建立一个表格,单片机通过查表的方式来获得相应的数据低音0-19之间,中音在20-39之间,高音在40-59之间
TABLE:
{
63565,63781,63878,64143,64220,64365,64491,
64549,64657,64706,64839,64878,64950,65013,
65042,65096,65121,65187,65207,65243,65274,}
3.2程序框图
音乐发声程序框图如图1-8所示:
图1-8音乐发声程序框图
4全文总结
通过这次设计,我学到了不少课本上没有的知识,也锻炼了自己的动手能力,将以前学过的零散的知识串到一起。
首先在设计刚开始的调研阶段,我学会了怎么通过各种方式查询相关的资料。
通过对这些资料的学习,我大致了解了单片机的发展现状以及未来的发展趋势,认识到目前单片机方面的各种各样的发展,和它们之间的竞争。
了解了单片机方面的先进技术,这些都为我的未来的学习指明了方向。
我的设计主要涉及硬件和软件两方面的内容,通过这些我的硬件和软件开发能力都获得了提高。
首先硬件方面,基本了解了电子产品的开发流程和所要做的工作。
通过开发板的设计和硬件搭建的过程,使我对51系单片机的接口有了更深层次的理解,熟悉了一些单片机常用的外围电路引脚和连接方法,如键盘等。
在软件方面,通过串行口调试工具的开发,使我加深了对累封装的理解,熟
悉了51系列单片机内部的寄存器和编程规则,以及如何控制外围电路。
附录程序:
#include
#defineucharunsignedchar
#defineuuintunsignedint
uchartemp;
ucharnum;
uchari,j;
unsignedcharSTH0;
unsignedcharSTL0;
sbitP3_4=P3^4;
sbitP3_5=P3^5;
sbitP3_6=P3^6;
sbitP3_7=P3^7;
sbitP1_0=P1^0;
unsignedintcodetab[]={
63565,63781,63878,64143,64220,64365,64491,
64549,64657,64706,64839,64878,64950,65013,
65042,65096,65121,65187,65207,65243,65274,};
voiddelay();
ucharkeyscan();
voidmain(void)
{
TMOD=0x01;
ET0=1;
EA=1;
num=17;
while
(1)
{
keyscan();
}
}
voiddelay()
{
unsignedchari,j;
for(i=110;i>0;i--)
for(j=110;j>0;j--);
}
ucharkeyscan()
{
P3=0xfe;
temp=P3;
temp=temp&0xf0;
while(temp!
=0xf0)
{
delay();
temp=P3;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P3;
switch(temp)
{
case0xee:
num=1;
break;
case0xde:
num=2;
break;
case0xbe:
num=3;
break;
case0x7e:
num=4;
break;
}
temp=P3;
P1_0=~P1_0;
STH0=tab[num]/256;
STL0=tab[num]%256;
TR0=1;
temp=temp&0x0f;
while(temp!
=0xf0)
{
temp=P3;
temp=temp&0xf0;
}
TR0=0;
}
}
P3=0xfd;
temp=P3;
temp=temp&0xf0;
while(temp!
=0xf0)
{
delay();
temp=P3;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P3;
switch(temp)
{
case0xed:
num=5;
break;
case0xdd:
num=6;
break;
case0xbd:
num=7;
break;
case0x7d:
num=8;
break;
}
temp=P3;
P1_0=~P1_0;
STH0=tab[num]/256;
STL0=tab[num]%6;
TR0=1;
temp=temp&0x0f;
while(temp!
=0xf0)
{
temp=P3;
temp=temp&0xf0;
}
TR0=0;
}
}
P3=0xfb;
temp=P3;
temp=temp&0xf0;
while(temp!
=0xf0)
{
delay();
temp=P3;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P3;
switch(temp)
{
case0xeb:
num=9;
break;
case0xdb:
num=10;
break;
case0xbb:
num=11;
break;
case0x7b:
num=12;
break;
}
temp=P3;
P1_0=~P1_0;
STH0=tab[num]/256;
STL0=tab[num]%256;
TR0=1;
temp=temp&0x0f;
while(temp!
=0xf0)
{
temp=P3;
temp=temp&0xf0;
}
TR0=0;
}
}
P3=0xf7;
temp=P3;
temp=temp&0xf0;
while(temp!
=0xf0)
{
delay();
temp=P3;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P3;
switch(temp)
{
case0xe7:
num=13;
break;
case0xd7:
num=14;
break;
case0xb7:
num=15;
break;
case0x77:
num=16;
break;
}
temp=P3;
P1_0=~P1_0;
STH0=tab[num]/256;
STL0=tab[num]%256;
TR0=1;
temp=temp&0x0f;
while(temp!
=0xf0)
{
temp=P3;
temp=temp&0xf0;
}
TR0=0;
}
}
returnnum;
}
voidt0(void)interrupt1
{
TH0=STH0;
TL0=STL0;
P1_0=~P1_0;
}