西北师范大学知行学院
计算机与电子信息工程系
课程设计报告书
课程名称: 单片机程序设计
专 业: 电子信息工程
课题名称: 基于单片机的音乐播放器设计 班 级: 12电本班
学 号: [1**********]4
姓 名: 窦红莉
指导教师: 胡亚琦
二○一四 ——二○一五 学年 第一学期
基于单片机的音乐播放器设计
一 、实验题目
基于单片机的音乐播放器设计
二、实验内容
本设计是一个基于AT89C51系列单片机的音乐播放器,依据单片机技术原理,通过硬件电路制作以及软件编译,设计制作出一个多功能多功能音乐播放器。该音乐播放器主要由按键电路、复位电路、时钟电路以及蜂鸣器组成。使用两个按键控制音乐播放器,一个用来切换歌曲,另一个用来切换8路LED 的变化花样,本音乐盒共有两首歌曲,花样灯花样共计3种。播放歌曲时,蜂鸣器发出某个音调,与之对应的LED 亮起。本设计利用KEIL 编程软件对音乐播放器源程序进行编程并调试,配合PROTEUS 仿真软件对硬件进行仿真调试,节约了设计时间。
【关键字】
音乐盒;AT89C51单片机; KEIL ; PROTEUS ;音调
三 、设计目的
1、设计方案
设计一个基于AT89C51系列单片机的音乐播放器,利用按键切换演奏出不同的乐曲。蜂鸣器发出某个音调,与之相对应的LED 亮起。使用两个按键,一个用来切换歌曲,另一个切换八路LED 的变化花样。
2、研究内容
1)电路有两种工作模式:演奏音乐模式和花样灯模式。演奏音乐模式:演奏完整的一首的歌曲,八路LED 随着音乐变化。花样灯模式:八路LED 变化出各种花样,蜂鸣器随着发出“嘀嘀”声
2)按下按键1进入演奏音乐模式,再按切换歌曲,共两首歌曲。
3)按下按键2进入花样灯模式,再按切换LED 花样,共三种花样。此电路的程序只占用了1K 左右,可编制更多的音乐和LED 花样,使系统的功能更加强大。
3、设计原理
1)系统组成框图音乐播放器的系统结构以AT89C51单片机位控制核心,加上2个按键、时钟复位电路、蜂鸣器、LED 模块组成。单片机负责接收按键的输入,根据输入控制音乐播放曲目和音乐花样灯的显示样式以及蜂鸣器发音。系统组成框图如图2.1所示。
2)音乐盒的功能结构图
音乐播放器的功能结构如图2.2所示。Key1负责切换播放歌曲,播
放歌曲共2首,分别是千年之恋和寂寞沙洲冷。Key2负责切换LED 显示花样,显示花样共3种,第一种顺序显示,第二种由两边向中间移动然后向两边移动,第三种循环显示。
3)硬件设计
四、总体设计框图
五、调试
5.1检查硬件连接
在PROTUES 检查各硬件管脚是否连接正确,线路逻辑是否正确,例如:晶振电路的连接,复位电路是否设计正确。
5.2 检查软件系统
1.根据系统的原理结构检查各流程图是否正确,再根据流程图来检查程序是否也正确。
2.将所有程序组织起来,在软件环境下运行,检查程序是否正确。通过对硬件和软件系统的认真检查,反复测试,如果没有出现问题即可把源程序编译成HEX 文件装载到单片机中,对硬件进行仿真。
5.3 测试结果
5.3.1.总体运行图
5.3.2.花样灯3种花样图
由于截图只能看到静态图,不能看到整体图样,下面画图说明:
(1)第一种花样灯显示方式为:从D1移向D2,然后D1熄灭,再从D2移向D3,然后D2熄灭,以此类推,往复循环。
(2)第二种花样灯显示方式为:从两边向中间移动,首先从D1移向D8,再从D8移向D2,以此类推,往复循环。具体如图5.3。
(3)第三种花样灯显示方式为:从D1移向D2,然后D1熄灭,再从D2移向D3,然后D2熄灭,以此往复循环。与第一种方式的不同之处为:当D1移向D2时,D1不熄灭,再从D2移向D3时,D2也不熄灭,以此类推。
六、实验程序
#include
#define uchar unsigned char
#define uint unsigned int
sbit duan=P2^6;
sbit key1=P3^2;//按key1可切换花样
sbit key2=P3^3;//按key2可切换歌曲
sbit fm=P0^7;//蜂鸣器连续的IO 口
sbit P34=P3^4;//矩阵键盘的一列
uchar code huayang1[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe, 0xfd,0xfb,0xf7,0xef,0xdf,0xbf};//花样1
uchar code huayang2[]={0x7f,0xfe,0xbf,0xfd,0xdf,0xfb,0xef,0xf7, 0xef,0xfb,0xdf,0xfd,0xbf,0xfe};//花样2
uchar code huayang3[]={0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01,0x0, 0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};
c har code huayang4[]={ 0x55,0xaa,0xcc,0x33,0x99,0x66,0x0f,0xf0}; uchar count1;//花样标志
uchar count2;//歌曲标志
uchar timeh,timel,i;
//---------------------------简谱--------------------------------------- //编程规则字节高位是简谱, 低位是持续时间,
//代表多少个十六分音符
//1-7代表中央C 调,8-E 代表高八度,0代表停顿
//最后的0是结束标志
uchar code qnzl[]={ //千年之恋
0x12,0x22,0x34,0x84,0x74,0x54,0x38,0x42,0x32,0x22,0x42,0x34,0x84, 0x72,0x82,0x94,0xA8,0x08,
//前奏
0x32,0x31,0x21,0x32,0x52,0x32,0x31,0x21,0x32,0x62,
//竹林的灯火到过的沙漠
0x32,0x31,0x21,0x32,0x82,0x71,0x81,0x71,0x51,0x32,0x22, //七色的国度不断飘逸风中
0x32,0x31,0x21,0x32,0x52,0x32,0x31,0x21,0x32,0x62,
//有一种神秘灰色的旋涡
0x32,0x31,0x21,0x32,0x83,0x82,0x71,0x72,0x02,
//将我卷入了迷雾中
0x63,0xA1,0xA2,0x62,0x92,0x82,0x52,
//看不清的双手
0x31,0x51,0x63,0x51,0x63,0x51,0x63,0x51,0x62,0x82,0x7C,0x02, //一朵花传来谁经过的温柔
0x61,0x71,0x82,0x71,0x62,0xA2,0x71,0x76,
//穿越千年的伤痛
0x61,0x71,0x82,0x71,0x62,0x52,0x31,0x36,
//只为求一个结果
//你留下的轮廓指引我
0x42,0x63,0x83,0x83,0x91,0x91,
//黑夜中不寂寞
0x61,0x71,0x82,0x71,0x62,0x0A2,0x71,0x76,
//穿越千年的哀愁
0x61,0x71,0x82,0x71,0x62,0x52,0x31,0x36,
//是你在尽头等我
0x61,0x71,0x82,0x71,0x62,0xA3,0x73,0x62,0x53,
//最美丽的感动会值得
0x42,0x82,0x88,0x02,0x74,0x93,0x89,0xff//结束标志
//用一生守候
};
uchar code jmszl[]={ //寂寞沙洲冷
0x12,0x12,0x22,0x32,0x31,0x22,0x21,0x22,
//自你走后心憔悴
0x21,0x31,0x51,0x52,0x31,0x52,0x61,0x15,0x14,
//白色油桐风中纷飞
0x51,0x52,0x31,0x52,0x62,0x13,0x11,0x13,0x32,0x28,0x08,0x28, //落花似人有情这个季节
0x31,0x32,0x31,0x32,0x11,0x21,0x51,0x52,0x51,0x52,
//河畔的风放肆拼命地吹
//不断拨弄离人的眼泪
0x62,0x71,0x81,0x72,0x61,0x61,0x52,0x31,0x21,0x32,0x51,0x54, //那样浓烈的爱再也无法给
0x22,0x12,0x11,0x12,0x11,0x12,0x12,0x14,0x26,0x32,0x26, //伤感一夜一夜
0x32,0x61,0x51,0x51,0x31,0x31,0x21,0x31,0x51,0x61,0x51,0x31,0x51, //当记忆的线缠绕过往支离破碎
0x02,0x32,0x81,0x81,0x81,0x81,0x62,0x52,0x34,
//是慌乱占据了心扉
0x31,0x81,0x81,0x81,0x61,0x91,0x82,
//有花儿伴着蝴蝶
0x51,0x51,0x51,0x51,0x31,0x61,0x53,
//孤雁可以双飞
0x21,0x11,0x21,0x11,0x22,0x11,0x21,0x26,
//夜深人静独徘徊
0x32,0x61,0x51,0x51,0x31,0x31,0x21,0x31,0x51,0x61,0x51,0x31,0x51, 0x52,
//当幸福恋人寄来红色分享喜悦
0x31,0x31,0x81,0x81,0x81,0x61,0x91,0x81,0x61,0x31,0x56, //闭上双眼难过头也不敢回
0x32,0x32,0x81,0x81,0x81,0x81,0x91,0x81,0x61,0x81,0x61,0x51,0x31,
0x51,0x34,
//仍然捡尽寒枝不肯安歇微带着后悔
0x21,0x31,0x51,0x31,0x21,0x11,0x61,0x21,0x16,
//寂寞沙洲我该思念谁
0xff};
//----------------------------简谱音
---------------------------
//适合
11.0592M 的晶振
uchar code cuzhi[]={
0xff,0xff,//占位
0xFC,0x8E,//中央C 调1-7
0xFC,0xED,
0xFD,0x43,
0xFD,0x6A,
0xFD,0xB3,
0xFD,0xF3,
0xFE,0x2D,
0xFE,0x47,
//高八度1-7
0xFE,0x76,
0xFE,0xA1, 调对应的定时器初值
0xFE,0xC7,
0xFE,0xD9,
0xFE,0xF9,
0xFF,0x16
};
uchar yinyue[]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0x0,0x0}; //将音调转化为对应的LED 样式
void delay1(uint z); //延时1MS
void delay(uint z); //延时165MS, 即十六分音符
void song();
void beep();//蜂鸣器叫一声
main()
{ uchar x;
count1=0;//流水灯无花样
count2=1;//唱第一首歌
P34=0;//选取矩阵键盘的一列
EA=1;//开总中断
EX0=1;//开外部中断0
IT0=1;//外部中断0下降沿触发方式
EX1=1;//开外部中断1
IT1=1;//外部中断1下降沿触发方式
TMOD=0x01;//定时器0工作在方式1
TH0=0;
TL0=0;
ET0=1;
while(1)
{
if(count1!=0)
{
switch(count1)
{
case 1:
for(x=0;x
{
duan=1;
P1=huayang1[x];
beep();
delay1(300);
duan=0;
if(count1!=1)
break;
}
break;
case 2:
for(x=0;x
{
duan=1;
P1=huayang2[x];
beep();
delay1(300);
duan=0;
if(count1!=2)
break;
}
break;
case 3:
for(x=0;x
{
duan=1;
P1=huayang3[x];
beep();
delay1(300);
duan=0;
if(count1!=3)
break;
}
break;
case 4:
for(x=0;x
{
duan=1;
P1=huayang4[x];
beep();
delay1(300);
duan=0;
if(count1!=4)
break;
}
break;
}
}
else
{
song();
delay1(1000);
}
}
}
void int0() interrupt 0
{
EA=0;//关总中断
delay1(1);//去抖
if(key1==0)
{
count2=0;//不让蜂鸣器唱歌
TR0=0;
count1++;
if(count1==5)
count1=1;
}
EA=1;//开总中断
}
void int1() interrupt 2
{
EA=0;//关总中断
delay1(1);//去抖
if(key2==0)
{
count1=0;//流水灯无花样
TR0=1;
i=0;//从头开始唱
count2++;
if(count2==3)
count2=1;
}
EA=1;//开总中断
}
void timer0() interrupt 1
{
TH0=timeh;
TL0=timel;
fm=~fm;
}
void song()
{
uint temp;
uchar jp;//jp是简谱
i=0;
while(1) //用于产生各种音调
{ if(count2==0)
{
break;
}
if(count2==1) //选曲
temp=qnzl[i];
if(count2==2)
temp=jmszl[i];
if(temp==0xff)
break;
jp=temp/16; //取数的高4位
duan=1;
P1=yinyue[jp];
duan=0;
if(jp!=0)
{
timeh=cuzhi[jp*2];
timel=cuzhi[jp*2+1];
}
else
{
TR0=0;
fm=1;//关蜂鸣器
}
delay(temp%16); //取数的低4位
TR0=0; //唱完一个音停10MS
fm=1;
delay1(10);
TR0=1;
i++;
}
TR0=0;
fm=1;
}
void delay(uint z) //延时165MS, 即十六分音符
{ uint x,y;
for(x=z;x>0;x--)
for(y=19000;y>0;y--);
}
void delay1(uint z) //延时1MS
{ uint x,y;
for(x=z;x>0;x--)
for(y=112;y>0;y--);
}
void beep() //蜂鸣器叫一声
{ uchar i;
for(i=0;i
{ fm=~fm;
delay1(1);
}
fm=1;
}
七、设计心得:
单片机的设计至今为止已经进入了令人鼓舞的阶段,在进行了长达两个多月的时间的摸索与实验,使我不仅仅是对于单片机入门软件与硬件的常用设计与功能,还使我对于一项设计研究的制作过程所需要的详细步骤和具体的实现方法的力度的掌握。当然在这次宝贵的设计活动中,经验才是对于我们最大的收获,而且还增强了自身对未知问题以及对知识的深化认识的能力,用受益匪浅这个词语来概括这次难忘的活动我觉得再合适不过了。总之,这次设计从软件编写、调试到软硬件联机调试,我倾注了大量的时间和心血。真是曾经为程序的编写而冥思查找过,曾经为无法找出错误而郁闷苦恼过,也曾经为某一功
能不能实现而犹豫彷徨过,但最终我成功了。我不仅品味到了结果的喜悦,更明白了过程的弥足珍贵感谢我的导师胡亚琪老师,他严谨细致、一丝不苟的作风一直是我工作、学习中的榜样;他循循善诱的教导和不拘一格的思路给予我无尽的启迪。
八、参考文献:
1、《单片机原理及应用系统设计》
胡亚琦 编著
西安科技大学出版社
2、《C 语言程序设计》 (第三版)
林小茶
中国铁道出版社
附录:源程序代码
#include
#define uchar unsigned char
#define uint unsigned int
sbit duan=P2^6;
sbit key1=P3^2;//按key1可切换花样
sbit key2=P3^3;//按key2可切换歌曲
sbit fm=P3^7;//蜂鸣器连续的IO 口
sbit P34=P3^4;//矩阵键盘的一列
uchar code huayang1[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,
0xfd,0xfb,0xf7,0xef,0xdf,0xbf};//花样1
uchar code huayang2[]={0x7f,0xfe,0xbf,0xfd,0xdf,0xfb,0xef,0xf7, 0xef,0xfb,0xdf,0xfd,0xbf,0xfe};//花样2
uchar code huayang3[]={0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01,0x0, 0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};
c har code huayang4[]={ 0x55,0xaa,0xcc,0x33,0x99,0x66,0x0f,0xf0}; uchar count1;//花样标志
uchar count2;//歌曲标志
uchar timeh,timel,i;
//---------------------------简谱--------------------------------------- //编程规则字节高位是简谱, 低位是持续时间,
//代表多少个十六分音符
//1-7代表中央C 调,8-E 代表高八度,0代表停顿
//最后的0是结束标志
uchar code qnzl[]={ //千年之恋
0x12,0x22,0x34,0x84,0x74,0x54,0x38,0x42,0x32,0x22,0x42,0x34,0x84, 0x72,0x82,0x94,0xA8,0x08,
//前奏
0x32,0x31,0x21,0x32,0x52,0x32,0x31,0x21,0x32,0x62,
//竹林的灯火到过的沙漠
0x32,0x31,0x21,0x32,0x82,0x71,0x81,0x71,0x51,0x32,0x22,
//七色的国度不断飘逸风中
0x32,0x31,0x21,0x32,0x52,0x32,0x31,0x21,0x32,0x62,
//有一种神秘灰色的旋涡
0x32,0x31,0x21,0x32,0x83,0x82,0x71,0x72,0x02,
//将我卷入了迷雾中
0x63,0xA1,0xA2,0x62,0x92,0x82,0x52,
//看不清的双手
0x31,0x51,0x63,0x51,0x63,0x51,0x63,0x51,0x62,0x82,0x7C,0x02, //一朵花传来谁经过的温柔
0x61,0x71,0x82,0x71,0x62,0xA2,0x71,0x76,
//穿越千年的伤痛
0x61,0x71,0x82,0x71,0x62,0x52,0x31,0x36,
//只为求一个结果
0x61,0x71,0x82,0x71,0x62,0xA3,0x73,0x62,0x53,
//你留下的轮廓指引我
0x42,0x63,0x83,0x83,0x91,0x91,
//黑夜中不寂寞
0x61,0x71,0x82,0x71,0x62,0x0A2,0x71,0x76,
//穿越千年的哀愁
0x61,0x71,0x82,0x71,0x62,0x52,0x31,0x36,
//是你在尽头等我
0x61,0x71,0x82,0x71,0x62,0xA3,0x73,0x62,0x53,
//最美丽的感动会值得
0x42,0x82,0x88,0x02,0x74,0x93,0x89,0xff//结束标志
//用一生守候
};
uchar code jmszl[]={ //寂寞沙洲冷
0x12,0x12,0x22,0x32,0x31,0x22,0x21,0x22,
//自你走后心憔悴
0x21,0x31,0x51,0x52,0x31,0x52,0x61,0x15,0x14,
//白色油桐风中纷飞
0x51,0x52,0x31,0x52,0x62,0x13,0x11,0x13,0x32,0x28,0x08,0x28, //落花似人有情这个季节
0x31,0x32,0x31,0x32,0x11,0x21,0x51,0x52,0x51,0x52,
//河畔的风放肆拼命地吹
0x51,0x51,0x31,0x32,0x31,0x32,0x81,0x72,0x63,
//不断拨弄离人的眼泪
0x62,0x71,0x81,0x72,0x61,0x61,0x52,0x31,0x21,0x32,0x51,0x54, //那样浓烈的爱再也无法给
0x22,0x12,0x11,0x12,0x11,0x12,0x12,0x14,0x26,0x32,0x26,
//伤感一夜一夜
0x32,0x61,0x51,0x51,0x31,0x31,0x21,0x31,0x51,0x61,0x51,0x31,0x51, //当记忆的线缠绕过往支离破碎
0x02,0x32,0x81,0x81,0x81,0x81,0x62,0x52,0x34,
//是慌乱占据了心扉
0x31,0x81,0x81,0x81,0x61,0x91,0x82,
//有花儿伴着蝴蝶
0x51,0x51,0x51,0x51,0x31,0x61,0x53,
//孤雁可以双飞
0x21,0x11,0x21,0x11,0x22,0x11,0x21,0x26,
//夜深人静独徘徊
0x32,0x61,0x51,0x51,0x31,0x31,0x21,0x31,0x51,0x61,0x51,0x31,0x51, 0x52,
//当幸福恋人寄来红色分享喜悦
0x31,0x31,0x81,0x81,0x81,0x61,0x91,0x81,0x61,0x31,0x56, //闭上双眼难过头也不敢回
0x32,0x32,0x81,0x81,0x81,0x81,0x91,0x81,0x61,0x81,0x61,0x51,0x31, 0x51,0x34,
//仍然捡尽寒枝不肯安歇微带着后悔
0x21,0x31,0x51,0x31,0x21,0x11,0x61,0x21,0x16,
//寂寞沙洲我该思念谁
0xff};
//----------------------------简谱音调对应的定时器初值---------------------------
//适合
11.0592M 的晶振
uchar code cuzhi[]={
0xff,0xff,//占位
0xFC,0x8E,//中央C 调1-7
0xFC,0xED,
0xFD,0x43,
0xFD,0x6A,
0xFD,0xB3,
0xFD,0xF3,
0xFE,0x2D,
0xFE,0x47,
//高八度1-7
0xFE,0x76,
0xFE,0xA1,
0xFE,0xC7,
0xFE,0xD9,
0xFE,0xF9,
0xFF,0x16
};
uchar yinyue[]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0x0,0x0}; //将音调转化为对应的LED 样式
void delay1(uint z); //延时1MS
void delay(uint z); //延时165MS, 即十六分音符
void song();
void beep();//蜂鸣器叫一声
main()
{ uchar x;
count1=0;//流水灯无花样
count2=1;//唱第一首歌
P34=0;//选取矩阵键盘的一列
EA=1;//开总中断
EX0=1;//开外部中断0
IT0=1;//外部中断0下降沿触发方式
EX1=1;//开外部中断1
IT1=1;//外部中断1下降沿触发方式
TMOD=0x01;//定时器0工作在方式1 TH0=0;
TL0=0;
ET0=1;
while(1)
{
if(count1!=0)
{
switch(count1)
{
case 1:
for(x=0;x
{
duan=1;
P1=huayang1[x]; beep();
delay1(300);
duan=0;
if(count1!=1)
break;
}
break;
case 2:
for(x=0;x
{
duan=1;
P1=huayang2[x]; beep();
delay1(300);
duan=0;
if(count1!=2)
break; }
break;
case 3:
for(x=0;x
duan=1;
P1=huayang3[x]; beep();
delay1(300); duan=0;
if(count1!=3) break; }
break;
case 4:
for(x=0;x
duan=1;
P1=huayang4[x]; beep();
delay1(300); duan=0;
if(count1!=4) break; }
break;
}
}
else
{
song();
delay1(1000); }
}
}
void int0() interrupt 0
{
EA=0;//关总中断
delay1(1);//去抖
if(key1==0)
{
count2=0;//不让蜂鸣器唱歌
TR0=0;
count1++;
if(count1==5)
count1=1;
}
EA=1;//开总中断
}
void int1() interrupt 2
{
EA=0;//关总中断
delay1(1);//去抖
if(key2==0)
{
count1=0;//流水灯无花样
TR0=1;
i=0;//从头开始唱
count2++;
if(count2==3)
count2=1;
}
EA=1;//开总中断
}
void timer0() interrupt 1 //用于产生各种音调 {
TH0=timeh;
TL0=timel;
fm=~fm;
}
void song()
{
uint temp;
uchar jp;//jp是简谱
i=0;
while(1)
{ if(count2==0)
{
break;
}
if(count2==1) //选曲
temp=qnzl[i];
if(count2==2)
temp=jmszl[i];
if(temp==0xff)
break;
jp=temp/16; //取数的高4位 duan=1;
P1=yinyue[jp];
duan=0;
if(jp!=0)
{
timeh=cuzhi[jp*2];
timel=cuzhi[jp*2+1];
}
else
{
TR0=0;
fm=1;//关蜂鸣器
}
delay(temp%16); //取数的低4位 TR0=0; //唱完一个音停10MS fm=1;
delay1(10);
TR0=1;
i++;
}
TR0=0;
fm=1;
}
void delay(uint z) //延时165MS, 即十六分音符 { uint x,y;
for(x=z;x>0;x--)
for(y=19000;y>0;y--);
}
void delay1(uint z) //延时1MS
{ uint x,y;
for(x=z;x>0;x--)
for(y=112;y>0;y--);
}
void beep() //蜂鸣器叫一声
{ uchar i;
for(i=0;i
{ fm=~fm;
delay1(1);
}
fm=1; }