Keil C51学习 6 控制播放音乐

变频救护车

#include<reg52.h>//包含访问sfr库函数
#define uchar unsigned char //定义一下方便使用
#define uint unsigned int 
#define ulong unsigned long
sbit BEEP=P1^0;
sbit K1=P3^2; 

//变频声救护车报警信号输出试验
main()
{
     uint n; 
         ulong ul;
 while(1) //程序循环
 { 
 //输出约 1 秒种一个频率的声音
     for(ul=0;ul<3000;ul++) 
     { 
     for(n=0;n<80;n++); //延时
     BEEP=~BEEP; //取反输出到喇叭的信号
     } 

     //输出约 1 秒种另一个频率的声音
     for(ul=0;ul<2500;ul++) 
     { 
     for(n=0;n<100;n++); //延时
     BEEP=~BEEP; //取反输出到喇叭的信号
     } 
 }
}
变频声救护车报警信号输出试验
音阶声音自动输出试验
#include<reg52.h>//包含访问sfr库函数
#define uchar unsigned char //定义一下方便使用
#define uint unsigned int 
#define ulong unsigned long
sbit BEEP=P1^0;
uchar th0_f; //在中断中装载的 T0 的值高 8 位
uchar tl0_f; //在中断中装载的 T0 的值低 8 位
//T0 的值,及输出频率对照表
uchar code freq[36*2]={ 
 0xA9,0xEF,//00220HZ ,1 //0 
 0x93,0xF0,//00233HZ ,1# 
 0x73,0xF1,//00247HZ ,2 
 0x49,0xF2,//00262HZ ,2# 
 0x07,0xF3,//00277HZ ,3 
 0xC8,0xF3,//00294HZ ,4 
 0x73,0xF4,//00311HZ ,4# 
 0x1E,0xF5,//00330HZ ,5 
 0xB6,0xF5,//00349HZ ,5# 
 0x4C,0xF6,//00370HZ ,6 
 0xD7,0xF6,//00392HZ ,6# 
 0x5A,0xF7,//00415HZ ,7 
 0xD8,0xF7,//00440HZ 1 //12 
 0x4D,0xF8,//00466HZ 1# //13 
 0xBD,0xF8,//00494HZ 2 //14 
 0x24,0xF9,//00523HZ 2# //15 
 0x87,0xF9,//00554HZ 3 //16 
 0xE4,0xF9,//00587HZ 4 //17 
 0x3D,0xFA,//00622HZ 4# //18 
 0x90,0xFA,//00659HZ 5 //19 
 0xDE,0xFA,//00698HZ 5# //20 
 0x29,0xFB,//00740HZ 6 //21 
 0x6F,0xFB,//00784HZ 6# //22 
 0xB1,0xFB,//00831HZ 7 //23 
 0xEF,0xFB,//00880HZ `1 
 0x2A,0xFC,//00932HZ `1# 
 0x62,0xFC,//00988HZ `2 
 0x95,0xFC,//01046HZ `2# 
 0xC7,0xFC,//01109HZ `3 
 0xF6,0xFC,//01175HZ `4 
 0x22,0xFD,//01244HZ `4# 
 0x4B,0xFD,//01318HZ `5 
 0x73,0xFD,//01397HZ `5# 
 0x98,0xFD,//01480HZ `6 
 0xBB,0xFD,//01568HZ `6# 
 0xDC,0xFD,//01661HZ `7 //35 
};

//定时中断 0,用于产生唱歌频率
timer0() interrupt 1 
{ 
 TL0=tl0_f;TH0=th0_f; //调入预定时值
 BEEP=~BEEP; //取反音乐输出 IO  
}
//音阶声音自动输出试验
void main(void) // 主程序
{ 
 ulong n; 
 uchar i; 
 uchar code jie8[8]={12,14,16,17,19,21,23,24};//1234567`1 八个音符在频率表中的位置
 TMOD = 0x01; //使用定时器 0 的 16 位工作模式
 TR0 = 1; 
 ET0 = 1; 
 EA = 1; 
 while(1) 
 { 
 for(i=0;i<8;i++) //循环播放 8 个音符
 { 
 
 tl0_f=freq[jie8[i]*2]; //置一个音符的值
 th0_f=freq[jie8[i]*2+1]; 
 for(n=0;n<50000;n++); //延时 1 秒左右
 
 } 
 } 
}
//音阶声音自动输出试验

按键控制音阶声音输出(电子琴)

#include<reg52.h>//包含访问sfr库函数
#define uchar unsigned char //定义一下方便使用
#define uint unsigned int 
#define ulong unsigned long
sbit BEEP=P1^0; //喇叭输出脚
sbit K1= P3^2; 
sbit K2= P3^3; 
sbit K3= P3^4; 
sbit K4= P3^5; 
uchar th0_f; //在中断中装载的 T0 的值高 8 位
uchar tl0_f; //在中断中装载的 T0 的值低 8 位
//T0 的值,及输出频率对照表
uchar code freq[36*2]={ 
 0xA9,0xEF,//00220HZ ,1 //0 
 0x93,0xF0,//00233HZ ,1# 
 0x73,0xF1,//00247HZ ,2 
 0x49,0xF2,//00262HZ ,2# 
 0x07,0xF3,//00277HZ ,3 
 0xC8,0xF3,//00294HZ ,4 
 0x73,0xF4,//00311HZ ,4# 
 0x1E,0xF5,//00330HZ ,5 
 0xB6,0xF5,//00349HZ ,5# 
 0x4C,0xF6,//00370HZ ,6 
 0xD7,0xF6,//00392HZ ,6# 
 0x5A,0xF7,//00415HZ ,7 
 0xD8,0xF7,//00440HZ 1 //12 
 0x4D,0xF8,//00466HZ 1# //13 
 0xBD,0xF8,//00494HZ 2 //14 
 0x24,0xF9,//00523HZ 2# //15 
 0x87,0xF9,//00554HZ 3 //16 
 0xE4,0xF9,//00587HZ 4 //17 
 0x3D,0xFA,//00622HZ 4# //18 
 0x90,0xFA,//00659HZ 5 //19 
 0xDE,0xFA,//00698HZ 5# //20 
 0x29,0xFB,//00740HZ 6 //21 
 0x6F,0xFB,//00784HZ 6# //22 
 0xB1,0xFB,//00831HZ 7 //23 
 0xEF,0xFB,//00880HZ `1 
 0x2A,0xFC,//00932HZ `1# 
 0x62,0xFC,//00988HZ `2 
 0x95,0xFC,//01046HZ `2# 
 0xC7,0xFC,//01109HZ `3 
 0xF6,0xFC,//01175HZ `4 
 0x22,0xFD,//01244HZ `4# 
 0x4B,0xFD,//01318HZ `5 
 0x73,0xFD,//01397HZ `5# 
 0x98,0xFD,//01480HZ `6 
 0xBB,0xFD,//01568HZ `6# 
 0xDC,0xFD,//01661HZ `7 //35 
}; 
//定时中断 0,用于产生唱歌频率
timer0() interrupt 1 
{ 
 TL0=tl0_f;TH0=th0_f; //调入预定时值
 BEEP=~BEEP; //取反音乐输出 IO 
} 
//按键控制音阶声音输出(电子琴)
void main(void) // 主程序
{ 
 ulong n; 
 uchar code jie8[8]={12,14,16,17,19,21,23,24};//1234567`1 八个音符在频率表中的位置
 TMOD = 0x01; //使用定时器 0 的 16 位工作模式
 TR0 = 0; 
 ET0 = 1; 
 EA = 1; 
 while(1) 
 { 
 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; 
 } 
}
按键控制音阶声音输出(电子琴)

 乐谱方式输入的音乐播放,仙剑奇侠传

乐谱解释函数,是逐个字符解释的。
  遇到拍子分隔符和空格跳过,判断是否高低音,读音符,调整为高低音音符,读音符后的升半个音符的“#”,读延长音“-”“.”,读缩短一半音长的“_”,字符串结束符“0x00”。请仔细领会这个函数。
 
  奏乐函数就比较简单,基本上就是从数组中取出音符和时长,送入定时器预置数,再延时即可。在每个音符播放前后,用 TR0 控制是否输出音乐,每个音符之间也有短暂静音,以使音乐更为清晰。
  在本程序中,播放音乐函数中,我们使用了 xdata 的空间的 RAM,这是因为乐谱的数据需要比较多的内存,data 和 idata 空间已经放不下了的原因。
如果你把这个程序烧写到一片没有 XRAM 的芯片中,比如 at89c52 之类,就会出现无法运行的现象。在使用没有 XRAM 的 51 芯片时,如果使用了 XRAM,则要在总线上外加一个内存芯片,比如 62256
之类。
    完全看懂了程序之后,请编译运行,观察结果。按全速,可以听到美妙的仙剑音乐从蜂鸣器中传出,真是太奇妙了
#include<reg52.h>//包含访问sfr库函数
#define uchar unsigned char //定义一下方便使用
#define uint unsigned int 
#define ulong unsigned long
sbit BEEP=P1^0; //喇叭输出脚
sbit K1= P3^2; 
sbit K2= P3^3; 
sbit K3= P3^4; 
sbit K4= P3^5; 
uchar th0_f; //在中断中装载的 T0 的值高 8 位
uchar tl0_f; //在中断中装载的 T0 的值低 8 位
//T0 的值,及输出频率对照表
uchar code freq[36*2]={ 
 0xA9,0xEF,//00220HZ ,1 //0 
 0x93,0xF0,//00233HZ ,1# 
 0x73,0xF1,//00247HZ ,2 
 0x49,0xF2,//00262HZ ,2# 
 0x07,0xF3,//00277HZ ,3 
 0xC8,0xF3,//00294HZ ,4 
 0x73,0xF4,//00311HZ ,4# 
 0x1E,0xF5,//00330HZ ,5 
 0xB6,0xF5,//00349HZ ,5# 
 0x4C,0xF6,//00370HZ ,6 
 0xD7,0xF6,//00392HZ ,6# 
 0x5A,0xF7,//00415HZ ,7 
 0xD8,0xF7,//00440HZ 1 //12 
 0x4D,0xF8,//00466HZ 1# //13 
 0xBD,0xF8,//00494HZ 2 //14 
 0x24,0xF9,//00523HZ 2# //15 
 0x87,0xF9,//00554HZ 3 //16 
 0xE4,0xF9,//00587HZ 4 //17 
 0x3D,0xFA,//00622HZ 4# //18 
 0x90,0xFA,//00659HZ 5 //19 
 0xDE,0xFA,//00698HZ 5# //20 
 0x29,0xFB,//00740HZ 6 //21 
 0x6F,0xFB,//00784HZ 6# //22 
 0xB1,0xFB,//00831HZ 7 //23 
 0xEF,0xFB,//00880HZ `1 
 0x2A,0xFC,//00932HZ `1# 
 0x62,0xFC,//00988HZ `2 
 0x95,0xFC,//01046HZ `2# 
 0xC7,0xFC,//01109HZ `3 
 0xF6,0xFC,//01175HZ `4 
 0x22,0xFD,//01244HZ `4# 
 0x4B,0xFD,//01318HZ `5 
 0x73,0xFD,//01397HZ `5# 
 0x98,0xFD,//01480HZ `6 
 0xBB,0xFD,//01568HZ `6# 
 0xDC,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 xdata diaodata[112]; //音调缓冲
 uchar xdata jiedata[112]; //音长缓冲
 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<jiedata[i];c++) //按照音长延时
 for(n=0;n<32000;n++); 
 TR0=0; 
 for(n=0;n<500;n++); //音符间延时
 TR0=1; 
 } 
 TR0=0; 
} 
//仙剑
uchar code xianjian[]={ 
"|3_3_3_2_3-|2_3_2_2_,6,6_,7_|12_1_,7,6_,5_|,6---|" 
"3_3_3_2_3.6_|5_6_5_5_22_3_|45_4_32_1_|3.--3_|" 
"67_6_55_3_|5--3_5_|26_5_32_3_|3---|" 
"26_6_6-|16_6_66_7_|`17_6_76_7_|3.--3_|" 
"67_6_55_3_|5--3_5_|67_6_76_7_|3---|" 
"26_6_6-|16_6_66_7_|`17_6_7.5_|6---|" 
}; 
//乐谱方式输入的音乐播放,仙剑奇侠传
void main(void) // 主程序
{ 
 TMOD = 0x01; //使用定时器 0 的 16 位工作模式
 TR0 = 0; 
 ET0 = 1; 
 EA = 1; 
 while(1) 
 { 
 play(xianjian); 
 } 
}
仙剑奇侠传

 四个按键控制

#include<reg52.h>//包含访问sfr库函数
#define uchar unsigned char //定义一下方便使用
#define uint unsigned int 
#define ulong unsigned long
sbit BEEP=P1^0; //喇叭输出脚
sbit P10=P1^1;//
sbit K1= P3^2; 
sbit K2= P3^3; 
sbit K3= P3^4; 
sbit K4= P3^5; 
uchar th0_f; //在中断中装载的 T0 的值高 8 位
uchar tl0_f; //在中断中装载的 T0 的值低 8 位
//T0 的值,及输出频率对照表
uchar code freq[36*2]={ 
 0xA9,0xEF,//00220HZ ,1 //0 
 0x93,0xF0,//00233HZ ,1# 
 0x73,0xF1,//00247HZ ,2 
 0x49,0xF2,//00262HZ ,2# 
 0x07,0xF3,//00277HZ ,3 
 0xC8,0xF3,//00294HZ ,4 
 0x73,0xF4,//00311HZ ,4# 
 0x1E,0xF5,//00330HZ ,5 
 0xB6,0xF5,//00349HZ ,5# 
 0x4C,0xF6,//00370HZ ,6 
 0xD7,0xF6,//00392HZ ,6# 
 0x5A,0xF7,//00415HZ ,7 
 0xD8,0xF7,//00440HZ 1 //12 
 0x4D,0xF8,//00466HZ 1# //13 
 0xBD,0xF8,//00494HZ 2 //14 
 0x24,0xF9,//00523HZ 2# //15 
 0x87,0xF9,//00554HZ 3 //16 
 0xE4,0xF9,//00587HZ 4 //17 
 0x3D,0xFA,//00622HZ 4# //18 
 0x90,0xFA,//00659HZ 5 //19 
 0xDE,0xFA,//00698HZ 5# //20 
 0x29,0xFB,//00740HZ 6 //21 
 0x6F,0xFB,//00784HZ 6# //22 
 0xB1,0xFB,//00831HZ 7 //23 
 0xEF,0xFB,//00880HZ `1 
 0x2A,0xFC,//00932HZ `1# 
 0x62,0xFC,//00988HZ `2 
 0x95,0xFC,//01046HZ `2# 
 0xC7,0xFC,//01109HZ `3 
 0xF6,0xFC,//01175HZ `4 
 0x22,0xFD,//01244HZ `4# 
 0x4B,0xFD,//01318HZ `5 
 0x73,0xFD,//01397HZ `5# 
 0x98,0xFD,//01480HZ `6 
 0xBB,0xFD,//01568HZ `6# 
 0xDC,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 xdata diaodata[112]; //音调缓冲
 uchar xdata jiedata[112]; //音长缓冲
 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<jiedata[i];c++) //按照音长延时
     {
         for(n=0;n<32000;n++); 
         if((!K1)||(!K2)||(!K3)||(!K4))//发现按键,立即退出播放
         { 
             TR0=0; 
             return; 
         }
     }
     TR0=0; 
     for(n=0;n<500;n++); //音符间延时
     TR0=1; 
    } 
         TR0=0;  
} 
//仙剑
uchar code xianjian[]={ 
"|3_3_3_2_3-|2_3_2_2_,6,6_,7_|12_1_,7,6_,5_|,6---|" 
"3_3_3_2_3.6_|5_6_5_5_22_3_|45_4_32_1_|3.--3_|" 
"67_6_55_3_|5--3_5_|26_5_32_3_|3---|" 
"26_6_6-|16_6_66_7_|`17_6_76_7_|3.--3_|" 
"67_6_55_3_|5--3_5_|67_6_76_7_|3---|" 
"26_6_6-|16_6_66_7_|`17_6_7.5_|6---|" 
}; 
uchar code song3[]={ 
"5-5_3_2_1_|3---|6-6_4_2_1_" 
",7--,5_|1.3_5.1_|,7.3_5 5_|" 
"6.7_`1.6_|6_5_5-3_2_|1.1_13_2_|" 
"1.1_12_3_|2.1_,62_3_|2-- ,5_|" 
"1.3_5.1_|,7.3_55_|6.7_`1.6_|" 
"6_5_5-3_2_|1.1_13_2_|1.1_12_3_" 
"2.,6_,71_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--" 
};



void main(void) // 主程序
{ 
 TMOD = 0x01; //使用定时器 0 的 16 位工作模式
 TR0 = 0; 
 ET0 = 1; //定时器 0 中断
 EA = 1; //打开总中断
 while(1) 
 { 
     if(!K1) 
     { 
     while(!K1); 
     play(xianjian); //播放音乐
     } 
     if(!K2) 
     { 
     while(!K2); 
     play(song3); //播放音乐
     } 
     if(!K3) 
     { 
     while(!K3); 
     play(mamahao); //播放音乐
     }
 } 
} 
三个按键播放,一个按键停止

 一个按键切换播放

#include<reg52.h>//包含访问sfr库函数
#define uchar unsigned char //定义一下方便使用
#define uint unsigned int 
#define ulong unsigned long
sbit BEEP=P1^0; //喇叭输出脚
sbit P10=P1^1;//
sbit K1= P3^2; 
sbit K2= P3^3; 
sbit K3= P3^4; 
sbit K4= P3^5; 
uchar th0_f; //在中断中装载的 T0 的值高 8 位
uchar tl0_f; //在中断中装载的 T0 的值低 8 位
//T0 的值,及输出频率对照表
uchar code freq[36*2]={ 
 0xA9,0xEF,//00220HZ ,1 //0 
 0x93,0xF0,//00233HZ ,1# 
 0x73,0xF1,//00247HZ ,2 
 0x49,0xF2,//00262HZ ,2# 
 0x07,0xF3,//00277HZ ,3 
 0xC8,0xF3,//00294HZ ,4 
 0x73,0xF4,//00311HZ ,4# 
 0x1E,0xF5,//00330HZ ,5 
 0xB6,0xF5,//00349HZ ,5# 
 0x4C,0xF6,//00370HZ ,6 
 0xD7,0xF6,//00392HZ ,6# 
 0x5A,0xF7,//00415HZ ,7 
 0xD8,0xF7,//00440HZ 1 //12 
 0x4D,0xF8,//00466HZ 1# //13 
 0xBD,0xF8,//00494HZ 2 //14 
 0x24,0xF9,//00523HZ 2# //15 
 0x87,0xF9,//00554HZ 3 //16 
 0xE4,0xF9,//00587HZ 4 //17 
 0x3D,0xFA,//00622HZ 4# //18 
 0x90,0xFA,//00659HZ 5 //19 
 0xDE,0xFA,//00698HZ 5# //20 
 0x29,0xFB,//00740HZ 6 //21 
 0x6F,0xFB,//00784HZ 6# //22 
 0xB1,0xFB,//00831HZ 7 //23 
 0xEF,0xFB,//00880HZ `1 
 0x2A,0xFC,//00932HZ `1# 
 0x62,0xFC,//00988HZ `2 
 0x95,0xFC,//01046HZ `2# 
 0xC7,0xFC,//01109HZ `3 
 0xF6,0xFC,//01175HZ `4 
 0x22,0xFD,//01244HZ `4# 
 0x4B,0xFD,//01318HZ `5 
 0x73,0xFD,//01397HZ `5# 
 0x98,0xFD,//01480HZ `6 
 0xBB,0xFD,//01568HZ `6# 
 0xDC,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 xdata diaodata[112]; //音调缓冲
 uchar xdata jiedata[112]; //音长缓冲
 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<jiedata[i];c++) //按照音长延时
     {
         for(n=0;n<32000;n++); 
         if((!K1)||(!K2)||(!K3)||(!K4))//发现按键,立即退出播放
         { 
             TR0=0; 
             return; 
         }
     }
     TR0=0; 
     for(n=0;n<500;n++); //音符间延时
     TR0=1; 
    } 
         TR0=0;  
} 
//仙剑
uchar code xianjian[]={ 
"|3_3_3_2_3-|2_3_2_2_,6,6_,7_|12_1_,7,6_,5_|,6---|" 
"3_3_3_2_3.6_|5_6_5_5_22_3_|45_4_32_1_|3.--3_|" 
"67_6_55_3_|5--3_5_|26_5_32_3_|3---|" 
"26_6_6-|16_6_66_7_|`17_6_76_7_|3.--3_|" 
"67_6_55_3_|5--3_5_|67_6_76_7_|3---|" 
"26_6_6-|16_6_66_7_|`17_6_7.5_|6---|" 
}; 
uchar code song3[]={ 
"5-5_3_2_1_|3---|6-6_4_2_1_" 
",7--,5_|1.3_5.1_|,7.3_5 5_|" 
"6.7_`1.6_|6_5_5-3_2_|1.1_13_2_|" 
"1.1_12_3_|2.1_,62_3_|2-- ,5_|" 
"1.3_5.1_|,7.3_55_|6.7_`1.6_|" 
"6_5_5-3_2_|1.1_13_2_|1.1_12_3_" 
"2.,6_,71_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 boluo[]={ 
"1-|2_4_3_2_55|5_6_3_4_22|2_4_3_2_1_`1_7_6_|5_4_2_3_11|" 
"2_4_3_2_55|5_6_3_4_22|2_4_3_2_1_5_2_3_|1---|" 
}; 
//小星星
uchar code xingxing[]={ 
"1155|665-|4433|221-|" 
"5544|332-|5544|332-|" 
"1155|665-|4433|221-|" 
}; 
//老鼠爱大米
uchar code dami[]={ 
"321-|3.2_1-|3231|3_6.5-|3_5_665|65-3_2_|122_3_2|12--|" 
};
void main(void) // 主程序
{ 
    uchar i;
 TMOD = 0x01; //使用定时器 0 的 16 位工作模式
 TR0 = 0; 
 ET0 = 1; //定时器 0 中断
 EA = 1; //打开总中断
 while(1) 
 {     
    if(!K1) 
     { 
     while(!K1); 
     
         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; 
     }
 } 
} 
一个按键选择播放六首音乐
#include "reg52.h"             //此文件中定义了单片机的一些特殊功能寄存器
sbit sound=P1^0;    //将sound位定义为P3.7
unsigned int C;     //储存定时器的定时常数
//以下是C调低音的音频宏定义
#define l_dao 262   //将“l_dao”宏定义为低音“1”的频率262Hz
#define l_re 286    //将“l_re”宏定义为低音“2”的频率286Hz
#define l_mi 311    //将“l_mi”宏定义为低音“3”的频率311Hz
#define l_fa 349    //将“l_fa”宏定义为低音“4”的频率349Hz
#define l_sao 392   //将“l_sao”宏定义为低音“5”的频率392Hz
#define l_la 440    //将“l_a”宏定义为低音“6”的频率440Hz
#define l_xi 494    //将“l_xi”宏定义为低音“7”的频率494Hz
//以下是C调中音的音频宏定义
#define dao 523     //将“dao”宏定义为中音“1”的频率523Hz
#define re 587      //将“re”宏定义为中音“2”的频率587Hz
#define mi 659      //将“mi”宏定义为中音“3”的频率659Hz
#define fa 698      //将“fa”宏定义为中音“4”的频率698Hz
#define sao 784     //将“sao”宏定义为中音“5”的频率784Hz
#define la 880      //将“la”宏定义为中音“6”的频率880Hz
#define xi 987      //将“xi”宏定义为中音“7”的频率523H      
//以下是C调高音的音频宏定义
#define h_dao 1046     //将“h_dao”宏定义为高音“1”的频率1046Hz
#define h_re 1174      //将“h_re”宏定义为高音“2”的频率1174Hz
#define h_mi 1318      //将“h_mi”宏定义为高音“3”的频率1318Hz
#define h_fa 1396     //将“h_fa”宏定义为高音“4”的频率1396Hz
#define h_sao 1567    //将“h_sao”宏定义为高音“5”的频率1567Hz
#define h_la 1760     //将“h_la”宏定义为高音“6”的频率1760Hz
#define h_xi 1975     //将“h_xi”宏定义为高音“7”的频率1975Hz
//函数功能:1个延时单位,延时200ms
void delay()               
   {
     unsigned char i,j;
      for(i=0;i<250;i++)
        for(j=0;j<250;j++);
   }
//函数功能:主函数
void main(void)
  {
  unsigned char i,j;                                    
//以下是《渴望》片头曲的一段简谱
   unsigned  int 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,
                                    0xff}; //以0xff作为音符的结束标志                    
//以下是简谱中每个音符的节拍
//"4"对应4个延时单位,"2"对应2个延时单位,"1"对应1个延时单位 
unsigned char 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的模式1(13位计数器)
       while(1)       //无限循环
         {
             i=0;   //从第1个音符f[0]开始播放
          while(f[i]!=0xff)            //只要没有读到结束标志就继续播放
               {
              C=460830/f[i];       
              TH0=(8192-C)/32;   //可证明这是13位计数器TH0高8位的赋初值方法
              TL0=(8192-C)%32;   //可证明这是13位计数器TL0低5位的赋初值方法
              TR0=1;             //启动定时器T0
                  for(j=0;j<JP[i];j++)  //控制节拍数
                  delay();          //延时1个节拍单位
                  TR0=0;                   //关闭定时器T0
                  i++;                 //播放下一个音符
                  }                                   
        }            
} 
//函数功能:定时器T0的中断服务子程序,使P3.7引脚输出音频的方波
void Time0(void ) interrupt 1 using 1  
  {
    sound=!sound;      //将P3.7引脚输出电平取反,形成方波  
    TH0=(8192-C)/32;   //可证明这是13位计数器TH0高8位的赋初值方法
    TL0=(8192-C)%32;   //可证明这是13位计数器TL0低5位的赋初值方法 
  }
        
播放《渴望》片头曲
原文地址:https://www.cnblogs.com/bymeet/p/14349805.html