找回密码
 立即注册

QQ登录

只需一步,快速开始

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

51单片机用定时器T0的模式0控制播放《好人一生平安》

[复制链接]
跳转到指定楼层
楼主
ID:223935 发表于 2017-8-1 20:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式



C音调与谱曲控制对应表
音调   低1(低音“dao”)  低2  低3  低4  低5  低6  低7  

频率   262                 294  330  349  392  440  494

音调   中1(中音“dao”)  中2  中3  中4  中5  中6  中7

频率   523                 587  659  698  784  880  988

音调   高1(高音“dao”)  高2  高3  高4  高5  高6  高7

频率   1046                1175 1318 1397 1568 1760 1967


实现方法

1.音频控制

要让蜂鸣器发出某音调的声音,只要给蜂鸣器输送该音调频率的电平信号就可以了。
由于单片机I/O口的输出只有高电平“1”和低电平“0”两种状态,因此给蜂鸣器输送的电平信号实际上就是该音频的方波。
例如:中音“1”的频率为523HZ,它的周期为1/523s,即1.91ms,因此,只要给蜂鸣器输送周期为1.91ms的脉冲方波电平信号就能发出
523HZ的音调,该方波的半周期为1.91/2=0.955ms.为此,需要利用定时器的中断,让输送给蜂鸣器的电平信号每0.995ms取反一次即可,
单片机晶振频率为11.0952MHZ,它的一个机器周期为12*(1/11.0592)us,所以需要的机器周期总数为

                                                955us/1.085us=880

即定时器的定时常数应取为880,由上述分析,发出频率为f的音频时,定时常数C计算公式为

                                                C=(10^6 / 2f)/1.085us =  460830/f

因为T0工作方式0,其最大计数值为8192,完全可以满足各音频定时常数设置的需要。可以证明,在已知定时常数C的条件下,13位计数器
的高8位和低5位的初值可由以下公式设定:

                    TH0=(8192-C)/32   //13位计数器高8位的赋初值方法
                    TL0=(8192-C)%32   //13位计数器低5位的赋初值方法


2.节拍控制

每分钟72拍,每个节拍所需时间:(1000*60/72)ms=833ms     // 具体见单片机扉页

3.音调与节拍的存储

可以将简谱中所有音调的频率及节拍分别存储于两个数组,然后依次从数组中读出频率,再根据频率和定时器延时常数的计算公式
即可由定时器中断控制发出该音调的音频,其发声时间可由节拍控制(1-4个延时单位)。

4.音调的宏定义

直接将频率存入数组,显然不如以“dao,rei,mi,fa,sao……”的形式存储方便,但是为了让单片机认识这些,需要在程序开头处对各音调
的频率进行宏定义。例如,低音6的频率为440Hz,中音6的频率为880Hz,高音6的频率为1760Hz。所以可以对这三个频率进行如下宏定义


           #define l_la 440  //将“l_la”宏定义为低音“6”的频率440Hz,以此类推
           #define la 880
           #define h_la 1760


程序设计

#include<reg52.h>
sbit deep=P2^3;
uint C;
#define uint unsigned int
#define uchar unsigned char
#define l_dao 262
#define l_re 286
#define l_mi 311
#define l_fa 349
#define l_sao 392
#define l_la 440
#define l_xi 494
#define dao 523
#define re 587
#define mi 659
#define fa 698
#define sao 784
#define la 880
#define xi 987
#define h_dao 1046
#define h_re 1174
#define h_mi 1318
#define h_fa 1396
#define h_sao 1567
#define h_la 1760
#define h_xi 1975

void delay(uint xms)
{
    uchar i,j;
    for(i=xms;i>0;i--)
       for(j=110;j>0;j--);
}


void main()
{
    uchar i.j;
    uint code f[]={re,mi,re,dao,l_la,dao,l_la,
                   l_sao,l_mi,l_sao,l_la,dao,
                   l_la,dao,sao,la,mi,sao,re,mi,re,mi,sao,mi,
                   l_sao,l_mi,l_sao,l_la,dao,
                   l_la,l_la,dao,l_la,l_sao,l_re,l_mi,
                   l_sao,re,re,sao,la,sao,
                   fa,mi,sao,mi,la,sao,mi,re,mi,l_la,dao,
                   re,mi,re,mi,sao,mi,l_sao,l_mi,l_sao,l_la,dao,
                   l_la,dao,re,l_la,dao,re,mi,re,l_la,dao,re,l_la,dao,
                   re,mi,re,l_la,dao,re,l_la,dao,re,mi,re,0xff};

    uchar code JP[]={4,1,1,4,1,1,2,           //每行对应一小节音调的节拍
                     2,2,2,2,8,
                         4,2,3,1,2,2,
                       10,
                      4,2,2,4,4,
                      2,2,2,2,4,
                   2,2,2,2,2,2,2,
                       10,
                      4,4,4,2,2,
                      4,2,4,4,
                      4,2,2,2,2,2,2,
                        10,
                      4,2,2,4,4,
                      2,2,2,2,6,
                      4,2,2,4,1,1,4,
                        10,
                      4,2,2,4,1,1,4,
                         10};


      EA=1;               //开总中断
      ET0=1;              //定时器T0中断允许
      TMOD=0X00;          //使用定时器T0的模式0(13位计数器)
      while(1)            //无限循环
       {
           i=0;
           while(1)
           {
              i=0;                     //从第一个音调f[0]开始播放
              while(f[i]!=0xff)        //只要没有读到结束标志就继续播放  
                  {
                      C=460830/f[i];
                      TH0=(8192-C)/32;   
                      TL0=(8192-C)%32;
                      TR0=1;
                      for(j=0;j<JP[i];j++)  //控制节拍数
                      delay();              //延时一个节拍单位
                       TR0=0;              //关闭定时器T0
                        i++;               //播放下一个音调
                   }
            }
}


void Time() interrupt 1
{
        deep=!deep;
        TH0=(8192-C)/32;
        TL0=(8192-C)%32;
}

















































分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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