Chinaunix首页 | 论坛 | 博客
  • 博客访问: 25900
  • 博文数量: 5
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 55
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-01 14:54
文章分类
文章存档

2011年(1)

2007年(4)

我的朋友
最近访客

分类: C/C++

2007-06-07 16:59:14

关于单片机的音乐控制
   最近在网上浏览一些帖子,看见网友用C语言写了一个51单片机唱歌的程序。本人觉得很有参考价值,在这里转载一下。希望对初学单片机的朋友有点帮助。该程序是在Keil C51下开发的,本人修改了一下已经用于自己的作品上,效果还可以。
 

子程序如下:

/**************************************************************************
   

                         SOUND PLAY FOR 51MCU
  
                       COPYRIGHT (c) 2005 BY JJJ.
                               -- ALL RIGHTS RESERVED --
  
   File Name: SoundPlay.h
   Author: Jiang Jian Jun
   Created: 2005/5/16
   Modified:        NO
   Revision:         1.0
  
*******************************************************************************/


/*说明**************************************************************************
 曲谱存贮格式 unsigned char code MusicName{音高,音长,音高,音长...., 0,0};    末尾:0,0 表示结束(Important)

 音高由三位数字组成:
         个位是表示 1~7 这七个音符
         十位是表示音符所在的音区:1-低音,2-中音,3-高音;
         百位表示这个音符是否要升半音: 0-不升,1-升半音。
 
 音长最多由三位数字组成:
         个位表示音符的时值,其对应关系是:
             |数值(n): |0 |1 |2 |3 | 4 | 5 | 6
             |几分音符: |1 |2 |4 |8 |16 |32 |64         音符=2^n
         十位表示音符的演奏效果 (0-2): 0-普通,1-连音,2-顿音
         百位是符点位: 0-无符点,1-有符点

 调用演奏子程序的格式
         Play(乐曲名,调号,升降八度,演奏速度);
    |乐曲名 : 要播放的乐曲指针,结尾以(0,0)结束;
    |调号(0-11) :    是指乐曲升多少个半音演奏;
    |升降八度(1-3)     : 1:降八度, 2:不升不降, 3:升八度;
    |演奏速度(1-12000):    值越大速度越快;

***************************************************************************/

#ifndef __SOUNDPLAY_H_REVISION_FIRST__
#define __SOUNDPLAY_H_REVISION_FIRST__

//**************************************************************************


#define SYSTEM_OSC         12000000    //定义晶振频率12000000HZ

#define SOUND_SPACE     4/5         //定义普通音符演奏的长度分率,//每4分音符间隔

sbit BeepIO =     P3^7;        //定义输出管脚


unsigned int code FreTab[12] = { 262,277,294,311,330,349,369,392,415,440,466,494 }; //原始频率表

unsigned char code SignTab[7] = { 0,2,4,5,7,9,11 };                                  //1~7在频率表中的位置

unsigned char code LengthTab[7]= { 1,2,4,8,16,32,64 };                        
unsigned char Sound_Temp_TH0,Sound_Temp_TL0;    //音符定时器初值暂存

unsigned char Sound_Temp_TH1,Sound_Temp_TL1;    //音长定时器初值暂存

//**************************************************************************

void InitialSound(void)
{
    BeepIO = 0;
    Sound_Temp_TH1 = (65535-(1/1200)*SYSTEM_OSC)/256;    // 计算TL1应装入的初值     (10ms的初装值)

    Sound_Temp_TL1 = (65535-(1/1200)*SYSTEM_OSC)%256;    // 计算TH1应装入的初值

    TH1 = Sound_Temp_TH1;
    TL1 = Sound_Temp_TL1;
    TMOD |= 0x11;
    ET0 = 1;
    ET1     = 0;
    TR0     = 0;
    TR1 = 0;
    EA = 1;
}

void BeepTimer0(void) interrupt 1    //音符发生中断

{
    BeepIO = !BeepIO;
    TH0 = Sound_Temp_TH0;
     TL0 = Sound_Temp_TL0;
}
//**************************************************************************

void Play(unsigned char *Sound,unsigned char Signature,unsigned Octachord,unsigned int Speed)
{
    unsigned int NewFreTab[12];        //新的频率表

    unsigned char i,j;
    unsigned int Point,LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength;
    //Point 指针索引值

    //LDiv     音音符演奏的长度(多少个10ms)

    //LDiv0 1分音符的长度(几个10ms)即一个节拍    

    //LDiv4 4分音符的长度

    //CurrentFre 查出对应音符的频率

    //SoundLength歌曲长度

    //Temp_T计算计数器初值

    unsigned char Tone,Length,SL,SH,SM,SLen,XG,FD;
    //Tone音调

    //Length音长

    //SL音符

    //SM高低音

    //SH是否升半

    //XG音符类型(0普通1连音2顿音)

    for(i=0;i<12;i++)                 // 根据调号及升降八度来生成新的频率表

    {
        j = i + Signature;
        if(j > 11)
        {
            j = j-12;
            NewFreTab[i] = FreTab[j]*2;
        }
        else
            NewFreTab[i] = FreTab[j];

        if(Octachord == 1)
            NewFreTab[i]>>=2;
        else if(Octachord == 3)
            NewFreTab[i]<<=2;
    }                                    
    
    SoundLength = 0;
    while(Sound[SoundLength] != 0x00)    //计算歌曲长度

    {
        SoundLength+=2;
    }

    Point = 0;
    Tone = Sound[Point];    
    Length = Sound[Point+1];             // 读出第一个音符和它时时值

    
    LDiv0 = 12000/Speed;                // 算出1分音符的长度(几个10ms)     

    LDiv4 = LDiv0/4;                     // 算出4分音符的长度

    LDiv4 = LDiv4-LDiv4*SOUND_SPACE;     // 普通音最长间隔标准

    TR0     = 0;
    TR1 = 1;
    while(Point < SoundLength)
    {
        SL=Tone%10;                                 //计算出音符

        SM=Tone/10%10;                                 //计算出高低音

        SH=Tone/100;                                 //计算出是否升半

        CurrentFre = NewFreTab[SignTab[SL-1]+SH];     //查出对应音符的频率     

        if(SL!=0)
        {
            if (SM==1) CurrentFre >>= 2;         //低音

            if (SM==3) CurrentFre <<= 2;         //高音

            Temp_T = 65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC);//计算计数器初值

            Sound_Temp_TH0 = Temp_T/256;
            Sound_Temp_TL0 = Temp_T%256;
            TH0 = Sound_Temp_TH0;
            TL0 = Sound_Temp_TL0 + 12; //加12是对中断延时的补偿

        }
        SLen=LengthTab[Length%10];     //算出是几分音符

        XG=Length/10%10;             //算出音符类型(0普通1连音2顿音)

        FD=Length/100;
        LDiv=LDiv0/SLen;             //算出连音音符演奏的长度(多少个10ms)

        if (FD==1)
            LDiv=LDiv+LDiv/2;
        if(XG!=1)    
            if(XG==0)                 //算出普通音符的演奏长度

                if (SLen<=4)    
                    LDiv1=LDiv-LDiv4;
                else
                    LDiv1=LDiv*SOUND_SPACE;
            else
                LDiv1=LDiv/2;         //算出顿音的演奏长度

        else
            LDiv1=LDiv;
        if(SL==0) LDiv1=0;
            LDiv2=LDiv-LDiv1;         //算出不发音的长度

         if (SL!=0)
        {
            TR0=1;
            for(i=LDiv1;i>0;i--)     //发规定长度的音

            {
                while(TF1==0);
                TH1 = Sound_Temp_TH1;
                TL1 = Sound_Temp_TL1;
                TF1=0;
            }
        }
        if(LDiv2!=0)
        {
            TR0=0; BeepIO=0;
            for(i=LDiv2;i>0;i--)     //音符间的间隔

            {
                while(TF1==0);
                TH1 = Sound_Temp_TH1;
                TL1 = Sound_Temp_TL1;
                TF1=0;
            }
        }
        Point+=2;
        Tone=Sound[Point];
        Length=Sound[Point+1];
    }
    BeepIO = 0;
}

#endif

//**************************************************************************
主程序如下:

unsigned char code Music_Two[] ={ 0x17,0x03, 0x16,0x03, 0x17,0x01, 0x16,0x03, 0x17,0x03,
                                  0x16,0x03, 0x15,0x01, 0x10,0x03, 0x15,0x03, 0x16,0x02,
                                  0x16,0x0D, 0x17,0x03, 0x16,0x03, 0x15,0x03, 0x10,0x03,
                                  0x10,0x0E, 0x15,0x04, 0x0F,0x01, 0x17,0x03, 0x16,0x03,
                                  0x17,0x01, 0x16,0x03, 0x17,0x03, 0x16,0x03, 0x15,0x01,
                                  0x10,0x03, 0x15,0x03, 0x16,0x02, 0x16,0x0D, 0x17,0x03,
                                  0x16,0x03, 0x15,0x03, 0x10,0x03, 0x15,0x03, 0x16,0x01,
                                  0x17,0x03, 0x16,0x03, 0x17,0x01, 0x16,0x03, 0x17,0x03,
                                  0x16,0x03, 0x15,0x01, 0x10,0x03, 0x15,0x03, 0x16,0x02,
                                  0x16,0x0D, 0x17,0x03, 0x16,0x03, 0x15,0x03, 0x10,0x03,
                                  0x10,0x0E, 0x15,0x04, 0x0F,0x01, 0x17,0x03, 0x19,0x03,
                                  0x19,0x01, 0x19,0x03, 0x1A,0x03, 0x19,0x03, 0x17,0x01,
                                  0x16,0x03, 0x16,0x03, 0x16,0x02, 0x16,0x0D, 0x17,0x03,
                                  0x16,0x03, 0x15,0x03, 0x10,0x03, 0x10,0x0D, 0x15,0x00,
                                  0x19,0x03, 0x19,0x03, 0x1A,0x03, 0x1F,0x03, 0x1B,0x03,
                                  0x1B,0x03, 0x1A,0x03, 0x17,0x0D, 0x16,0x03, 0x16,0x03,
                                  0x16,0x0D, 0x17,0x01, 0x17,0x03, 0x17,0x03, 0x19,0x03,
                                  0x1A,0x02, 0x1A,0x02, 0x10,0x03, 0x17,0x0D, 0x16,0x03,
                                  0x16,0x01, 0x17,0x03, 0x19,0x03, 0x19,0x03, 0x17,0x03,
                                  0x19,0x02, 0x1F,0x02, 0x1B,0x03, 0x1A,0x03, 0x1A,0x0E,
                                  0x1B,0x04, 0x17,0x02, 0x1A,0x03, 0x1A,0x03, 0x1A,0x0E,
                                  0x1B,0x04, 0x1A,0x03, 0x19,0x03, 0x17,0x03, 0x16,0x03,
                                  0x17,0x0D, 0x16,0x03, 0x17,0x03, 0x19,0x01, 0x19,0x03,
                                  0x19,0x03, 0x1A,0x03, 0x1F,0x03, 0x1B,0x03, 0x1B,0x03,
                                  0x1A,0x03, 0x17,0x0D, 0x16,0x03, 0x16,0x03, 0x16,0x03,
                                  0x17,0x01, 0x17,0x03, 0x17,0x03, 0x19,0x03, 0x1A,0x02,
                                  0x1A,0x02, 0x10,0x03, 0x17,0x0D, 0x16,0x03, 0x16,0x01,
                                  0x17,0x03, 0x19,0x03, 0x19,0x03, 0x17,0x03, 0x19,0x03,
                                  0x1F,0x02, 0x1B,0x03, 0x1A,0x03, 0x1A,0x0E, 0x1B,0x04,
                                  0x17,0x02, 0x1A,0x03, 0x1A,0x03, 0x1A,0x0E, 0x1B,0x04,
                                  0x17,0x16, 0x1A,0x03, 0x1A,0x03, 0x1A,0x0E, 0x1B,0x04,
                                  0x1A,0x03, 0x19,0x03, 0x17,0x03, 0x16,0x03, 0x0F,0x02,
                                  0x10,0x03, 0x15,0x00, 0x00,0x00 };
//***********************************************************************************
main()
{
 InitialSound();
 while(1)
 {
  Play(Music_Two,0,3,300);
  Delay1ms(500);
 }
}

 

阅读(1436) | 评论(3) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-05-22 21:18:09

http://www.5y3c.com/ http://www.955966.com/ http://www.liuhecaitema.net/ http://www.liuhecaikaiziliao.info/ http://www.liuhecaikaijiangjieguo.info/ http://www.3g8888.com/ http://www.15194.com/ http://www.46199.com/ http://www.3uu1.com/ http://www.1add5.com/ http://www.51lzy.com/ http://www.gift818.com/ http://www.ahlhedu.cn/ http://www.sdqlkc.com/ http://www.zjlthk.com/ http://www.cnhanfu.com/ http://www.smart-car.com.cn/ http://www.dzongsal.com/ http://www.yn800.com/

chinaunix网友2010-05-22 21:17:29

http://www.bandaoxx.com/ http://www.06610.info/ http://www.05552.info/ http://www.855766.com/ http://www.055088.com/ http://www.61220.com/ http://www.633588.com/ http://www.022088.com/ http://www.liuhecaikaijiang.com/ http://www.188200.com/ http://www.03877.com/ http://www.955966.com/ http://www.188200.net/ http://www.f7775.com/ http://www.668768.com/ http://www.ff118.com/ http://www.shwanju888.com.cn/ http://www.87709.com/ http://www.57505.com/ http://www.05877.com/ ht

chinaunix网友2008-12-11 12:56:48

很复杂