找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于单片机的音乐播放

[复制链接]
跳转到指定楼层
楼主
#include "MusicPlay.h"
unsigned char *PP[]={song1,song2,song3};//指向歌曲的指针数组
unsigned char *p;//只想歌曲的指针
unsigned int Point = 0;//歌曲播放位置
bit flag_pause=1;//暂停标志位
bit flag_up=0;//上一曲标志位
bit flag_down=0;//下一曲标志位
int flag_order=0;//歌曲顺序
void Delay1ms(unsigned int count);//简单延时
void InitialSound(void);//初始化
void Play(unsigned char *sound,unsigned char Signature,unsigned Octachord,unsigned int Speed);//音乐播放函数
//******************主程序***************************************************
void main()
{
    InitialSound();
    while(1)
    {
        if(k_state==0)//有按键按下
        {
            if(k_pause==0)//开始/暂停键
            {
                while(k_pause==0);
                flag_pause=~flag_pause;
            }
        }
        while(!flag_pause)
        {
            Play(p+Point,0,3,360);
            Delay1ms(300);
            if(flag_down | flag_up)
            {
                if(flag_down) flag_down=0;
                if(flag_up)   flag_up  =0;
                Point = 0;
            }
            else flag_order++;
            if(flag_pause==1) flag_order--;
        
            if(flag_order == 3)
                flag_order = 0;
            p=PP[flag_order];   
        }
    }
}
//***********************中断服务程序*************************************//
void BeepTimer0(void) interrupt 1   //音符中断程序
{
    BeepIO = !BeepIO;
    TH0    = Sound_Temp_TH0;
    TL0    = Sound_Temp_TL0;
}
//***********************简单延时*******************************************//
void Delay1ms(unsigned int count)
{
    unsigned int i,j;
    for(i=0;i<count;i++)
    for(j=0;j<120;j++);
}
//***********************系统初始化********************************************//
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;
    p=PP[0];
}
/****************************音乐播放函数***************************************/
/*  input:歌曲名sound
                    调号signature
          音阶octachord
                    速度speed
*/
void Play(unsigned char *sound,unsigned char Signature,unsigned Octachord,unsigned int Speed)
{
    unsigned int NewFreTab[12];//新的频率表
    unsigned char i,j;
    unsigned int LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength;
    unsigned char Tone,Length,SL,SH,SM,SLen,XG,FD;
    if(p==song1) flag_order=0;
    else if (p==song2) flag_order=1;
    else if (p==song3)  flag_order=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=p[Point];
        Length=p[Point+1];
//按键扫描
        if(k_state==0)
        {//扫描开始
            if(k_pause==0)
            {
                while(k_pause==0);
                flag_pause=~flag_pause;
                TR1   = flag_pause;
                return;
            }
            if(k_up==0)
            {
                while(k_up==0);
                flag_up=~flag_up;
                flag_order--;
                if(flag_order < 0)
                    flag_order = 2;//第三首
                 p=PP[flag_order];
                break;
            }
            if(k_down==0)
            {
                while(k_down==0);
                flag_down=~flag_down;
                flag_order++;
                if(flag_order > 2)
                    flag_order=0;//第一首
                 p=PP[flag_order];
                break;
            }
        }//按键扫描结束
    }
    BeepIO = 0;//播放结束,关闭
}#include "MusicPlay.h"
unsigned char *PP[]={song1,song2,song3};//指向歌曲的指针数组
unsigned char *p;//只想歌曲的指针
unsigned int Point = 0;//歌曲播放位置
bit flag_pause=1;//暂停标志位
bit flag_up=0;//上一曲标志位
bit flag_down=0;//下一曲标志位
int flag_order=0;//歌曲顺序
void Delay1ms(unsigned int count);//简单延时
void InitialSound(void);//初始化
void Play(unsigned char *sound,unsigned char Signature,unsigned Octachord,unsigned int Speed);//音乐播放函数
//******************主程序***************************************************
void main()
{
    InitialSound();
    while(1)
    {
        if(k_state==0)//有按键按下
        {
            if(k_pause==0)//开始/暂停键
            {
                while(k_pause==0);
                flag_pause=~flag_pause;
            }
        }
        while(!flag_pause)
        {
            Play(p+Point,0,3,360);
            Delay1ms(300);
            if(flag_down | flag_up)
            {
                if(flag_down) flag_down=0;
                if(flag_up)   flag_up  =0;
                Point = 0;
            }
            else flag_order++;
            if(flag_pause==1) flag_order--;
        
            if(flag_order == 3)
                flag_order = 0;
            p=PP[flag_order];   
        }
    }
}
//***********************中断服务程序*************************************//
void BeepTimer0(void) interrupt 1   //音符中断程序
{
    BeepIO = !BeepIO;
    TH0    = Sound_Temp_TH0;
    TL0    = Sound_Temp_TL0;
}
//***********************简单延时*******************************************//
void Delay1ms(unsigned int count)
{
    unsigned int i,j;
    for(i=0;i<count;i++)
    for(j=0;j<120;j++);
}
//***********************系统初始化********************************************//
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;
    p=PP[0];
}
/****************************音乐播放函数***************************************/
/*  input:歌曲名sound
                    调号signature
          音阶octachord
                    速度speed
*/
void Play(unsigned char *sound,unsigned char Signature,unsigned Octachord,unsigned int Speed)
{
    unsigned int NewFreTab[12];//新的频率表
    unsigned char i,j;
    unsigned int LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength;
    unsigned char Tone,Length,SL,SH,SM,SLen,XG,FD;
    if(p==song1) flag_order=0;
    else if (p==song2) flag_order=1;
    else if (p==song3)  flag_order=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=p[Point];
        Length=p[Point+1];
//按键扫描
        if(k_state==0)
        {//扫描开始
            if(k_pause==0)
            {
                while(k_pause==0);
                flag_pause=~flag_pause;
                TR1   = flag_pause;
                return;
            }
            if(k_up==0)
            {
                while(k_up==0);
                flag_up=~flag_up;
                flag_order--;
                if(flag_order < 0)
                    flag_order = 2;//第三首
                 p=PP[flag_order];
                break;
            }
            if(k_down==0)
            {
                while(k_down==0);
                flag_down=~flag_down;
                flag_order++;
                if(flag_order > 2)
                    flag_order=0;//第一首
                 p=PP[flag_order];
                break;
            }
        }//按键扫描结束
    }
    BeepIO = 0;//播放结束,关闭
}


untitled.png (278.08 KB, 下载次数: 53)

untitled.png

音乐r.zip

18.57 KB, 下载次数: 10, 下载积分: 黑币 -5

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

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

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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