资源描述
单片机课程设计
《单片机原理及应用》课程设计
---八音盒设计---
院 系: 机电汽车工程学院
姓 名:
班 级: 机101-4班
组 长:
组 员:
指导教师: 姜风国
完成时间: 2013年6月5日
目录
一、课程设计任务书 3
二、设计项目简介 3
2.1 总体设计思路..................................................................................................3
2.2 音符产生方法 .................................................................................................3
2.3 节拍产生方法 .................................................................................................4
2.4 核心器件简介 .................................................................................................5
2.5 任务分工 ...................................................................................................7
三、系统功能简介 ..........8
四、电路原理图 8
4.1 硬件电路设计框图…………………………………………………………..10
4.2 键盘控制电路………………………………………………………………..10
4.3 LCD显示电路……………………………………………………………….11
4.4 晶振和复位电路…………………………………………………………… ..11
4.5 扬声器和闪烁电路…………………………………………………………...12
4.6 播放和停止电路……………………………………………………………...12
五、程序框图 ..................13
六、程序清单 .....16
6.1 主函数main.c………………………………………………………………..16
6.2 功能函数 fun.c………………………………………………………………18
6.3 数据函数 data.c……………………………………………………………...27
6.4 主函数变量定义 ……………………………………………………………33
6.5 功能函数相关变量定义 …………………………………………………….33
6.6 数据函数相关变量定义………………………………………………………34
七、总结...................................................................................................35
参考文献: ...36
摘要
近年来随着科技的飞速发展,单片机的应用正在不断地走向深入。当今,利用单片机控制音乐播放举不胜举,而利用单片机存储音乐,控制播放最为广泛,它具有功能多、价格优、外围电路简单等特点,很受音乐爱好者和音乐芯片制造商的青睐。
本设计主要是应用单片机的原理和控制理论来设计音乐播放器的硬件电路,并利用C语言进行软件程序设计。通过控制单片机内部的定时器产生不同频率的方波,驱动蜂鸣器发出不同音调的音乐,再利用延时来控制发音时间的长短。把乐谱转化成相应的定时常数就可以从发音设备中演奏出悦耳动听的音乐。最后利用编程软件uVision3和仿真软件PROTEUS对该音乐播放器进行仿真,完全实现所需功能。
关键词 89C51单片机;矩阵键盘;蜂鸣器;LCD;八音盒
一、课程设计任务书
本设计利用89C51单片机结合内部定时器以及外接LCD和矩阵键盘设计了一个八音盒,按下单键可以演奏预先设置的歌曲旋律。本设计可以学习89C51定时器程序设计,按键扫描及歌曲旋律简单直觉式输入法的设计方法。
其基本功能为:1、使用LCD显示器来显示目前演奏的歌曲编号;2、具有16个按键操作来选择演奏哪一首歌曲;3、内建10首歌曲旋律,按下单键可以演奏歌曲;4、演奏时可以按键中断。程序执行后工作指示LED闪动,表示程序开始执行,按下单键0~9便可以演奏歌曲,歌曲演奏中,可以按键中断。
二、设计项目简介
1、设计思路:
⑴ 选用ATMEL公司89C51单片机,它具有16KB的内部ROM, 2个定时器/计数器,2个外部中断。
⑵ 通过中断实现歌曲的播放和暂停。
⑶ 通过定时实现LED闪烁和音乐频率的变化。
⑷ 通过键盘实现歌曲的选择。
2、音符产生方法:
不同的音调有不同的频率。频率不同,音调也就不同。利用定时器,使其工作在模式0,定时中断,然后控制P3.7引脚的输出每次取反,就可以在P3.7的引脚输出相应的方波频率。改变计数初值,就改变了频率。定时器的定时时间等于半个周期,定时时间到就输出脉冲取反,重复此过程,就可在P3.7引脚得到一音频的脉冲。
如:C调中音1的频率=523HZ,周期T=1/523=1912us;
定时器的定时时间为:T/2=1912/2us=956us;
则其计数初值为:TH0=(8192-C)/32;TL0=(8192-C)%32;
下面是音符及其程序中对应的编码
表2.1 音符编码表
音符
音符编码
音符
音符编码
音符
音符编码
低音1
l_dao
中音1
dao
高音1
h_dao
低音2
l_re
中音
Re
高音2
h_re
低音3
l_mi
中音
Mi
高音3
h_mi
低音4
l_fa
中音
Fa
高音4
h_fa
低音5
l_sao
中音
Sao
高音5
h_sao
低音6
l_la
中音
La
高音6
h_la
低音7
l_xi
中音
Xi
高音7
h_xi
3、节拍产生方法:
音乐中的节拍用延时时间产生。假设1/4拍执行一次延时程序, 1/2拍就执行两次延时程序,所以只要求出1/4延时时间,其余的节拍就是他的倍数。为方便记谱,将节拍数也进行编码,如下:
表2.2 节拍编码表
节拍
节拍编码(基本延时次数)
1/4
1
1/2
2
3/4
3
4/4
4
建立曲谱编码表,例如:
简谱编码:re,sao,mi,re,mi,sao,mi,re,dao,re,re,sao,re,mi,sao, mi,re,dao,l_la,dao,dao,mi,re,mi,l_sao,re,l_xi,l_la,l_sao,l_la,
dao,re,l_xi,l_la,l_sao,l_mi,l_sao,0xff
节拍编码:4,4,2,2,4,2,2,2,2,8,4,4,4,2,2,
2,2,2,2,8,4,4,2,2,4,2,2,2,2,4,
6,2,2,2,2,2,16
4、核心器件简介
(1)AT89C51的性能介绍
AT89C51是一种带4K字节闪烁可编程可擦除只读存储器,高性能CMOS8位微处理器,俗称单片机。该器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的AT89C51是一种高效微控制器,为很多嵌入式控制系统提供了一种灵活性高且价廉的方案。
它可以提供以下的功能标准:
1) 4K的字节闪烁存储器;
2)128字节随机存取数据存储器;
3)32个I/O口;
4)2个16位定时/计数器;
5)1个串行通信口;
6)片内振荡器和时钟电路。
(2)蜂鸣器
蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。 蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。
1) 压电式蜂鸣器 压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。有的压电式蜂鸣器外壳上还装有发光二极管。多谐振荡器由晶体管或集成电路构成。当接通电源后(1.5~15V直流工作电压),多谐振荡器起振,输出1.5~2.5kHZ的音频信号,阻抗匹配器推动压电蜂鸣片发声。压电蜂鸣片由锆钛酸铅或铌镁酸铅压电陶瓷材料制成。在陶瓷片的两面镀上银电极,经极化和老化处理后,再与黄铜片或不锈钢片粘在一起。
2) 电磁式蜂鸣器 电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。
(3)矩阵键盘
单片机系统中,若使用按键的数量比较多时,通常选用用矩阵式键盘。矩阵式键由行线和列线构成,按键位于行、列线的交叉点上, 键盘矩阵是由四行四列构成,矩阵的四列和 P2 口的低四位相连,四行与 P2 口的高四位相连。其键盘识别方法如下:
1) 判断键盘中有无键按下 将全部行线置低电平,然后检测列线的状态。只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平线与4根行线相交叉的4个按键之中。若所有列线均为高电平,则键盘中无键按下。
2) 判断闭合键所在的位置 在确认有键按下后,即可进入确定具体闭合键的过程。其方法是:依次将行线置为低电平,即在置某根行线为低电平时,其它线为高电平。在确定某根行线位置为低电平后,再逐行检测各列线的电平状态。若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键
(4)LCD1602液晶显示器简介
工业字符型液晶,能够同时显示16X02即32个字符。(16列2行)
1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用。
1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。 基本内容如下:
5、任务分工
(1)系统总体设计及调试方面-----臧
(2)键盘扫描程序编辑方面-----------刘
(3)LCD显示程序编辑方面------------臧
(4)中断程序及protues仿真调试方面-------周
(5)扬声器、二极管闪烁程序以及protues硬件电路设计 -------王
(6)歌曲搜集整理、歌曲播放程序及文档编写-------林 、李 、刘
三、系统功能简介
1、此80C51八音盒有矩阵式键盘共十个按键,0~9按键用于选择歌曲,通过P2口与单片机相连。
2、LCD通过用于显示,显示当前正在播放的歌曲编号。P0口输出编号,P1.4、P1.5、P1.6用于控制LCD。
3、有中断按键,在单片机播放旋律时可以按外部中断1键实现歌曲暂停,再按中断T0实现歌曲暂停后的播放。
4、LED灯连接在P1.7口,用LED灯闪烁指示单片机处于工作状态。
5、歌曲音调经P3.7口的喇叭播放出来。
四、电路原理图
电路原理图设计结果如下:
图4.1 电路原理图
具体设计如下:
4.1 硬件电路设计框图
键盘控制电路
89C51单片机
LCD显示电路
LED闪烁电路
扬声器电路
4.2 键盘控制电路
图4.2 键盘控制电路
按键功能:
0—9键:十首歌曲选择键,按下某个按键可播放对应的歌曲。键盘中断通过三输入与门引入外部中断0。
4.3 LCD显示电路
图4.3 LCD显示电路
用P1.4—P1.6作为LCD的RS、R/W、E的控制信号
用P0.0--P0.7作为LCD的D0--D7的控制信号
4.4 晶振和复位电路
图4.4 晶振和复位电路
XTAL1和XTAL2的两端用来连接石英晶体和外接电容,即用来连接片内OSC的定时反馈回路。石英起振后应能在XTAL2线上输入一个3V左右的正弦波,以便使MCS-51片内的OSC电路按石英晶振相同频率自激振荡。
4.5 扬声器和闪烁电路
图4.5.1 闪烁电路通过P1.7口驱动 图4.5.2 扬声器通过P3.7驱动
4.6 播放和停止电路
播放中断通过T0中断引入单片机;暂停中断通过外部中断1引入单片机。
图4.6 播放和停止电路
五、程序框图
主程序
定时器T1、T2初始化
外部中断0、1的初始化
LCD初始化
键盘扫描
While(1)
无限循环
键盘扫描
Switch
判断
default
Case:music
开始
键盘扫描
否
是
全列置零,全行扫描
开始
结束
判断是否有键按下
全列置零,全行扫描
去抖延时
行赋值
全列置零,全行扫描
列赋值
计算键值
音符播放程序
开始
LCD清屏
显示歌曲编号
判断是否是标志位
计数器赋初值
启动定时器
控制节拍延时
关闭定时器
播放下一个音符
结束
否
是
六、程序清单:
6.1 主函数main.c
#include "main.h"
#include "data.c"
#include "fun.c"
/******************************************************************************
函数功能:键盘扫描中断服务程序(外部中断0)
******************************************************************************/
void int0()interrupt 0
{
BZ=0;
keyscan();
}
/******************************************************************************
函数功能:歌曲播放与暂停中断服务程序(外部中断1和计数器T0中断)
******************************************************************************/
void int1()interrupt 2
{
uchar temp;
while(!bz);
k=1;
TR0=0;
while(k)
{
temp=bf;
if(temp==0)
{
delayms(5);
temp=bf;
if(temp==0)
{
while(!bf);
k=0;TR0=1;
break;
}
}
}
}
/******************************************************************************
函数功能:定时器1的中断服务程序
******************************************************************************/
void timer1()interrupt 3
{
LED=!LED;
keyscan();
}
/*****************************************************************************
函数功能:定时器T0的中断服务子程序,使P3.7引脚输出音频的方波
*****************************************************************************/
void Time0(void ) interrupt 1 using 1
{
sound=!sound; //将P3.7引脚输出电平取反,形成方波
TH0=(8192-C)/32; //可证明这是13位计数器TH0高8位的赋初值方法
TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法
}
/*****************************************************************************
函数功能:主函数
*****************************************************************************/
void main(void)
{
initialT012(); //LED 灯、定时器T1、T2初始化
initial(); //外部中断0和1的初始化
LCD(); //LCD初始化*/
while(1)
{
BZ=1;
switch(keynum)
{
case 0x00: music0();break;
case 0x01: music1();break;
case 0x02: music2();break;
case 0x03: music3();break;
case 0x04: music4();break;
case 0x05: music5();break;
case 0x06: music6();break;
case 0x07: music7();break;
case 0x08: music8();break;
case 0x09: music9();break;
default : break;
}
}
}
6.2 功能函数 fun.c
用于播放歌曲、LCD以及中断初始化
#include "main.h"
#include "fun.h"
#include "data.h"
/******************************************************************************
函数功能: 歌曲 0《好人一生平安》
******************************************************************************/
void music0(void)
{ LCD();
WriteData('m');WriteData('u');WriteData('s');WriteData('i');
WriteData('c');WriteData(' ');WriteData('0');WriteData('!');
i=0; //从第1个音符f[0]开始播放
while(f0[i]!=0xff) //只要没有读到结束标志就继续播放
{
if(BZ==0)
break;
C=460830/f0[i];
TH0=(8192-C)/32; //可证明这是13位计数器TH0高8位的赋初值方法
TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法
TR0=1; //启动定时器T0
for(j=0;j<JP0[i];j++) //控制节拍数
delay(); //延时1个节拍单位
TR0=0; //关闭定时器T0
i++; //播放下一个音符
}
}
/******************************************************************************
函数功能: 歌曲 1《保卫黄河》
******************************************************************************/
void music1(void)
{ LCD();
WriteData('m');WriteData('u');WriteData('s');WriteData('i');
WriteData('c');WriteData(' ');WriteData('1');WriteData('!');
i=0; //从第1个音符f[0]开始播放
while(f1[i]!=0xff) //只要没有读到结束标志就继续播放
{
if(BZ==0)
break;
C=460830/f1[i];
TH0=(8192-C)/32; //可证明这是13位计数器TH0高8位的赋初值方法
TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法
TR0=1; //启动定时器T0
for(j=0;j<JP1[i];j++) //控制节拍数
delay(); //延时1个节拍单位
TR0=0; //关闭定时器T0
i++; //播放下一个音符
}
}
/******************************************************************************
函数功能: 歌曲 2《毕业歌》
******************************************************************************/
void music2()
{ LCD();
WriteData('m');WriteData('u');WriteData('s');WriteData('i');
WriteData('c');WriteData(' ');WriteData('2');WriteData('!');
i=0; //从第1个音符f[0]开始播放
while(f2[i]!=0xff) //只要没有读到结束标志就继续播放
{
if(BZ==0)
break;
C=460830/f2[i];
TH0=(8192-C)/32; //可证明这是13位计数器TH0高8位的赋初值方法
TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法
TR0=1; //启动定时器T0
for(j=0;j<JP2[i];j++) //控制节拍数
delay(); //延时1个节拍单位
TR0=0; //关闭定时器T0
i++; //播放下一个音符
}
}
/******************************************************************************
函数功能: 歌曲 3《沂蒙山小调》
******************************************************************************/
void music3()
{ LCD();
WriteData('m');WriteData('u');WriteData('s');WriteData('i');
WriteData('c');WriteData(' ');WriteData('3');WriteData('!');
i=0; //从第1个音符f[0]开始播放
while(f3[i]!=0xff) //只要没有读到结束标志就继续播放
{
if(BZ==0)
break;
C=460830/f3[i];
TH0=(8192-C)/32; //可证明这是13位计数器TH0高8位的赋初值方法
TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法
TR0=1; //启动定时器T0
for(j=0;j<JP3[i];j++) //控制节拍数
delay(); //延时1个节拍单位
TR0=0; //关闭定时器T0
i++; //播放下一个音符
}
}
/******************************************************************************
函数功能:歌曲4 《套马杆》
******************************************************************************/
void music4()
{ LCD();
WriteData('m');WriteData('u');WriteData('s');WriteData('i');
WriteData('c');WriteData(' ');WriteData('4');WriteData('!');
i=0; //从第1个音符f[0]开始播放
while(f4[i]!=0xff) //只要没有读到结束标志就继续播放
{
if(BZ==0)
break;
C=460830/f4[i];
TH0=(8192-C)/32; //可证明这是13位计数器TH0高8位的赋初值方法
TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法
TR0=1; //启动定时器T0
for(j=0;j<JP4[i];j++) //控制节拍数
delay(); //延时1个节拍单位
TR0=0; //关闭定时器T0
i++; //播放下一个音符
}
}
/******************************************************************************
函数功能:歌曲 5《军港之夜》
******************************************************************************/
void music5()
{ LCD();
WriteData('m');WriteData('u');WriteData('s');WriteData('i');
WriteData('c');WriteData(' ');WriteData('5');WriteData('!');
i=0; //从第1个音符f[0]开始播放
while(f5[i]!=0xff) //只要没有读到结束标志就继续播放
{
if(BZ==0) break;
C=460830/f5[i];
TH0=(8192-C)/32; //可证明这是13位计数器TH0高8位的赋初值方法
TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法
TR0=1; //启动定时器T0
for(j=0;j<JP5[i];j++) //控制节拍数
delay(); //延时1个节拍单位
TR0=0; //关闭定时器T0
i++; //播放下一个音符
}
}
/******************************************************************************
函数功能:歌曲 6《童年》
******************************************************************************/
void music6()
{ LCD();
WriteData('m');WriteData('u');WriteData('s');WriteData('i');
WriteData('c');WriteData(' ');WriteData('6');WriteData('!');
i=0; //从第1个音符f[0]开始播放
while(f6[i]!=0xff) //只要没有读到结束标志就继续播放
{
if(BZ==0)
break;
C=460830/f6[i];
TH0=(8192-C)/32; //可证明这是13位计数器TH0高8位的赋初值方法
TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法
TR0=1; //启动定时器T0
for(j=0;j<JP6[i];j++) //控制节拍数
delay(); //延时1个节拍单位
TR0=0; //关闭定时器T0
i++; //播放下一个音符
}
}
/******************************************************************************
函数功能: 歌曲 7《爱情买卖》
******************************************************************************/
void music7()
{ LCD();
WriteData('m');WriteData('u');WriteData('s');WriteData('i');
WriteData('c');WriteData(' ');WriteData('7');WriteData('!');
i=0; //从第1个音符f[0]开始播放
展开阅读全文