基于单片机的数字音乐盒Word文档下载推荐.docx
《基于单片机的数字音乐盒Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《基于单片机的数字音乐盒Word文档下载推荐.docx(21页珍藏版)》请在冰豆网上搜索。
1设计目的
《单片机原理及应用》是高校工程专业的一门专业基础课,该门课程具有很强的实践性。
通过课程的学习,使学生掌握基本概念、基本理论和基本技能。
通过本次设计使同学们掌握对单片机的控制,实现自己编程,完成专业要求。
2设计要求
1、利用I/O口产生一定频率的方波,驱动蜂鸣器,发出不同的音调,从而演奏乐曲(最少储存三首乐曲,每首不少于30秒)
2、采用LCD显示信息
3、开机时有英文欢迎提示字符,播放时显示歌曲序号(或名称)
4、可通过功能键选择乐曲,暂停,播放
5、显示乐曲播放时间或剩余时间
3设计内容
3.1设计原理
设计原理:
通过按键给单片机的P2口输入低电平,进而利用程序来判断是否执行某一播放功能。
而利用单片机的定时器0中断来控制播放乐曲。
3.2方案设计
本实验采用AT80S51单片机的I/O口产生一定频率的方波,配合键盘系统,时钟电路,复位电路以及液晶显示电路,驱动蜂鸣器,发出不同的音调,从而演奏乐曲。
共有4乐曲,每首乐曲都由相应的按键控制,并且有开关键、暂停键、上一曲以及下一曲控制键。
系统总体结构框图
3.3电路各模块说明
3.3.1时钟电路
此系统的时钟电路设计是采用内部方式,即是利用芯片内部的振荡电路。
利用12MHZ的晶振做外部时钟;
AT80C51中有一个用于构成内部振荡器的高增益反相放大器,引脚XTAL1和XTAL2分别是该放大器的输入端和输出端。
这个放大器与作为反馈元件的片外石英晶体(陶瓷)谐振器一起构成自然振荡器。
外接石英晶体及电容C1、C2接在放大器的反馈回路中构成并联振荡电路。
对外接电容C1,C2虽然没有什么严格的要求,但电容容量的大小会轻微影响振荡频率的高低、振荡器工作的稳定性、起振的难易程序及温度稳定性。
如果使用石英晶体,我们推荐电容使用30PF
10PF(而如果使用陶瓷振荡器建议选择40PF
10PF)。
其电路图如图3-3-1所示
图3-3-1
3.3.2复位电路
51单片机的RST引脚是复位信号的输入端,复位信号是高电平有效,其有效时间应持续24个振荡脉冲周期(即二个机器周期)以上。
一般有两种复位方式:
上电复位和手动复位。
复位电路图如图3-3-2所示。
图3-3-2
3.3.2控制电路
键盘接口电路如图,本次设计中,按键有7个.键分别接于7根I/O线(P1口),各按键在实物连接上相互独立,彼此的工作状态互不影响,STC单片机自带上拉电阻因此无需外接上拉电阻,用查询法完成按键功能。
其电路图如图3-3-2所示:
3.3.3蜂鸣器电路:
利用PNP管放大驱动。
基极接10K欧姆的电阻,发射极接蜂鸣器,集电极接电源。
其电路图如图3-3-3所示:
图3-3-3
3.4器件选择
3.4.180C51单片机简介
该系列单片机是采用高性能的静态80C51设计由先进CMOS工艺制造并带有非易失性Flash程序存储器全部支持12时钟和6时钟操作P89C51X2和P89C52X2/54X2/58X2分别包含128字节和256字节RAM32条I/O口线3个16位定时/计数器6输入4优先级嵌套中断结构1个串行I/O口可用于多机通信I/O扩展或全双工UART以及片内振荡器和时钟电路。
外形及引脚排列如图3-4-1所示.
图3-4-1
3.4.2键盘
键盘在单片机应用系统中能实现向单片机输入数据,传送命令等功能,是人工干预单片机的主要手段。
(1)键盘输入的特点
键盘实质上是一级按键开关的集合。
通常,键盘开关利用了机械触点的合、断作用。
(2)按键的确认
键的闭合与否,反映在行线输出电压上就呈现高电平或低电平,如果高电平表示键断开,低电平则表示键闭合,通过对行线电平高低状态的检测,便可确认按键按下与否。
为了确保CPU对一次按键动作只确认一次按键有效,必须消除抖动的影响。
(3)如何消除按键的抖动
采用软件来消除按键抖动的基本思想是:
在一次检测到有键按下时,该键所对应的行线为低电平,执行一段延时10MS的子程序后,确认该行线电平是不否仍为低电平,如果仍为低电平,则确认为该行确实有键按下。
当按键松开时,行线的低电平变为高电平,执行一段延时10MS的子程序后,检测该行线为高电平,说明按键确实已经松开。
3.4.3LCD液晶显示
1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。
它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形。
1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。
3.5.系统设计
其系统原理图如附录一所示。
3.6软件设计
程序设计流程图如图3-6所示.
先从主程序开始,接着初始化变量及LCD接口,然后初始化方波发生器、晶振管,使LCD显示信息,就进入了开机状态,等待动作——选择按键,包括播放键,暂停键,停止键,当然也可以选择返回;
加入选择的是播放键,LCD上就会-7-现实歌曲编号,与此同时演奏相应的乐曲,此时,你可以按上一曲或下一曲键,使其演奏上一个或者先一个乐曲。
主程序流程图LCD显示流程图
其程序代码如附录二所示。
3.7仿真调试及操作说明
按照上面设计的电路在protel软件内画图,打开单片机软件开发系统Keil,选择80c51单片机,在其中编写程序,运行生成一个后缀名为hex的文件,然后将该文件下载到protel中的AT80c51单片机中进行仿真,观察实验现象。
仿真能实现播放音乐,按键选择曲目,暂停,播放功能。
仿真成功后,安装好实验板,然后将音乐程序下载到电路板内,观察结果。
能实现播放音乐,按键换曲等功能。
总结与致谢
一个星期的摸索与实验,虽然时间很短,但使我们不仅仅是对于单片机入门软件与硬件的常用设计与功能,还使我们对于一项设计研究的制作过程所需要的详细步骤和具体的实现方法的力度的掌握。
当然在这次宝贵的设计活动中,经验才是对于我们最大的收获,而且还增强了自身对未知问题以及对知识的深化认识的能力,用受益匪浅这个词语来概括这次难忘的活动我觉得再合适不过了。
但是,光是完成了作品还是不可以自我满足的,在从一开始的时候就怀着将作品制作得更加人性化,更加令人满意,更加地使功能完美又方便地被应用领域这个最终目的下,随着对单片机这门学科的认识加深,到达了拓展的程度,我想这个目的将在不远的时期内被实现。
总之,这次设计从软件编写、调试到软硬件联机调试,我们倾注了大量的时间和心血。
真是曾经为程序的编写而冥思苦想过,曾经为无法找出错误而郁闷苦恼过,也曾经为某一功能不能实现而犹豫彷徨过,但最终我们完成设计了。
至此完成课程设计,首先要感谢不畏辛辞的老师,通过老师的指导,使我增涨了单片机的知识。
其次,还要感谢我的同学,在这次课程设计中,遇到了许多的困难,是通过询问他们才解决的。
参考文献
[1]徐峥颖编著.Protel99SEEDA技术及应用[M].北京机械工业出版社2005.
[2]三恒星科技.MCS-51单片机原理与应用实例[M].北京:
电子工业出版社,2008.01
[3]王为青,程国钢.单片机KeilCx51应用开发技术[M].北京:
人民邮电出版社,2007.02
[4]边春远编著.MCS-51单片机应用开发实用子程序[M].北京人民邮电出版社2005.
[5]黄智伟凌阳单片机课程设计指导[M],北京:
北京航空航天大学出版社,2006.11.
[6]李广弟,朱月秀,王秀山.单片机基础[M],北京:
北京航空航天大学出版社,2001.7.
[7]康华光模拟电子技术基础第四版)[M],武汉:
华中理工大学出版社,1999.
附录
附录一:
基于单片机的数字音乐盒总电路图
附录二:
音乐程序
#include<
reg52.h>
#defineucharunsignedchar
#defineuintunsignedint
sbitBEEP=P1^4;
//蜂鸣器
sbitk0=P2^0;
sbitk1=P2^1;
sbitk2=P2^2;
sbitk3=P2^3;
sbitk4=P2^4;
sbitk5=P2^5;
sbitk6=P2^6;
uintcodeTone_Delay_Table[]={64021,64103,64260,64400,64524,64580,64684,64777,64820,64898,64968,65030,65058,65110,65157,65178};
ucharcodeSong1_Tone[]={1,1,5,5,6,6,5,4,4,3,3,2,2,1,5,5,4,4,3,3,2,5,5,4,4,3,3,2,1,1,5,5,6,6,5,4,4,3,3,2,2,1,0xff};
ucharcodeSong1_Time[]={2,2,2,2,2,3,4,2,2,2,2,2,2,4,2,2,2,2,2,2,4,2,2,2,2,2,2,5,2,2,2,2,2,2,5,2,2,2,2,2,2,5,0xff};
ucharcodeSong2_Tone[]={1,2,3,1,1,2,3,1,3,4,5,3,4,5,5,6,5,4,3,1,5,6,5,4,3,1,1,5,1,0xff};
ucharcodeSong2_Time[]={2,2,3,2,2,2,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,0xff};
ucharcodeSong3_Tone[]={1,3,3,3,3,5,4,2,5,3,7,6,5,5,7,4,4,3,6,7,2,1,0xFF};
ucharcodeSong3_Time[]={2,1,1,2,1,1,1,2,1,1,3,2,1,1,2,4,1,1,2,1,1,1,0xFF};
ucharcodeSong4_Tone[]={8,9,2,3,7,6,2,3,10,11,1,2,3,1,2,3,3,4,5,6,5,3,5,6,5,3,5,3,2,1,1,2,3,0xFF};
ucharcodeSong4_Time[]={3,6,7,2,4,5,8,1,2,2,5,5,1,9,1,1,1,1,6,1,1,2,4,1,1,2,1,1,1,1,1,2,2,1,0xFF};
ucharSong_Index=0,Tone_Index=0;
//音乐片段索引,音符索引
uchar*Song_Tone_Pointer,*Song_Time_Pointer;
//音符指针,延时指针
uchari=0;
ucharj=0,k=0,m=0;
//从当前数组中取音符的位置
voidDelayMS(uintms)//延时
{
uchart;
while(ms--)for(t=0;
t<
120;
t++);
}
voidplay0()//按键产生的INT0
{ET0=1;
TR0=0;
k0=1;
Song_Index=(Song_Index+1)%4;
//切换到下一音乐
switch(Song_Index)
{
case0:
Song_Tone_Pointer=Song1_Tone;
Song_Time_Pointer=Song1_Time;
break;
case1:
Song_Tone_Pointer=Song2_Tone;
Song_Time_Pointer=Song2_Time;
case2:
Song_Tone_Pointer=Song3_Tone;
Song_Time_Pointer=Song3_Time;
case3:
Song_Tone_Pointer=Song4_Tone;
Song_Time_Pointer=Song4_Time;
}
//从下一段音乐的第0个音符开始
i=0;
while(k0==1&
&
k1==1&
k2==1&
k3==1&
k4==1&
k5==1&
k6==1)
Tone_Index=Song_Tone_Pointer[i];
if(Tone_Index==0xFF)
{
i=0;
DelayMS(2000);
//每段音乐播放结束后停顿一段时间
continue;
//继续播放
}
TR0=1;
DelayMS(Song_Time_Pointer[Tone_Index]*240);
TR0=0;
i++;
return;
voidplay1()
k1=1;
Song_Index=(Song_Index+3)%4;
//切换到上一段音乐
switch(Song_Index)
//从上一段音乐的第0个音符开始
while(k0==1&
voidplay2()
{
m=!
m;
TR0=0;
k2=1;
if(m==0)
{j=1;
TR0=0;
ET0=0;
}
if(m==1)
{ET0=1;
k=1;
if(j==1)//播放被暂停的音乐
switch(Song_Index)
case0:
Song_Time_Pointer=Song1_Time;
break;
case1:
Song_Time_Pointer=Song2_Time;
case2:
Song_Time_Pointer=Song3_Time;
case3:
Song_Time_Pointer=Song4_Time;
//从本一段音乐的第i个音符开始
while(k0==1&
Tone_Index=Song_Tone_Pointer[i];
if(Tone_Index==0xFF)
{
i=0;
DelayMS(2000);
Song_Index=(Song_Index+1)%4;
//播放下一首音乐
switch(Song_Index)
case0:
Song_Time_Pointer=Song1_Time;
break;
case1:
case2:
Song_Time_Pointer=Song3_Time;
case3:
Song_Time_Pointer=Song4_Time;
if(j==0)
{j=1;
Song_Tone_Pointer=Song1_Tone;
//开始播放音乐
i=0;
while(k0==1&
Tone_Index=Song_Tone_Pointer[i];
if(Tone_Index==0xFF)
//播放下一段音乐
break;
Song_Time_Pointer=Song3_Time;
continue;
TR0=1;
DelayMS(Song_Time_Pointer[Tone_Index]*240);
TR0=0;
i++;
return;
voidplay3()
k3=1;
//切换到第一段音乐
Song_Tone_Pointer=Song1_Tone;
Song_Time_Pointer=Song1_Time;
Song_Index=0;
//从第一段音乐的第0个音符开始
voidplay4()
ET0=1;
k4=1;
//切换到第二段音乐
Song_Time_Pointer=Song2_Time;
Song_Index=1;
i=0;
//