单片机实习音乐播放器的源码

/*基于52单片机的源代码

sbit L=P2^2;

sbit LRW=P2^1;

sbit LRS=P2^0;

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

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

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

sbit K1=P1^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 delay1(void) //延时程序

uchar i,j; 

for(i=20;i>0;i--) 

for(j=248;j>0;j--); 

 

 void Getch (  )

{   uchar X,Y,Z;

P1=0xff;

P1=0xf3;       //先对P0置数  行扫描

if(P1!=0xf3)     //判断是否有键按下

{ delay1();    //延时,软件去干扰

  if(P1!=0xf3)   //确认按键按下X = P3;

   {

X=P1;          //保存行扫描时有键按下时状态

P1=0xfc;       //列扫描

Y=P1;          //保存列扫描时有键按下时状态

  Z=X|Y; 

        //取出键值

switch ( Z )   //判断键值(那一个键按下)

{

case 0xf9: k=0; break; //对键值赋值

case 0xf5: k=1; break; 

case 0xfa: k=2; break; 

case 0xf6: k=3; break;

        

}

   }

}

}   

 void Delay()

{  uint uiCount;

  for(uiCount=0;uiCount<250;uiCount++);

}

 

void WriteCMD(uchar Commond)//LCD写指令函数      

{

 Delay();    //先延时。

 L=1;     //然后把LCD改为写入命令状态。

 LRS=0;

 LRW=0;

 LPORT=Commond;  //再输出命令。

 LCDE=0;     //最后执行命令。

}

 

void WriteData(uchar dat)//LCD写数据函数      

{ Delay();      //先延时。

 L=1;       //然后把LCD改为写入数据状态。

 LRS=1;

 LRW=0;

 LPORT=dat;     //再输出数据。

 LE=0;       //最后显示数据。

}

 

void init()

{

  LRW=0;

    L=0;

   WriteCMD(0x38);

  WriteCMD(0x0c);

  WriteCMD(0x06);

  WriteCMD(0x01);

  WriteCMD(0x80);

}

 

void mydelay(int x)

{ int i,j;

 for(i=x;i>0;i--)

 for(j=255;j>0;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;

}

 

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;

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

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&&K1==1)//歌曲代码未放完且暂停键未被按下

{

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;

}

 

main()

{ uint i;

k=8;

init();

   for(i=0;i<15;i++)

     {

    WriteData(tab[i]); //LCD写数据函数写第一行

       mydelay(50);

}

    mydelay(1000);

    WriteCMD(0x80+0x40+2); //将指针设到第二行空两字符

    for(i=0;i<6;i++)

    {

        WriteData(tab1[i]);

       mydelay(50);

    }

 

InitialSound(); //发音初始化程序

while(1)

{  Getch(); //扫描键盘,获得键值

  if(k==0) //若键值为0

    { uint i;

   init();

          for(i=0;i<10;i++)

       {

    WriteData(tab2[i]); //写第一首歌序号

       mydelay(50);

       }

    mydelay(1000);

    WriteCMD(0x80+0x40); //转到第二行

    for(i=0;i<9;i++)

    { WriteData(tab3[i]); //写歌名

       mydelay(50);

    }

 

  Play(Music_Girl,0,3,360); //播放第一首歌

  mydelay(500);

break;

  }

  else if (k==1)  //若键值为1

{ uint i;

   init();

        for(i=0;i<11;i++)

       { WriteData(tab4[i]);  //写第二首歌序号

       mydelay(50);

       }

    mydelay(1000);

    WriteCMD(0x80+0x40);  //转到第二行

    for(i=0;i<11;i++)

    {

        WriteData(tab5[i]);  //写歌名

       mydelay(50);

    }

 

Play(Music_Jingle,0,3,360);//播放第二首歌

mydelay(500);

break;

}

  else if (k==2) //若键值为2

{ uint i;

   init();

   for(i=0;i<10;i++)

       { WriteData(tab6[i]);  //写第三首歌序号

       mydelay(50);

       }

    mydelay(1000);

    //WriteCMD(0x01);

    WriteCMD(0x80+0x40);  //转到第二行

    for(i=0;i<6;i++)

    {

        WriteData(tab7[i]);  //写歌名

       mydelay(50);

    }

 

Play(Music_Two,0,3,360);  //播放第三首歌

mydelay(500);

break;

  }

else if (k==3) //若键值为3

{ uint i;

   init();

       for(i=0;i<10;i++)

       { WriteData(tab8[i]);  //写第四首歌序号

       mydelay(50);

       }

    mydelay(1000);

WriteCMD(0x80+0x40);  //转到第二行

    for(i=0;i<6;i++)

    { WriteData(tab9[i]);  //写歌名

       mydelay(50);

    }

 

  Play(Music_Jingle,0,3,360);//播放第三首歌

mydelay(500);

break;

}

}

  • 5
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值