51单片机实验-蜂鸣器播放音乐
题目:编程实现利用单片机使蜂鸣器播放“茉莉花”的乐曲。
学习单片机时写的,利用单片机控制蜂鸣器播放乐曲,开发板上的蜂鸣器可以用三极管驱动,需要根据乐谱来设置当前节拍的发声时间。中断函数来控制蜂鸣器的发声。
#include<reg51.h>
sbit Buzz = P1^6; //声明绑定蜂鸣器,接线时只需将此IO口与蜂鸣器(扬声器)信号输入端相连即可
unsigned int code NoteFrequ[]={
523,587,659,698,784,880,988, //中音对应的1-7
1047,1175,1319,1397,1568,1760,1976, //高音对应的1-7
262,294,330,349,392,440,494}; //低音对应的1-7
unsigned int code NoteReload[]={ //中音1-7和高音1-7对应的定时器重载值
65536 - (11059200/12) /(523*2),//中音1-7
65536 - (11059200/12) /(587*2),
65536 - (11059200/12) /(659*2),
65536 - (11059200/12) /(698*2),
65536 - (11059200/12) /(784*2),
65536 - (11059200/12) /(880*2),
65536 - (11059200/12) /(988*2),
65536 - (11059200/12) /(1047*2),//高音1-7
65536 - (11059200/12) /(1175*2),
65536 - (11059200/12) /(1319*2),
65536 - (11059200/12) /(1397*2),
65536 - (11059200/12) /(1568*2),
65536 - (11059200/12) /(1760*2),
65536 - (11059200/12) /(1976*2),
65536 - (11059200/12) /(262*2), //低音1-7
65536 - (11059200/12) /(294*2),
65536 - (11059200/12) /(330*2),
65536 - (11059200/12) /(349*2),
65536 - (11059200/12) /(392*2),
65536 - (11059200/12) /(440*2),
65536 - (11059200/12) /(494*2)};
bit enable = 1; //发声使能表标识
bit tmrflay = 0; //定时器中中断完成标识
unsigned char T0RH = 0xff; //T0重载值高字节
unsigned char T0RL = 0x00; //T0重载值低字节
void PlayTwoTiger(); void main()
{
unsigned int i;
EA = 1;
TMOD =0x01; //模式1
TH0 = T0RH;
TL0 = T0RL;
ET0 = 1; //使能T0中断
TR0 = 1; //启动
while(1)
{
PlayTwoTiger();
for(i=0;i<40000;i++);
}
}
/**音乐函数**/
void PlayTwoTiger()
{
unsigned char beat; //节拍索引
unsigned char note; //节拍对应音符
unsigned int time=0; //节拍计时
unsigned int beattime=0; //总时间计时
unsigned int soundtime=0; //没拍发声计时
unsigned char code PlayTwoTigerNote[]={ //音符表
3,3,5,6,8,8,6,5,5,6,5,
3,3,5,6,8,8,6,5,5,6,5,
5,5,5,3,5,6,6,5,
3,2,3,5,3,2,1,1,2,1,
3,2,1,3,2,3,5,6,8,5,
2,3,5,2,3,1,20,19,
20,1,2,3,
1,2,1,20,19
};
unsigned char code PlayTwoBeat[]={ //节拍表,4表示一拍,1表示1/4拍,8表示两拍
4,2,2,2,2,2,2,4,2,2,8,
4,2,2,2,2,2,2,4,2,2,8,
4,4,4,2,2,4,4,8,
4,2,2,4,2,2,4,2,2,8,
2,2,2,2,6,2,4,2,2,8,
4,2,2,2,2,2,2,8,
4,4,6,2,
2,2,2,2,16
};
for(beat=0; beat<sizeof(PlayTwoTigerNote);) //节拍索引循环变量
{
while(!tmrflay); //每次定时器中断完成 节拍处理
tmrflay = 0;
if(time == 0) //节拍播放完成重启
{
note = PlayTwoTigerNote[beat]-1;
T0RH = NoteReload[note]>>8;
T0RL = NoteReload[note]; //计算总时间,右移2位等于除4,移位代替除法加快速度
beattime = (PlayTwoBeat[beat]*NoteFrequ[note])>>2; //计算发声时间,为总时间的0.75s
soundtime =beattime - (beattime>>2);
enable = 1; //开始发声
time++;
}
else //节拍播放未结束,则继续处理
{
if(time >= beattime) //当前时间清零
{
time = 0; //准备重新启动
beat++;
}
else //累加时间
{
time++;
if(time == soundtime) //发声时间到达;关闭蜂鸣器
{
enable =0; //用以区分连续两个节拍
}
}
}
}
}
void InterRupt() interrupt 1 //中断服务
{
TH0 =T0RH;
TL0 =T0RL;
tmrflay = 1;
if(enable)
{
Buzz=~Buzz;
}
else
{
Buzz=1;
}
}
若有问题,评论留言~