基于单片机的数字音乐盒

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

文档来源为:从网络收集整理.word版本可编辑.欢迎下载支持.
山东建筑大学
课程设计说明书
题目:基于单片机的数字音乐盒
课程:单片机原理及应用B课程设计
院(部):信息与电气工程学院
专业:电子信息工程
班级:
学生姓名:
学号: 56
指导教师:高焕兵张君捧
完成日期:2013年6月
目录
摘要错误!未定义书签。

1 设计目的错误!未定义书签。

2 设计要求错误!未定义书签。

3 设计内容错误!未定义书签。

3.1设计原理错误!未定义书签。

3.2 方案设计错误!未定义书签。

3.3 电路各模块说明错误!未定义书签。

3.4 器件选择错误!未定义书签。

3.5.系统设计错误!未定义书签。

3.6软件设计错误!未定义书签。

3.7 仿真调试及操作说明错误!未定义书签。

总结与致谢错误!未定义书签。

参考文献错误!未定义书签。

附录错误!未定义书签。

附录一:基于单片机的数字音乐盒总电路图错误!未定义书签。

附录二:音乐程序错误!未定义书签。

摘要
20世纪末,电子技术获得了飞速的发展,在其推动下,现代电子产品几乎渗透了社会的各个领域,基于单片机制作的电子式音乐盒,控制功能强大,可根据需要选歌,使用方便。

所放歌曲的节奏可以根据需要进行设置,根据存储容量的大小,可以尽可能多的存储歌曲。

本设计由由单片机AT80C51芯片和LCD显示器为核心,辅以必要的电路,构成的一个单片机电子数字音乐盒。

本设计采用4*4键盘,用Protel99来画系统硬件图,采用C语言进行编程,编程后利用KEIL C51来进行编译,再生成的HEX文件装入芯片中,采用proteus软件来仿真,检验功能得以正常实现。

关键词:单片机;音乐盒;电路;播放
1 设计目的
《单片机原理及应用》是高校工程专业的一门专业基础课,该门课程具有很强的实践性。

通过课程的学习,使学生掌握基本概念、基本理论和基本技能。

通过本次设计使同学们掌握对单片机的控制,实现自己编程,完成专业要求。

2 设计要求
1、利用I/O口产生一定频率的方波,驱动蜂鸣器,发出不同的音调,从而演奏乐曲(最少储存三首乐曲,每首不少于30秒)
2、采用LCD显示信息
3、开机时有英文欢迎提示字符,播放时显示歌曲序号(或名称)
4、可通过功能键选择乐曲,暂停,播放
5、显示乐曲播放时间或剩余时间
3 设计内容
3.1设计原理
设计原理:通过按键给单片机的P2口输入低电平,进而利用程序来判断是否执行某一播放功能。

而利用单片机的定时器0中断来控制播放乐曲。

2
3.2 方案设计
本实验采用AT80S51单片机的I/O口产生一定频率的方波,配合键盘系统,时钟电路,复位电路以及液晶显示电路,驱动蜂鸣器,发出不同的音调,从而演奏乐曲。

共有4乐曲,每首乐曲都由相应的按键控制,并且有开关键、暂停键、上一曲以及下一曲控制键。

系统总体结构框图
3.3 电路各模块说明
此系统的时钟电路设计是采用内部方式,即是利用芯片内部的振荡电路。

利用12MHZ的晶振做外部时钟;AT80C51中有一个用于构成内部振荡器的高增益反相放大器,引脚XTAL1和XTAL2分别是该放大器的输入端和输出端。

这个放大器与作为反馈元件的片外石英晶体(陶瓷)谐振器一起构成自然振
3
荡器。

外接石英晶体及电容C1、C2接在放大器的反馈回路中构成并联振荡电路。

对外接电容C1,C2虽然没有什么严格的要求,但电容容量的大小会轻微影响振荡频率的高低、振荡器工作的稳定性、起振的难易程序及温度稳定性。

如果使用石英晶体,我们推荐电容使用30PF±10PF(而如果使用陶瓷振荡器建议选择40PF±10PF)。

其电路图如图3-3-1所示
图3-3-1
3.3.2 复位电路
51单片机的RST引脚是复位信号的输入端,复位信号是高电平有效,其有效时间应持续24个振荡脉冲周期(即二个机器周期)以上。

一般有两种复位方式:上电复位和手动复位。

复位电路图如图3-3-2所示。

4
图3-3-2
3.3.2 控制电路
键盘接口电路如图,本次设计中,按键有7个.键分别接于7根I/O线(P1口),各按键在实物连接上相互独立,彼此的工作状态互不影响,STC 单片机自带上拉电阻因此无需外接上拉电阻,用查询法完成按键功能。

其电路图如图3-3-2所示:
图3-3-2
利用PNP管放大驱动。

基极接10K欧姆的电阻,发射极接蜂鸣器,集电极接电源。

其电路图如图3-3-3所示:
5
图3-3-3
3.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所示.
6
图3-4-1 3.4.2 键盘
键盘在单片机应用系统中能实现向单片机输入数据,传送命令等功能,是人工干预单片机的主要手段。

(1)键盘输入的特点
键盘实质上是一级按键开关的集合。

通常,键盘开关利用了机械触点的合、断作用。

(2)按键的确认
键的闭合与否,反映在行线输出电压上就呈现高电平或低电平,如果高电平表示键断开,低电平则表示键闭合,通过对行线电平高低状态的检测,便可确认按键按下与否。

为了确保CPU对一次按键动作只确认一次按键有效,必须消除抖动的影响。

(3)如何消除按键的抖动
7
采用软件来消除按键抖动的基本思想是:在一次检测到有键按下时,该键所对应的行线为低电平,执行一段延时10MS的子程序后,确认该行线电平是不否仍为低电平,如果仍为低电平,则确认为该行确实有键按下。

当按键松开时,行线的低电平变为高电平,执行一段延时10MS的子程序后,检测该行线为高电平,说明按键确实已经松开。

3.4.3 LCD液晶显示
1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。

它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形。

1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。

3.5.系统设计
其系统原理图如附录一所示。

3.6软件设计
程序设计流程图如图3-6所示.
先从主程序开始,接着初始化变量及 LCD 接口,然后初始化方波发生器、晶振管,使 LCD 显示信息,就进入了开机状态,等待动作——选择按键,包括播放键,暂停键,停止键,当然也可以选择返回;加入选择的是播放键,LCD 上就会 -7-现实歌曲编号,与此同时演奏相应的乐曲,此时,你可以按
8
上一曲或下一曲键,使其演奏上一个或者先一个乐曲。

主程序流程图LCD显示流程图
其程序代码如附录二所示。

3.7 仿真调试及操作说明
按照上面设计的电路在protel软件内画图, 打开单片机软件开发系统Keil,选择80c51单片机,在其中编写程序,运行生成一个后缀名为hex的文件,然后将该文件下载到protel中的AT80c51单片机中进行仿真,观察实验现象。

仿真能实现播放音乐,按键选择曲目,暂停,播放功能。

仿真成功后,安装好实验板,然后将音乐程序下载到电路板内 ,观察结果。

能实现播放音乐,按键换曲等功能。

总结与致谢
一个星期的摸索与实验,虽然时间很短,但使我们不仅仅是对于单片机入门软件与硬件的常用设计与功能,还使我们对于一项设计研究的制作过程所需要的详细步骤和具体的实现方法的力度的掌握。

当然在这次宝贵的设计活动中,经验才是对于我们最大的收获,而且还增强了自身对未知问题以及对知识的深化认识的能力,用受益匪浅这个词语来概括这次难忘的活动我觉得再合适不过了。

但是,光是完成了作品还是不可以自我满足的,在从一开始的时候就怀着将作品制作得更加人性化,更加令人满意,更加地使功能完美又方便地被应用领域这个最终目的下,随着对单片机这门学科的认识加深,到达了拓展的程度,我想这个目的将在不远的时期内被实现。

总之,这次设计从软件编写、调试到软硬件联机调试,我们倾注了大量的时间和心血。

真是曾经为程序的编写而冥思苦想过,曾经为无法找出错误而郁闷苦恼过,也曾经为某一功能不能实现而犹豫彷徨过,但最终我们完成设计了。

至此完成课程设计,首先要感谢不畏辛辞的老师,通过老师的指导,使我增涨了单片机的知识。

其次,还要感谢我的同学,在这次课程设计中,遇到了许多的困难,是通过询问他们才解决的。

参考文献
[1] 徐峥颖编著.Protel99SE EDA 技术及应用[M].北京机械工业出版社2005.
[2] 三恒星科技.MCS-51单片机原理与应用实例[M]. 北京:电子工业出版社,2008.01
[3]王为青,程国钢.单片机Keil Cx51应用开发技术[M].北京:人民邮电出版社,2007.02
[4] 边春远编著.MCS-51单片机应用开发实用子程序[M].北京人民邮电出版社2005.
[5] 黄智伟凌阳单片机课程设计指导[M],北京:北京航空航天大学出版社,2006.11.
[6] 李广弟,朱月秀,王秀山.单片机基础[M],北京:北京航空航天大学出版社,2001.7.
[7] 康华光模拟电子技术基础第四版)[M], 武汉:华中理工大学出版社,1999.
附录
附录一:基于单片机的数字音乐盒总电路图
附录二:音乐程序
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit BEEP = P1^4; //蜂鸣器
sbit k0=P2^0;
sbit k1=P2^1;
sbit k2=P2^2;
sbit k3=P2^3;
sbit k4=P2^4;
sbit k5=P2^5;
sbit k6=P2^6;
uint code Tone_Delay_Table[] = { 64021,64103,64260,64400,64524,64580,64684,64777, 64820,64898,64968,65030,65058,65110,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,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};
uchar 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; //音符指针,延时指针
uchar 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;
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_Time;
break;
}
//从下一段音乐的第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;
}
void play1()
{ ET0=1;
TR0 = 0;
k1=1;
Song_Index = ( Song_Index + 3) % 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 = Song3_Tone;
Song_Time_Pointer = Song3_Time;
break;
case 3: Song_Tone_Pointer = Song4_Tone;
Song_Time_Pointer = Song4_Time;
break;
}
i = 0; //从上一段音乐的第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;
}
void play2()
{
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)
{
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;
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_Pointer[i];
if ( Tone_Index == 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 = 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++;
}
}
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_Pointer[i];
if ( Tone_Index == 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 = 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_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_Pointer[i];
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;
//从第二段音乐的第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;
}
void play5()
{
ET0=1;
TR0 = 0;
k5=1;
Song_Tone_Pointer = Song3_Tone; //切换到第三段音乐
Song_Time_Pointer = Song3_Time;
Song_Index=2;
//从第三段音乐的第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;
}
void play6()
{
ET0=1;
TR0 = 0;
k6=1;
Song_Tone_Pointer = Song4_Tone; //切换到第四段音乐
Song_Time_Pointer = Song4_Time;
Song_Index=3;
//从第四段音乐的第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;
}
void Timer0_Play_Music() interrupt 1 // T0 定时器控制播放{
TH0 = Tone_Delay_Table[ Tone_Index ] / 256;
TL0 = Tone_Delay_Table[ Tone_Index ] % 256;
BEEP = ~BEEP;
}
void main() // 主程序
{
TMOD = 0x01;
IE = 0x82; //许可INTO 和TO 中断
TR0 = 0;
while(1)
{
if(k0==0&&k==1) { DelayMS(2000); play0();m=1;}
if(k1==0&&k==1) { DelayMS(2000); play1();m=1;}
if(k2==0) { DelayMS(2000); play2();}
if(k3==0&&k==1) { DelayMS(2000); play3();m=1;}
if(k4==0&&k==1) { DelayMS(2000); play4();m=1;}
if(k5==0&&k==1) { DelayMS(2000); play5();m=1;}
if(k6==0&&k==1) { DelayMS(2000); play6();m=1;}
}
}。

相关文档
最新文档