1、基于单片机的数字音乐盒山东建筑大学课 程 设 计 说 明 书题 目: 基于单片机的数字音乐盒课 程: 单片机原理及应用B课程设计院 (部): 信息与电气工程学院专 业: 电子信息工程班 级: 学生姓名: 学 号: 指导教师: 高焕兵 张君捧完成日期: 2013年6月摘 要20世纪末,电子技术获得了飞速的发展,在其推动下,现代电子产品几乎渗透了社会的各个领域,基于单片机制作的电子式音乐盒,控制功能强大,可根据需要选歌,使用方便。所放歌曲的节奏可以根据需要进行设置,根据存储容量的大小,可以尽可能多的存储歌曲。本设计由由单片机AT80C51芯片和LCD显示器为核心,辅以必要的电路,构成的一个单片机电
2、子数字音乐盒。本设计采用4*4键盘,用Protel99来画系统硬件图,采用C语言进行编程,编程后利用KEIL C51来进行编译,再生成的HEX文件装入芯片中,采用proteus软件来仿真,检验功能得以正常实现。关键词:单片机;音乐盒;电路;播放1 设计目的单片机原理及应用是高校工程专业的一门专业基础课,该门课程具有很强的实践性。通过课程的学习,使学生掌握基本概念、基本理论和基本技能。通过本次设计使同学们掌握对单片机的控制,实现自己编程,完成专业要求。2 设计要求1、利用I/O口产生一定频率的方波,驱动蜂鸣器,发出不同的音调,从而演奏乐曲(最少储存三首乐曲,每首不少于30秒)2、采用LCD显示信
3、息3、开机时有英文欢迎提示字符,播放时显示歌曲序号(或名称)4、可通过功能键选择乐曲,暂停,播放 5、显示乐曲播放时间或剩余时间3 设计内容3.1设计原理 设计原理:通过按键给单片机的P2口输入低电平,进而利用程序来判断是否执行某一播放功能。而利用单片机的定时器0中断来控制播放乐曲。3.2 方案设计本实验采用AT80S51单片机的I/O口产生一定频率的方波,配合键盘系统,时钟电路,复位电路以及液晶显示电路,驱动蜂鸣器,发出不同的音调,从而演奏乐曲。共有4乐曲,每首乐曲都由相应的按键控制,并且有开关键、暂停键、上一曲以及下一曲控制键。系统总体结构框图 3.3 电路各模块说明3.3.1时钟电路此系
4、统的时钟电路设计是采用内部方式,即是利用芯片内部的振荡电路。利用12MHZ的晶振做外部时钟;AT80C51中有一个用于构成内部振荡器的高增益反相放大器,引脚XTAL1和XTAL2分别是该放大器的输入端和输出端。这个放大器与作为反馈元件的片外石英晶体(陶瓷)谐振器一起构成自然振荡器。外接石英晶体及电容C1、C2接在放大器的反馈回路中构成并联振荡电路。对外接电容C1,C2虽然没有什么严格的要求,但电容容量的大小会轻微影响振荡频率的高低、振荡器工作的稳定性、起振的难易程序及温度稳定性。如果使用石英晶体,我们推荐电容使用30PF10PF(而如果使用陶瓷振荡器建议选择40PF10PF)。其电路图如图3-
5、3-1所示图3-3-13.3.2 复位电路51单片机的RST引脚是复位信号的输入端,复位信号是高电平有效,其有效时间应持续24个振荡脉冲周期(即二个机器周期)以上。一般有两种复位方式:上电复位和手动复位。复位电路图如图3-3-2所示。图3-3-23.3.2 控制电路键盘接口电路如图,本次设计中,按键有7个.键分别接于7根I/O线(P1口),各按键在实物连接上相互独立,彼此的工作状态互不影响,STC单片机自带上拉电阻因此无需外接上拉电阻,用查询法完成按键功能。其电路图如图3-3-2所示:图3-3-23.3.3蜂鸣器电路:利用PNP管放大驱动。基极接10K欧姆的电阻,发射极接蜂鸣器,集电极接电源。
6、其电路图如图3-3-3所示:图3-3-33.4 器件选择3.4.1 80C51单片机简介该系列单片机是采用高性能的静态80C51 设计 由先进CMOS 工艺制造并带有非易失性Flash 程序存储器 全部支持12 时钟和6 时钟操作 P89C51X2 和P89C52X2/54X2/58X2 分别包含128 字节和256 字节RAM 32 条I/O 口线 3 个16 位定时/计数器 6 输入4 优先级嵌套中断结构 1 个串行I/O 口 可用于多机通信 I/O 扩展或全双工UART以及片内振荡器和时钟电路。外形及引脚排列如图3-4-1所示. 图3-4-13.4.2 键盘 键盘在单片机应用系统中能实现
7、向单片机输入数据,传送命令等功能,是人工干预单片机的主要手段。(1)键盘输入的特点键盘实质上是一级按键开关的集合。通常,键盘开关利用了机械触点的合、断作用。(2)按键的确认键的闭合与否,反映在行线输出电压上就呈现高电平或低电平,如果高电平表示键断开,低电平则表示键闭合,通过对行线电平高低状态的检测,便可确认按键按下与否。为了确保CPU对一次按键动作只确认一次按键有效,必须消除抖动的影响。(3)如何消除按键的抖动采用软件来消除按键抖动的基本思想是:在一次检测到有键按下时,该键所对应的行线为低电平,执行一段延时10MS的子程序后,确认该行线电平是不否仍为低电平,如果仍为低电平,则确认为该行确实有键
8、按下。当按键松开时,行线的低电平变为高电平,执行一段延时10MS的子程序后,检测该行线为高电平,说明按键确实已经松开。3.4.3 LCD液晶显示1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形。1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。3.5系统设计其系统原理图如附录一所示。3.6软件设计程序设计流程图如图3-
9、6所示. 先从主程序开始,接着初始化变量及 LCD 接口,然后初始化方波发生器、晶振管,使 LCD 显示信息,就进入了开机状态,等待动作选择按键,包括播放键,暂停键,停止键,当然也可以选择返回;加入选择的是播放键,LCD 上就会 -7-现实歌曲编号,与此同时演奏相应的乐曲,此时,你可以按上一曲或下一曲键,使其演奏上一个或者先一个乐曲。主程序流程图 LCD显示流程图其程序代码如附录二所示。3.7 仿真调试及操作说明按照上面设计的电路在protel软件内画图, 打开单片机软件开发系统Keil,选择80c51单片机,在其中编写程序,运行生成一个后缀名为hex的文件,然后将该文件下载到protel中的
10、AT80c51单片机中进行仿真,观察实验现象。仿真能实现播放音乐,按键选择曲目,暂停,播放功能。仿真成功后,安装好实验板,然后将音乐程序下载到电路板内 ,观察结果。能实现播放音乐,按键换曲等功能。总结与致谢一个星期的摸索与实验,虽然时间很短,但使我们不仅仅是对于单片机入门软件与硬件的常用设计与功能,还使我们对于一项设计研究的制作过程所需要的详细步骤和具体的实现方法的力度的掌握。当然在这次宝贵的设计活动中,经验才是对于我们最大的收获,而且还增强了自身对未知问题以及对知识的深化认识的能力,用受益匪浅这个词语来概括这次难忘的活动我觉得再合适不过了。但是,光是完成了作品还是不可以自我满足的,在从一开始
11、的时候就怀着将作品制作得更加人性化,更加令人满意,更加地使功能完美又方便地被应用领域这个最终目的下,随着对单片机这门学科的认识加深,到达了拓展的程度,我想这个目的将在不远的时期内被实现。总之,这次设计从软件编写、调试到软硬件联机调试,我们倾注了大量的时间和心血。真是曾经为程序的编写而冥思苦想过,曾经为无法找出错误而郁闷苦恼过,也曾经为某一功能不能实现而犹豫彷徨过,但最终我们完成设计了。至此完成课程设计,首先要感谢不畏辛辞的老师,通过老师的指导,使我增涨了单片机的知识。其次,还要感谢我的同学,在这次课程设计中,遇到了许多的困难,是通过询问他们才解决的。 参考文献1 徐峥颖编著.Protel99S
12、E EDA 技术及应用M.北京 机械工业出版社 2005.2 三恒星科技.MCS-51单片机原理与应用实例M. 北京:电子工业出版社,2008.013 王为青,程国钢.单片机Keil Cx51应用开发技术M. 北京:人民邮电出版社,2007.024 边春远编著.MCS-51单片机应用开发实用子程序M.北京 人民邮电出版社 2005.5 黄智伟凌阳单片机课程设计指导M,北京:北京航空航天大学出版社,2006.11. 6 李广弟,朱月秀,王秀山.单片机基础M,北京:北京航空航天大学出版社,2001.7. 7 康华光模拟电子技术基础第四版)M, 武汉:华中理工大学出版社,1999.附录附录一:基于单
13、片机的数字音乐盒总电路图附录二:音乐程序#include #define uchar unsigned char#define uint unsigned intsbit BEEP = P14; /蜂鸣器sbit k0=P20;sbit k1=P21;sbit k2=P22;sbit k3=P23;sbit k4=P24;sbit k5=P25;sbit k6=P26;uint code Tone_Delay_Table = 64021,64103,64260,64400,64524,64580,64684,64777, 64820,64898,64968,65030,65058,65110,
14、65157,65178 ;uchar code Song1_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;uchar code Song1_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;uchar code Song2_Tone=1,2,3,1
15、,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;uchar code Song2_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; uchar code Song3_Tone = 1,3,3,3,3,5,4,2,5,3,7,6,5,5,7,4,4,3,6,7,2,1,0xFF; uchar code Song3_Time = 2,1,1,2,1,1,1,2,1,1,3,2,1,1,2,4,1,1,2,1,1,1,0xFF; uch
16、ar code Song4_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; uchar code Song4_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;uchar Song_Index = 0, Tone_Index = 0; /音乐片段索引,音符索引uchar *Song_Tone_Pointer, *Song_Time_Pointer; /音符指针,延时指针uc
17、har i = 0; uchar j=0,k=0,m=0; /从当前数组中取音符的位置 void DelayMS(uint ms) /延时 uchar t; while(ms-) for (t = 0; t 120; t+); void play0() /按键产生的INT0 ET0=1; TR0 = 0; k0=1; Song_Index = ( Song_Index + 1) % 4; /切换到下一音乐 switch (Song_Index) case 0: Song_Tone_Pointer = Song1_Tone; Song_Time_Pointer = Song1_Time; bre
18、ak; case 1: Song_Tone_Pointer = Song2_Tone; Song_Time_Pointer = Song2_Time; break; case 2: Song_Tone_Pointer = Song3_Tone; Song_Time_Pointer = Song3_Time; break; case 3: Song_Tone_Pointer = Song4_Tone; Song_Time_Pointer = Song4_Time; break; /从下一段音乐的第0个音符开始 i = 0; while (k0=1&k1=1&k2=1&k3=1&k4=1&k5=1
19、&k6=1) Tone_Index = Song_Tone_Pointeri; if ( Tone_Index = 0xFF ) i = 0; DelayMS(2000); /每段音乐播放结束后停顿一段时间 continue; /继续播放 TR0 = 1; DelayMS( Song_Time_Pointer Tone_Index * 240); TR0 = 0; i+; return; void play1() ET0=1; TR0 = 0; k1=1; Song_Index = ( Song_Index + 3) % 4; /切换到上一段音乐 switch (Song_Index) cas
20、e 0: Song_Tone_Pointer = Song1_Tone; Song_Time_Pointer = Song1_Time; break; case 1: Song_Tone_Pointer = Song2_Tone; Song_Time_Pointer = Song2_Time; break; case 2: Song_Tone_Pointer = Song3_Tone; Song_Time_Pointer = Song3_Time; break; case 3: Song_Tone_Pointer = Song4_Tone; Song_Time_Pointer = Song4_
21、Time; break; i = 0; /从上一段音乐的第0个音符开始 while (k0=1&k1=1&k2=1&k3=1&k4=1&k5=1&k6=1) Tone_Index = Song_Tone_Pointeri; if ( Tone_Index = 0xFF ) i = 0; DelayMS(2000); /每段音乐播放结束后停顿一段时间 continue; /继续播放 TR0 = 1; DelayMS( Song_Time_Pointer Tone_Index * 240); TR0 = 0; i+; return; void play2() m=!m; TR0 = 0; k2=1
22、; if(m=0) j=1; TR0=0; ET0=0; if(m=1) ET0=1; k=1; if(j=1) /播放被暂停的音乐 switch (Song_Index) case 0: Song_Tone_Pointer = Song1_Tone; Song_Time_Pointer = Song1_Time; break; case 1: Song_Tone_Pointer = Song2_Tone; Song_Time_Pointer = Song2_Time; break; case 2: Song_Tone_Pointer = Song3_Tone; Song_Time_Point
23、er = Song3_Time; break; case 3: Song_Tone_Pointer = Song4_Tone; Song_Time_Pointer = Song4_Time; break; /从本一段音乐的第i个音符开始 while (k0=1&k1=1&k2=1&k3=1&k4=1&k5=1&k6=1) Tone_Index = Song_Tone_Pointeri; if ( Tone_Index = 0xFF ) i = 0; DelayMS(2000); /每段音乐播放结束后停顿一段时间 Song_Index = ( Song_Index + 1) % 4; /播放下一
24、首音乐 switch (Song_Index) case 0: Song_Tone_Pointer = Song1_Tone; Song_Time_Pointer = Song1_Time; break; case 1: Song_Tone_Pointer = Song2_Tone; Song_Time_Pointer = Song2_Time; break; case 2: Song_Tone_Pointer = Song3_Tone; Song_Time_Pointer = Song3_Time; break; case 3: Song_Tone_Pointer = Song4_Tone;
25、 Song_Time_Pointer = Song4_Time; break; continue; TR0 = 1; DelayMS( Song_Time_Pointer Tone_Index * 240); TR0 = 0; i+; if (j=0) j=1; Song_Tone_Pointer = Song1_Tone; /开始播放音乐 Song_Time_Pointer = Song1_Time; i = 0; while (k0=1&k1=1&k2=1&k3=1&k4=1&k5=1&k6=1) Tone_Index = Song_Tone_Pointeri; if ( Tone_Ind
26、ex = 0xFF ) i = 0; DelayMS(2000); /每段音乐播放结束后停顿一段时间 Song_Index = ( Song_Index + 1) % 4; /播放下一段音乐 switch (Song_Index) case 0: Song_Tone_Pointer = Song1_Tone; Song_Time_Pointer = Song1_Time; break; case 1: Song_Tone_Pointer = Song2_Tone; Song_Time_Pointer = Song2_Time; break; case 2: Song_Tone_Pointer
27、= Song3_Tone; Song_Time_Pointer = Song3_Time; break; case 3: Song_Tone_Pointer = Song4_Tone; Song_Time_Pointer = Song4_Time; break; continue; TR0 = 1; DelayMS( Song_Time_Pointer Tone_Index * 240); TR0 = 0; i+; return; void play3() ET0=1; TR0 = 0; k3=1; /切换到第一段音乐 Song_Tone_Pointer = Song1_Tone; Song_
28、Time_Pointer = Song1_Time; Song_Index=0; /从第一段音乐的第0个音符开始 i = 0; while (k0=1&k1=1&k2=1&k3=1&k4=1&k5=1&k6=1) Tone_Index = Song_Tone_Pointeri; if ( Tone_Index = 0xFF ) i = 0; DelayMS(2000); /每段音乐播放结束后停顿一段时间 continue; /继续播放 TR0 = 1; DelayMS( Song_Time_Pointer Tone_Index * 240); TR0 = 0; i+; return; void play4() ET0=1; TR0 = 0; k4=1; Song_Tone_Pointer = Song2_Tone; /切换到第二段音乐 Song_Time_Pointer = Song2_Time; Song_Index=1 ; i=0; /
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1