仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
要求通过4个按键来设置想要倒数的时间,其中系统默认倒计时为1分钟,K1可调整倒计时间1~60分钟,K2可设置倒计时为5分钟,K3可设置倒计时为15分钟,K4可设置的倒计时为20分钟,K5为启动键。当初值被设定好,只要启动K5,就可以启动倒计时功能。当计时为0时播放音乐,而且它能循环播放,可随时人为停止。
二. 方案原理
此次设计以89C52芯片为核心来设计音乐计时器,其具有倒数计时、时间设置、音乐演奏等功能。除了设定默认值为1分钟外,本计时器还有5分钟,15分钟和20分钟的快捷键,而且可在上述时间的基础上任意调整自己想设定的倒计时时间。当倒计时结束时,计时器会播放音乐,可循环播放,亦可随时停止。
这个音乐计时器由四个模块组成,分别是数码管模块,倒计时模块,音乐模块和核心处理模块。通过对P2口的查询,我们可以实现对时间的不同设定和调整。系统晶振为12MHz,RESET管脚处连接复位开关。同时,我们使用查询方式来设定定时器时间。
三. 方案具体说明
通过计算某一音频周期(1/频率),然后将此周期除以2,即为半周期的时间。利用单片机定时器计时这个半周期时间,每当计时到后就将输出脉冲的I/O口反相,然后重复计时此半周期时间再对I/O口反相,这样就能在此I/O口上得到此频率的脉冲,再结合中断延时程序,程序中节拍控制是通过调用延时子程序DELAY的次数来实现,产生音乐。利用P2.1、P2.2、P2.3管脚,对应开关K2、K3、K4,分别启动不同的倒计时程序5分钟、15分钟、20分钟。通过查询方式对P3.2管脚进行查询,进入1到60分钟的时间调整程序。P0引脚作为显示输出连至LED显示器,P1.0、P1.1、P1.2、P1.3为位选信号,控制不同位的数码管。程序中使用定时器T0方式1来产生歌谱中各音符对应频率的音频脉冲,由P1.5通放大输出,,1拍为748 ms。确定了设计思路后,就可以具体设计了。先编写程序,然后加入硬件进行调试。
四. 模块原理说明
(一).数码管模块
数码管动态显示接口是单片机中应用最为广泛的一种显示方式之一,动态驱动是将所有数码管的8个显示笔划"a,b,c,d,e,f,g,dp"的同名端连在一起,另外为每个数码管的公共极COM增加位选通控制电路,位选通由各自独立的I/O线控制,当单片机输出字形码时,所有数码管都接收到相同的字形码,但究竟是那个数码管会显示出字形,取决于单片机对位选通COM端电路的控制,所以我们只要将需要显示的数码管的选通控制打开,该位就显示出字形,没有选通的数码管就不会亮。通过分时轮流控制各个数码管的的COM端,就使各个数码管轮流受控显示,这就是动态驱动。在轮流显示过程中,每位数码管的点亮时间为1~2ms,由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,动态显示的效果和静态显示是一样的,能够节省大量的I/O端口,而且功耗更低。
(二).倒计时模块
定时器倒计时部分用中断来实现功能。定义定时器0,工作方式1,当时间过去1s后,数码管就按照设定规则显示数字。
(三).音乐模块
(1) 音乐的产生主要是通过单片机的I/O口输出高低不同的脉冲信号来控制蜂鸣器发音。要想产生音频脉冲信号,需要算出某一音频的周期(1/频率),然后将此周期除以2,即为半周期的时间。利用单片机定时器计时这个半个周期时间,每当计时到后就将输出脉冲的I/O口反相,然后重复计时此半周期时间再对I/O口反相,这样就能在此I/O口上得到此频率的脉冲。
通常,利用单片机的内部定时器0,工作在方式1下,改变计数初值TH0和TL0来产生不同频率。 对于音乐的节拍,每个音符使用1个字节,字节的高4位代表音符的高低,低4位代表音符的节拍。如果1拍为0.4S,1/4拍为0.1S,只要设定延迟时间就可求得节拍的时间。假设1/4拍为1DELAY,那么1拍应为4DELAY,以此类推。所以只要求得1/4拍的DELAY,其余的节拍就是它的倍数。
总而言之,一首乐曲是由音阶和节拍两大要素构成。一首乐曲演奏的原理是:不同音阶分别对应不同的频率,发出不同的音调,而节拍则控制发出音调时间的长短;若将乐曲的音调连续发出,并使其按相应的节拍变化,即可演奏一首乐曲。根据这一特点,我们采用单片机辅以相应的接口来设计音乐播放器。
(2)产生音乐通过单片机的I/O口输出高低不同的脉冲信号来控制蜂鸣器发音。利用AT89C52单片机的内部定时器0,工作在方式1下,改变计数初值TH0和TL0来产生不同的频率。若单片机采用12MHz晶振,要产生频率为587Hz的音频脉冲时,其音频脉冲信号的周期T=1/587=1703.577us,约1704us,半周期的时间852us,因此只要今计数器计数=852us/1us=852,在每计数852次时将I/O口反相,就可得C调中音Re。
计数脉冲值与频率的关系如下:
N=Fi/2/Fr 式中:N—计数值
Fi—机器频率。晶体振荡器为12MHz时,内部计时一次为1us,故其频率为1MHz
Fr—想要产生的频率 所以定时常数(计数值T)的求法: T=65536-N=65536-Fi/2/Fr 例如,设Fi=1MHz,求低音Do(262Hz)、中音Do(523Hz)和高音Do(1046Hz)的计数初值。
解:T=65536-N=65536-Fi/2/Fr=65536-500000/Fr
低音Do的T=65536-500000/262=63628
中音Do的T=65536-500000/523=64580
高音Do的T=65536-500000/1046=65058
(四).核心处理模块
对计时器和中断进行初始化后,系统出现默认时间设定值,也就是1分钟。如果有按键按下,屏幕上面的时间会发生改变。K1可调整倒计时间1~60分钟,K2可设置倒计时为5分钟,K3可设置倒计时为15分钟,K4可设置的倒计时为20分钟。在时间设定完毕后,利用K5启动计时器,在计时结束后调用音乐函数,SPEAKER就会播放出我们所设定的旋律。
五. 实验原理图
六. 实验感悟
在本次设计中,我重新复习了中断和计时器部分的知识,同时也学到了单片机播放音乐的原理。然而在实验过程中,我遇到了不少问题:1.复位开关失效,即它并未有起到复位效果;2.每次设定好初始值后,计时器往往会自动启动计时功能,即K5失效;3.K5按键不灵敏,往往需要重复按2次以上才会启动计时;4.SPEAKER并没有按照程序的设定播放出一段完整的音乐。如今,通过调试和修改,一到三的问题得到了解决,而第四个问题,只有在对程序进行编译,才能发现错误的所在。在整个实验过程中,我在不断的修改与调整中学习到越来越多的东西,同时也让我原本掌握的知识更加牢固,这对我来说是大有裨益的。
七. 相关程序
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit SPK=P1^5;
sbit K1=P2^0;
sbit K2=P2^1;
sbit K3=P2^2;
sbit K4=P2^3;
sbit K5=P2^4;
sbit A1=P1^0;
sbit A2=P1^1;
sbit A3=P1^2;
sbit A4=P1^3;
uchar miao_g,miao_d,fen_g,fen_d;
uchar code Num[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xf8,0x80,0x90};
uchar num1;
uchar code song[]={0x58,0x84,0xA8,0x84,0x68,0x82,0x62,0x5C,0xA4,0xA4,0xA4,0xA4,0x93,0x81,0x9C,0x9C,0xC8,0xC4,0xC8,0xD2,0xC2,0xA8,0x92,0x82,0x6B,0xC4,0xC4,0xC4,0xA8,0x94,0x8C,0xFF};
//音律部分,前四位为音阶,后四位为节拍,其中以1/4节拍为单位节拍;
uchar m;
uchar code yinjie[]={0xff,0xff,0xFC,0x4A,0xFC,0xAE,0xFD,0x08,0xFD,0x30,0xFD,0x80,0xFD,0xC6,0xFE,0x02,0xFE,0x2A,0xFE,0x5C,0xFE,0x84,0xFE,0x98,0xFE,0xC0,0xFE,0xE8,0xFF,0x06};
//音阶所对应的计时器初值,前两位是占位,中间14位是中音1~7,后面14位是高音1~7,晶振为12MHz;
uchar ding;
void delay_1();//1/4节拍函数声明;
void delay(uint k);//计数器延时函数声明;
void display(uint fen_g,uint fen_d,uint miao_g,uint miao_d);//数码管显示函数声明;
void music();//音乐函数声明;
void delayxiaodou(int n);//消抖函数声明,用于主函数K5;
//数码管部分
void delay(uint k) //延时函数,用于计时器计算1s部分和数码管延时显示部分
{ uint x,y;
for(x=k;x>0;x--)
for(y=125;y>0;y--);
}
void delayxiaodou(int n)
{
while(n--);
}
void display(uint fen_g,uint fen_d,uint miao_g,uint miao_d) //数码管显示时间
{
P0=0xFF; //消隐;
A1=1;A2=0;A3=0;A4=0;
P0=Num[fen_g];
delay(1);
P0=0xFF;
A1=0;A2=1;A3=0;A4=0;
P0=Num[fen_d];
delay(1);
A1=0;A2=0;A3=1;A4=0;
P0=0xFF;
P0=Num[miao_g];
delay(1);
A1=0;A2=0;A3=0;A4=1;
P0=0xFF;
P0=Num[miao_d];
delay(1);
TR0=0;
}
//倒计时部分
void timer()interrupt 1 //定时器0,方式1
{
TH0=0x3C; //50ms倒计时
TL0=0xB0;
num1++;
if(num1==20) //50ms*20=1s
{ num1=0;
miao_d--;
if(miao_d==-1)
{ miao_d=9;
miao_g--;
if(miao_g==-1)
{ miao_g=5;
fen_d--;
if(fen_d==-1)
{ fen_d=9;
fen_g--;
if(fen_g==-1)
{
fen_g=5;}}}}}}
//音乐部分
void music()
{ uint data j=0;
uchar data g;
uchar data i;
while (*(song+j)!=0xff)//歌曲的停顿;
{ g=*(song+j)&0x0F;//低4位,节拍;
m=*(song+j)>>4; //高4位,音阶;
TH1=yinjie[2*m];
TL1=yinjie[2*m+1];
TR1=1;
if((yinjie[2*m]==0xff)&&(yinjie[2*m+1]==0xff))
{ TR1=0;
SPK=1;}
for(i=g;i>0;i--)
{ delay_1();
TR1=0;
j++;
}}}
void delay_1()//1/4 节拍所需要用的时间,约187ms;
{ uchar m,n,p;
for(m=100;m>0;m--)
for(n=20;n>0;n--)
for(p=15;p>0;p--);
}
void timer0() interrupt 3 //半个周期后,SPK处的脉冲反相,得到音阶;
{ TH1=yinjie[2*m];
TL1=yinjie[2*m+1];
SPK=!SPK;
}
//核心处理模块
void main()
{
TMOD=0x01; //启动定时器,初值为50ms;
TH0=0x3C;
TL0=0xB0;
ET0=1; //定义中断;
ET1=1;
EA=1;
TR0=0; //时钟初始化;
miao_g=miao_d=fen_g=0;
fen_d=1;
ding=0;
while(1)
{
display(fen_g,fen_d,miao_g,miao_d);
if(K5!=0)
{
if(K1==0) //K1按键:在1分钟基础上递增,可自定义计时时间;
{ delayxiaodou(100);
if(K1==0)
{ miao_g=miao_d=0;
fen_d++;
if(fen_d==10)
{ fen_d=0;
fen_g++;
if(fen_g==6)
{fen_d=0;
}}}}
while(!K1);
if(K2==0) //K2按键:初值为5分钟;
{ delayxiaodou(100);
if(K2==0)
{
miao_g=miao_d=0;
fen_d=5;
fen_g=0;
}
}
while(!K2);
if(K3==0) //K3按键:初值为15分钟;
{ delayxiaodou(100);
if(K3==0)
{ miao_g=miao_d=0;
fen_d=5;
fen_g=1;
}
}
while(!K3);
if(K4==0) //K4按键:初值为20分钟;
{ delayxiaodou(100);
if(K4==0)
{ miao_g=miao_d=0;
fen_d=0;
fen_g=2;
}
}
while(!K4);
}
if(K5==0) //K5按键:初值设定好后,启动倒计时;
{ delayxiaodou(1);
if(K5==0)
{ ding++;
if(ding==2)
{ ding=5;}
}}
while(!K5);
if(ding==5)
TR0=1;
//倒计时结束;
display(fen_g,fen_d,miao_g,miao_d);
if(fen_g==0&&fen_d==0&&miao_g==0&&miao_d==0)
music();
}
}
全部资料51hei下载地址:
单片机设计——音乐计时器.zip
(472.64 KB, 下载次数: 105)
|