功能:单片机烧录好程序后,按key1按键播放《IF YOU》,再次按key1可暂停播放,按key2可切换歌曲到《国际歌》,再按key3可切换歌曲到《孤勇者》
芯片:STC15F2K61S2
完整工程文件和hex文件在这
提取码:1111
前言:相信大家焊好板子后最喜欢玩的就是蜂鸣器播放音乐,路过每个教室基本都是各种杂音,毕竟这玩意真挺好玩的,于是我就根据老师的代码和谱子写了播放其他歌曲的文件(国际歌是我直接拿往届学长的音乐代码,来凑个数的),说实话这玩意看起来挺简单的,实际上挺难的,还得学一遍乐理知识,然后对着各种拍子和音调不断调试才能得到一个比较理想的状态,但是if you和孤勇者这两首曲子总感觉有些地方不是很完美,但对于摆烂人来说能听就行了。反正也是娱乐娱乐
废话不多说,代码如下:(谱子在最后)
#include#define uint unsigned int #define uchar unsigned char sbit beep=P3^4; //蜂鸣器 sbit key1=P3^2; //按键1 sbit key2=P3^3; //按键2 uchar timeh,timel,jindu=0,gequ=0; //定义定时器的重装值 bit flag; //播放标志位 uchar code music1[] = //音乐代码,歌曲为《IF YOU》,格式为: 音符, 节拍, 音符, 节拍, { 0x26,0x10, 0x25,0x10, 0x23,0x10, 0x21,0x10, 0x22,0x10, 0x23,0x10, 0x16,0x20, 0x22,0x08, 0x21,0x08, 0x22,0x08, 0x21,0x08, 0x22,0x08, 0x21,0x08, 0x22,0x10, 0x21,0x08, 0x22,0x08, 0x22,0x08, 0x21,0x08, 0x23,0x20, 0x26,0x10, 0x25,0x10, 0x23,0x10, 0x21,0x10, 0x22,0x10, 0x23,0x10, 0x16,0x20, 0x16,0x08, 0x17,0x10, 0x21,0x08, 0x21,0x08, 0x16,0x08, 0x21,0x08, 0x16,0x08, 0x21,0x08, 0x22,0x08, 0x23,0x08, 0x22,0x08, 0x22,0x10, 0x21,0x08, 0x21,0x08, 0x21,0x10, 0x15,0x08, 0x21,0x20, 0x31,0x10, 0x31,0x08, 0x31,0x08, 0x27,0x08, 0x26,0x08, 0x21,0x10, 0x32,0x10, 0x33,0x10, 0x36,0x10, 0x35,0x10, 0x33,0x10, 0x32,0x10, 0x31,0x10, 0x32,0x30, 0x32,0x08, 0x31,0x08, 0x32,0x08, 0x23,0x08, 0x32,0x10, 0x25,0x24, 0x25,0x08, 0x32,0x08, 0x31,0x08, 0x32,0x08, 0x33,0x24, 0x31,0x08, 0x31,0x10, 0x32,0x10, 0x33,0x10, 0x36,0x10, 0x35,0x10, 0x33,0x10, 0x32,0x10, 0x31,0x08, 0x31,0x08, 0x32,0x10, 0x31,0x30, 0x26,0x08, 0x26,0x08, 0x31,0x08, 0x26,0x08, 0x31,0x08, 0x31,0x24, 0x31,0x08, 0x31,0x08, 0x32,0x08, 0x31,0x08, 0x31,0x08, 0x31,0x24, 0x00,0x10, }; uchar code music2[] = //歌曲为国际歌 { 0x25, 0x10, 0x31, 0x18, 0x27, 0x08, 0x32, 0x08, 0x31, 0x08, 0x25, 0x08, 0x23, 0x08, 0x26, 0x18, 0x26, 0x08, 0x24, 0x10, 0x20, 0x08, 0x26, 0x08, 0x32, 0x18, 0x31, 0x08, 0x27, 0x08, 0x26, 0x08, 0x25, 0x08, 0x24, 0x08, 0x23, 0x30, 0x25, 0x10, 0x31, 0x18, 0x27, 0x08, 0x32, 0x08, 0x31, 0x08, 0x25, 0x08, 0x23, 0x08, 0x26, 0x20, 0x24, 0x08, 0x26, 0x08, 0x32, 0x08, 0x31, 0x08, 0x27, 0x10, 0x32, 0x10, 0x34, 0x10, 0x27, 0x10, 0x31, 0x20, 0x31, 0x08, 0x30, 0x08, 0x33, 0x08, 0x32, 0x08, 0x27, 0x20, 0x26, 0x08, 0x27, 0x08, 0x31, 0x08, 0x26, 0x08, 0x27, 0x20, 0x25, 0x08, 0x25, 0x08, 0x24, 0x08, 0x25, 0x08, 0x26, 0x18, 0x26, 0x08, 0x32, 0x18, 0x31, 0x08, 0x27, 0x20, 0x27, 0x08, 0x20, 0x08, 0x32, 0x10, 0x32, 0x18, 0x27, 0x08, 0x25, 0x08, 0x25, 0x08, 0x24, 0x08, 0x25, 0x08, 0x33, 0x20, 0x31, 0x08, 0x26, 0x08, 0x27, 0x08, 0x31, 0x08, 0x27, 0x10, 0x32, 0x10, 0x31, 0x10, 0x26, 0x10, 0x25, 0x20, 0x25, 0x08, 0x20, 0x08, 0x33, 0x08, 0x32, 0x08, 0x31, 0x20, 0x25, 0x18, 0x23, 0x08, 0x26, 0x20, 0x24, 0x08, 0x20, 0x08, 0x32, 0x0c, 0x31, 0x04, 0x27, 0x20, 0x26, 0x10, 0x25, 0x10, 0x25, 0x20, 0x25, 0x08, 0x20, 0x08, 0x25, 0x10, 0x33, 0x20, 0x32, 0x10, 0x25, 0x10, 0x31, 0x20, 0x27, 0x18, 0x27, 0x08, 0x26, 0x18, 0x25, 0x08, 0x26, 0x10, 0x32, 0x10, 0x32, 0x20, 0x32, 0x08, 0x30, 0x08, 0x33, 0x0c, 0x32, 0x04, 0x31, 0x20, 0x25, 0x18, 0x23, 0x08, 0x26, 0x20, 0x24, 0x08, 0x20, 0x08, 0x32, 0x0c, 0x31, 0x04, 0x27, 0x20, 0x26, 0x10, 0x25, 0x10, 0x33, 0x30, 0x33, 0x10, 0x35, 0x20, 0x34, 0x10, 0x33, 0x10, 0x32, 0x18, 0x33, 0x08, 0x34, 0x10, 0x30, 0x08, 0x34, 0x08, 0x33, 0x18, 0x33, 0x08, 0x32, 0x18, 0x32, 0x08, 0x31, 0x30, 0x00, 0x00 }; uchar code music3[] = //歌曲为孤勇者 { 0x16,0x08,0x17,0x08, 0x21,0x08,0x22,0x08, 0x17,0x08,0x21,0x08, 0x21,0x10,0x21,0x08, 0x17,0x08,0x21,0x08, 0x22,0x08,0x17,0x08, 0x21,0x08,0x21,0x10, 0x21,0x08,0x22,0x08, 0x23,0x08,0x22,0x08, 0x23,0x08,0x22,0x08, 0x23,0x10,0x23,0x08, 0x22,0x08,0x23,0x10, 0x25,0x10,0x23,0x10, 0x16,0x08,0x17,0x08, 0x21,0x08,0x22,0x08, 0x17,0x08,0x21,0x08, 0x21,0x10,0x21,0x08, 0x17,0x08,0x21,0x08, 0x22,0x08,0x17,0x08, 0x21,0x08,0x21,0x10, 0x21,0x08,0x22,0x08, 0x23,0x08,0x22,0x08, 0x23,0x08,0x22,0x08, 0x23,0x10,0x23,0x08, 0x22,0x08,0x23,0x10, 0x25,0x10,0x23,0x10, 0x25,0x10,0x23,0x14, 0x25,0x08,0x23,0x14, 0x25,0x08,0x23,0x08, 0x25,0x08,0x26,0x08, 0x23,0x08,0x25,0x10, 0x25,0x08,0x23,0x14, 0x25,0x08,0x23,0x14, 0x25,0x08,0x23,0x08, 0x25,0x08,0x26,0x08, 0x23,0x08,0x25,0x10, 0x25,0x08,0x25,0x08, 0x23,0x08,0x22,0x08, 0x22,0x10,0x22,0x10, 0x21,0x08,0x23,0x08, 0x23,0x08,0x22,0x08, 0x22,0x10,0x22,0x10, 0x21,0x08,0x21,0x08, 0x16,0x20,0x25,0x08, 0x25,0x08,0x23,0x08, 0x22,0x08,0x22,0x10, 0x22,0x10,0x21,0x08, 0x23,0x08,0x23,0x08, 0x22,0x08,0x22,0x10, 0x22,0x10,0x21,0x08, 0x21,0x08,0x16,0x20, 0x00 }; uchar code quzi[] = //此数组数据为各个音符在定时器中的重装值,第一列是高位,第二列是低位 //时间 { 0xf8,0x8c, //低八度,低1 0xf9,0x5b, 0xfa,0x15, //低3 0xfa,0x67, 0xfb,0x04, //低5 0xfb,0x90, 0xfc,0x0c, //低7 0xfc,0x44, //中央C调 0xfc,0xac, //中2 0xfd,0x09, 0xfd,0x34, //中4 0xfd,0x82, 0xfd,0xc8, //中6 0xfe,0x06, 0xfe,0x22, //高八度,高1 0xfe,0x56, 0xfe,0x6e, //高3 0xfe,0x9a, 0xfe,0xc1, //高5 0xfe,0xe4, 0xff,0x03 //高7 }; void delay(unsigned int xms) { uint i,j; for(i=xms; i>0; i--) for(j=124; j>0; j--); } uchar quyin(uchar tem) { uchar qudiao,jp,weizhi; //定义曲调,音符和位置 qudiao=tem/16; //高4位是曲调值 jp=tem%16; //低4位是音符 if(qudiao==1) //当曲调值为1时,即是低八度,低八度在quzi数组中基址为0 qudiao=0; else if(qudiao==2) //当曲调值为2时,即是中八度,中八度在quzi数组中基址为14 qudiao=14; else if(qudiao==3) //当曲调值为3时,即是高八度,高八度在quzi数组中,基址为28 qudiao=28; weizhi=qudiao+(jp-1)*2; //通过基址加上音符作为偏移量,即可定位此音符在quzi数组中的位置 return weizhi; //返回这一个位置值 } void playmusic() { uchar p,m,tem; //m为节拍 while(1) { if(flag==1) //若播放的标志位为1则播放音乐 { if(gequ==0) //歌曲选择位为0,则播放同一首歌 { p=music1[jindu]; if(p==0x00) //如果碰到结束符,延时1秒,回到开始再来一遍 { jindu=0; delay(1000); break; } else if(p==0xff) //若碰到休止符,延时100ms,继续取下一音符 { jindu=jindu+1; delay(100); TR0=0; break; } else //正常情况下取音符和节拍 { tem=quyin(music1[jindu]); //取出当前音符在quzi数组中的位置值 timeh=quzi[tem]; //把音符相应的计时器重装载值赋予timeh和timel timel=quzi[tem+1]; jindu++; TH0=timeh; //把timeh和timel赋予计时器 TL0=timel; m=music1[jindu]; //取得节拍 jindu++; } TR0=1; //开定时器1 delay(m*180); //等待节拍完成, 通过P3^4口输出音频 TR0=0; //关定时器1 beep=0; //使beep端口置0,起保护蜂鸣器作用 } else if(gequ==1) //歌曲选择位为1,则播放小毛驴 { p=music2[jindu]; if(p==0x00) //如果碰到结束符,延时1秒,回到开始再来一遍 { jindu=0; delay(1000); break; } else if(p==0xff) //若碰到休止符,延时100ms,继续取下一音符 { jindu=jindu+1; delay(100); TR0=0; break; } else //正常情况下取音符和节拍 { tem=quyin(music2[jindu]); //取出当前音符在quzi数组中的位置值 timeh=quzi[tem]; //把音符相应的计时器重装载值赋予timeh和timel timel=quzi[tem+1]; jindu++; TH0=timeh; //把timeh和timel赋予计时器 TL0=timel; m=music2[jindu]; //取得节拍 jindu++; } TR0=1; //开定时器1 delay(m*300); //等待节拍完成, 通过P3^4口输出音频 TR0=0; //关定时器1 beep=0; //使beep端口置0,起保护蜂鸣器作用 } else if(gequ==2) //歌曲选择位为2,则播放天空之城 { p=music3[jindu]; if(p==0x00) //如果碰到结束符,延时1秒,回到开始再来一遍 { jindu=0; delay(1000); break; } else if(p==0xff) //若碰到休止符,延时100ms,继续取下一音符 { jindu=jindu+1; delay(100); TR0=0; break; } else //正常情况下取音符和节拍 { tem=quyin(music3[jindu]); //取出当前音符在quzi数组中的位置值 timeh=quzi[tem]; //把音符相应的计时器重装载值赋予timeh和timel timel=quzi[tem+1]; jindu++; TH0=timeh; //把timeh和timel赋予计时器 TL0=timel; m=music3[jindu]; //取得节拍 jindu++; } TR0=1; //开定时器1 delay(m*200); //等待节拍完成, 通过P3^4口输出音频 TR0=0; //关定时器1 beep=0; //使beep端口置0,起保护蜂鸣器作用 } } else //播放标志位不为1时,暂停播放音乐 while(flag!=1); } } void init_sys() { P0M0=0xff; //设置推挽模式 P0M1=0x00; P2M0=0x08; P2M1=0x00; P3M0=0x10; P3M1=0x00; P4M0=0x00; P4M1=0x00; P5M0=0x00; P5M1=0x00; } void init() { TMOD=0x01; //设置定时器0,定时方式1,16位手动重装模式 TH0=0xD8; //设置定时初值 TL0=0xEF; IE=0x87; // 1000 0111 EA=1,EX0=1,ET0=1,EX1=0; IP=0x02; // 0000 0010 PT0=1; 定时器0优先级高 TR0=0; //定时器0开始运行 beep=0; //使beep端口置0,起保护蜂鸣器作用 } void main() { init_sys(); //系统初始化 init(); P0=0x00; key1=1; //两个按键设为输入状态,检测中断 key2=1; flag=0; //播放标志位清零 while(1) { playmusic(); //播放音乐函数 } } void tim1() interrupt 1 //计时器控制频率 { TH0=timeh; //赋初值 TL0=timel; beep=~beep; //中断使得beep翻转产生方波 } void ex1() interrupt 0 { delay(5); if(key1==0) //判断key1是否按下 { delay(5); if(key1==0) { while(!key1); flag=~flag; //播放中断位取反,播放或者暂停 } } } void ex2() interrupt 2 { delay(5); if(key2==0) //按键key2按下,切换歌曲 { jindu=0; //歌曲的进度清零,从头开始演唱 gequ++; //下一曲 if(gequ==3) //到达最后一首调到第一首 gequ=0; } }



