找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6743|回复: 6
打印 上一主题 下一主题
收起左侧

单片机音乐计时器Proteus仿真+代码设计分享

[复制链接]
跳转到指定楼层
楼主
仿真原理图如下(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, 下载次数: 103)
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏4 分享淘帖 顶2 踩
回复

使用道具 举报

沙发
ID:626741 发表于 2019-10-19 19:48 | 只看该作者
portues 工程文件是哪个呀?下载之后,没有找到
后来才知道原来需要安装Proteus7.5才能打开,下面是仿真图

51hei.png (18.19 KB, 下载次数: 47)

51hei.png
回复

使用道具 举报

板凳
ID:626741 发表于 2019-10-19 19:57 | 只看该作者
请问压缩包里的protues工程文件在哪里呀 没有找到
回复

使用道具 举报

地板
ID:462085 发表于 2020-3-6 16:56 | 只看该作者
不错的设计,值得学习
回复

使用道具 举报

5#
ID:341891 发表于 2020-5-29 18:45 | 只看该作者
好东西 谢谢楼主
回复

使用道具 举报

6#
ID:781587 发表于 2020-6-20 19:45 | 只看该作者
为啥数码管一闪一闪的,除了复位和K5能按,其它按钮都按不了,小白的我太难了
回复

使用道具 举报

7#
ID:910064 发表于 2021-4-26 16:49 | 只看该作者
羽儿 发表于 2020-6-20 19:45
为啥数码管一闪一闪的,除了复位和K5能按,其它按钮都按不了,小白的我太难了

哇,我也是呜呜呜,那你现在解决了吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表