×
单片机 > 单片机程序设计 > 详情

单片机编程 音乐编程程序

发布时间:2020-06-06 发布时间:
|
#include 

#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long


sbit BEEP=P2^0; //喇叭输出脚

uchar th0_f; //在中断中装载的T0的值高8位
uchar tl0_f; //在中断中装载的T0的值低8位
uchar key;

/*------------------------------------------------
                   函数声明
------------------------------------------------*/
uchar keyscan(void);//键盘扫描程序
void delay(uint i); //延时子程序

/*-------- T0的值,及输出频率对照表 --------------*/
uchar code freq[36*2]={
    0xA9,0xEF,            //0x3F,0XEE,//00220HZ ,1 //0
 0x93,0xF0,            //0X3D,0XEF,//00233HZ ,1#
 0x73,0xF1,            //0X30,0XF0,//00247HZ ,2
 0x49,0xF2,            //0X18,0XF1,//00262HZ ,2#
 0x07,0xF3,            //0XE6,0XF1,//00277HZ ,3
 0xC8,0xF3,             //0XB7,0XF2,//00294HZ ,4
 0x73,0xF4,             //0X71,0XF3,//00311HZ ,4#
 0x1E,0xF5,             //0X2A,0XF4,//00330HZ ,5
 0xB6,0xF5,             //0XCF,0XF4,//00349HZ ,5#
 0x4C,0xF6,             //0X72,0XF5,//00370HZ ,6
 0xD7,0xF6,             //0X09,0XF6,//00392HZ ,6#
 0x5A,0xF7,             //0X97,0XF6,//00415HZ ,7
 0xD8,0xF7,              //0X20,0XF7,//00440HZ 1   //12
 0x4D,0xF8,              //0X9F,0XF7,//00466HZ 1#  //13
 0xBD,0xF8,              //0X18,0XF8,//00494HZ 2   //14
 0x24,0xF9,              //0X88,0XF8,//00523HZ 2#  //15
 0x87,0xF9,              //0XF3,0XF8,//00554HZ 3   //16
 0xE4,0xF9,              //0X59,0XF9,//00587HZ 4   //17
 0x3D,0xFA,               //0X05,0XFA,//00622HZ 4# //18
 0x90,0xFA,              //0X13,0XFA,//00659HZ 5   //19
 0xDE,0xFA,               //0X66,0XFA,//00698HZ 5# //20
 0x29,0xFB,             //0XB9,0XFA,//00740HZ 6    //21
 0x6F,0xFB,               //0X05,0XFB,//00784HZ 6# //22
 0xB1,0xFB,                //0X4D,0XFB,//00831HZ 7 //23
 0xEF,0xFB,                 //0X90,0XFB,//00880HZ `1
 0x2A,0xFC,                 //0XD0,0XFB,//00932HZ `1#
 0x62,0xFC,                //0X0C,0XFC,//00988HZ `2
 0x95,0xFC,                   //0X44,0XFC,//01046HZ `2#
 0xC7,0xFC,               //0X7B,0XFC,//01109HZ `3
 0xF6,0xFC,                 //0XAD,0XFC,//01175HZ `4
    0x22,0xFD,                  //0XDD,0XFC,//01244HZ `4#
    0x4B,0xFD,                 //0X0A,0XFD,//01318HZ `5
    0x73,0xFD,                //0X35,0XFD,//01397HZ `5#
    0x98,0xFD,              //0X5D,0XFD,//01480HZ `6
    0xBB,0xFD,               //0X83,0XFD,//01568HZ `6#
    0xDC,0xFD,                 //0XA6,0XFD,//01661HZ `7 //35
};

//定时中断0,用于产生唱歌频率
timer0() interrupt 1
{
   TL0=tl0_f;TH0=th0_f; //调入预定时值
   BEEP=~BEEP; //取反音乐输出IO
}

//音乐符号串解释函数
//入口:要解释的音乐符号串,输出的音调串,输出的时长串
changedata(uchar *song,uchar *diao,uchar *jie)
{
 uchar i,i1,j;
 char gaodi; //高低+/-12音阶
 uchar banyin;//有没有半个升音阶
 uchar yinchang;//音长
 uchar code jie7[8]={0,12,14,16,17,19,21,23}; //C调的7个值
 *diao=*song;
 for(i=0,i1=0;;)
 {
  gaodi=0; //高低=0
  banyin=0;//半音=0
  yinchang=4;//音长1拍
  if((*(song+i)=='|') || (*(song+i)==' ')) i++;
  //拍子间隔和一个空格过滤
  switch(*(song+i))
  {
   case ',': gaodi=-12;i++;//低音
   break;
   case '`': gaodi=12;i++; //高音
   break;
  }
  if(*(song+i)==0) //遇到0结束
  {
   *(diao+i1)=0; //加入结束标志0
   *(jie+i1)=0;
   return;
  }
  j=*(song+i)-0x30; i++; //取出基准音
  j=jie7[j]+gaodi; //加上高低音
  yinc: switch(*(song+i))
  {
   case '#': //有半音j加一个音阶
   i++;j++;
   goto yinc;
   case '-': //有一个音节加长
   yinchang+=4;
   i++;
   goto yinc;
   case '_': //有一个音节缩短
   yinchang/=2;
   i++;
   goto yinc;
   case '.': //有一个加半拍
   yinchang=yinchang+yinchang/2;
   i++;
   goto yinc;
  }
  *(diao+i1)=j; //记录音符
  *(jie+i1)=yinchang; //记录音长
  i1++;
 }
}

//奏乐函数
//入口:要演奏的音乐符号串
void play(uchar *songdata)
{
 uchar i,c,j=0;
 uint n;
 uchar diaodata[48]; //音调缓冲
 uchar jiedata[48]; //音长缓冲
 changedata(songdata,diaodata,jiedata); //解释音乐符号串
 TR0=1;
 for(i=0;diaodata[i]!=0;i++) //逐个符号演奏
 {
  tl0_f=freq[diaodata[i]*2]; //取出对应的定时值送给T0
  th0_f=freq[diaodata[i]*2+1];
  for(c=0;c   { key = keyscan();
   for(n=0;n<29500;n++); // 29500
   if(key != 0xff)//((!K1)||(!K2)||(!K3)||(!K4))//发现按键,立即退出播放
   {
    TR0=0;
    return;
   }
  }
  TR0=0;
  for(n=0;n<460;n++); //460音符间延时
  TR0=1;
 }
 TR0=0;
}

//一分钱
uchar code yifenqian[]={
                  "5`1|6_`1_5|3_5_2_3_|5-|"
                  "3_5_6_`1_|5_6_5_3_|1.3__|2-|"
                  "3_2_1_2_|3-|6_5_3_5_|6-|"
                        "5_`1_6_5_|3_5_2|5_2_3_2_|1-|"
                        };

//世上只有妈妈好
uchar code mamahao[]={
                      "6.5_35|`16_5_6-|35_6_53_2_|1_,6_5_3_2-|"
                      "2.3_55_6_|321-|5.3_2_1_,6_1_|,5--"
                     };
//找朋友
uchar code zhaopengyou[]={ "5_6_5_6_|5_6_5|5_`1_7_6_|5 3|"
                         "5_5_3_4_|5_5_3|1_4_3_2_|1_2_1|"
                       };
//茉莉花
uchar code molihua[]={"33_5_6_`1_`1_6_|55_6_5-|33_5_6_`1_`1_6_|55_6_5-|"
                       "5553_5_|665-|32_3_53_2_|11_2_1|"
                       //"3_2_1_3_2.3_|56_`1_5-|23_5_2_3_1_,6_|,5-,61|"
                       //"2.3_1_2-1_,6_|,5--"
       };
//新年好
uchar code xinnianhao[]={
   "1_1_1 ,5|3_3_3 1|1_3_5 5|4_3_2-|"
   "2_3_4-|3_2_3 1|1_3_2 ,5|,7_2_1-|"
};
//小星星
uchar code xingxing[]={
                       "1155|665-|4433|221-|"
                       "5544|332-|5544|332-|"
                       "1155|665-|4433|221-|"
};
//外婆的澎湖湾
uchar code waipodephw[]={
                        "3_5_5_5_6_`1_6_5_|`1_`1_`1_6_5-|"
                        "`3_`3_`3_`3_`4_`3_`2_`1_|`2_`2_`2_`3_`2-|"
                        "`3_`3_`3_`3_`4_`3_`2_`1_|6_`1_`1_6_5-|"
                        };
}

//春天在哪里
uchar code chuntian[]={"3_3_3_1_|,5,5|3_3_3_1_|3-|5_5_3_1_|,5_,5_,5|,6_,7_1_3_|2-|"
                       "3_3_3_1_|,5,5|3_3_3_1_|3-|5_6_5_6_|5_4_3_1_|,53|1-|"
                      };

//两只老虎
uchar code laohu[]={"1231|1231|345-|345-|5_6_5_4_31|5_6_5_4_31|"
                    "151-|151-"
                   };

/*------------------------------------------------
              键盘扫描程序
------------------------------------------------*/
uchar keyscan(void)  //键盘扫描函数,使用行列反转扫描法
{
  uchar cord_h,cord_l;//行列值中间变量
  P3=0x0f;            //行线输出全为0
  cord_h=P3&0x0f;     //读入列线值
  if(cord_h!=0x0f)    //先检测有无按键按下
  {
    delay(100);        //去抖
    if(cord_h!=0x0f)
    {
       cord_h=P3&0x0f;  //读入列线值
       P3=cord_h|0xf0;  //输出当前列线值
       cord_l=P3&0xf0;  //读入行线值
       return(cord_h+cord_l);//键盘最后组合码值
    }
   }
   return(0xff);     //返回该值
}
/*------------------------------------------------
                 延时程序
------------------------------------------------*/
void delay(uint i)  //延时函数
{
 while(i--);
}
//乐谱方式输入的音乐播放,
void main(void) // 主程序
{
 uchar code jie8[8]={12,14,16,17,19,21,23,24};//1234567`1八个音符在频率表中的位置
 uchar i = 0;
    uchar n = 0;
 TMOD = 0x01; //使用定时器0的16位工作模式
 TR0 = 0;
 ET0 = 1;
 EA = 1;
 
 while(1)
 { 
   key = keyscan();
   switch(key)
   {
     case 0x7e:
         while(key == 0x7e)
       {
        key = keyscan();
       }
       play(molihua);
       break;//0
     case 0x7d:
         while(key == 0x7d)
       {
        key = keyscan();
       }
       play(yifenqian);
       break;//1
     case 0x7b: while(key == 0x7b)
         {
        key = keyscan();
       }
       play(chuntian);
       break;//2
     case 0x77: while(key == 0x77)
         {
        key = keyscan();
       }
       play(waipodephw);
       break;//3
     case 0xbe: while(key == 0xbe)
         {
        key = keyscan();
       }
       play(xingxing);
       break;//4
     case 0xbd: while(key == 0xbd)
         {
        key = keyscan();
       }
       play(xinnianhao);
       break;//5
     case 0xbb: while(key == 0xbb)
         {
        key = keyscan();
       }
       play(mamahao);
       break;//6
     case 0xb7: while(key == 0xb7)
         {
        key = keyscan();
       }
       play(zhaopengyou);
       break;//7
     case 0xde: while(!(key ^ 0xde))
       {
        tl0_f=freq[jie8[0]*2]; //置一个音符的值
        th0_f=freq[jie8[0]*2+1];
        TR0 = 1;
        key = keyscan();
        //for(n=0;n<10000;n++); //延时
       }
         break;//8
     case 0xdd: while(!(key ^ 0xdd))
       {
        tl0_f=freq[jie8[1]*2]; //置一个音符的值
        th0_f=freq[jie8[1]*2+1];
        TR0 = 1;
        key = keyscan();
        //for(n=0;n<10000;n++); //延时
       } 
       break;//9
     case 0xdb: while(!(key ^ 0xdb))
       {
        tl0_f=freq[jie8[2]*2]; //置一个音符的值
        th0_f=freq[jie8[2]*2+1];
        TR0 = 1;
        key = keyscan();
        //for(n=0;n<10000;n++); //延时
       }
       break;//a
     case 0xd7: while(!(key ^ 0xd7))
       {
        tl0_f=freq[jie8[3]*2]; //置一个音符的值
        th0_f=freq[jie8[3]*2+1];
        TR0 = 1;
        key = keyscan();
        //for(n=0;n<10000;n++); //延时
       }
       break;//b
     case 0xee: while(!(key ^ 0xee))
       {
        tl0_f=freq[jie8[4]*2]; //置一个音符的值
        th0_f=freq[jie8[4]*2+1];
        TR0 = 1;
        key = keyscan();
        //for(n=0;n<10000;n++); //延时
       }break;//c
     case 0xed: while(!(key ^ 0xed))
       {
        tl0_f=freq[jie8[5]*2]; //置一个音符的值
        th0_f=freq[jie8[5]*2+1];
        TR0 = 1;
        key = keyscan();
        //for(n=0;n<10000;n++); //延时
       }break;//d
     case 0xeb: while(!(key ^ 0xeb))
       {
        tl0_f=freq[jie8[6]*2]; //置一个音符的值
        th0_f=freq[jie8[6]*2+1];
        TR0 = 1;
        key = keyscan();
        //for(n=0;n<10000;n++); //延时
       }break;//e
     case 0xe7: while(!(key ^ 0xe7))
       {
        tl0_f=freq[jie8[7]*2]; //置一个音符的值
        th0_f=freq[jie8[7]*2+1];
        TR0 = 1;
        key = keyscan();
        //for(n=0;n<10000;n++); //延时
       }break;//f
    default:   break;
   }
   TR0 = 0;
  /*if(!K1)
  {
      tl0_f=freq[jie8[0]*2]; //置一个音符的值
      th0_f=freq[jie8[0]*2+1];
      TR0 = 1;
      for(n=0;n<10000;n++); //延时
  }
  if(!K2)
  {
      tl0_f=freq[jie8[1]*2]; //置一个音符的值
      th0_f=freq[jie8[1]*2+1];
      TR0 = 1;
      for(n=0;n<10000;n++); //延时
  }
  if(!K3)
  {
      tl0_f=freq[jie8[2]*2]; //置一个音符的值
      th0_f=freq[jie8[2]*2+1];
      TR0 = 1;
      for(n=0;n<10000;n++); //延时
  }
  if(!K4)
  {
      tl0_f=freq[jie8[3]*2]; //置一个音符的值
      th0_f=freq[jie8[3]*2+1];
      TR0 = 1;
      for(n=0;n<10000;n++); //延时
  }
      TR0 = 0;
  if(!K1)
  {
   while(!K1);
   play(molihua); //播放音乐
  }
  if(!K2)
  {
   while(!K2);
   play(dami); //播放音乐
  }
  if(!K3)
  {
   while(!K3);
   play(mamahao); //播放音乐
  }
  if (!K4)
  {
   switch(i)
   {
    case 0:
    play(xianjian); //播放音乐
    break;
    case 1:
    play(song3); //播放音乐
    break;
    case 2:
    play(mamahao); //播放音乐
    break;
    case 3:
    play(boluo); //播放音乐
    break;
    case 4:
    play(xingxing); //播放音乐
    break;
    case 5:
    play(dami); //播放音乐
    break;
   }
   i++;if(i==6)i=0;
  }*/
 }




『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
51单片机的数码管动态扫描方法