第9章-步进电机与蜂鸣器(下:蜂鸣器播放音乐)
无源蜂鸣器发声;需要方波,可以控制频率
挺绕的,一方面要控制频率,一方面要控制发声时间
有源蜂鸣器:给电就响,控制简单

老师的只能看懂一半,
用自己的理解改写了一半,成功
//用T0播放频率,T0控制时间的方式
#include <reg52.h>
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
typedef signed char i8;
typedef signed int i16;
typedef signed long i32;
sbit BUZZ = P1^6; //蜂鸣器控制引脚
u16 code Frequ[] = { //中音1-7和高音1-7对应频率列表
523, 587, 659, 698, 784, 880, 988, //中音1-7
1047, 1175, 1319, 1397, 1568, 1760, 1976 //高音1-7
};
u16 code Frequ2Reload[] = { //中音1-7和高音1-7对应的定时器重载值
65536 - (11059200/12) / (523*2), //中音1
65536 - (11059200/12) / (587*2), //2
65536 - (11059200/12) / (659*2), //3
65536 - (11059200/12) / (698*2), //4
65536 - (11059200/12) / (784*2), //5
65536 - (11059200/12) / (880*2), //6
65536 - (11059200/12) / (988*2), //7
65536 - (11059200/12) / (1047*2), //高音1
65536 - (11059200/12) / (1175*2), //2
65536 - (11059200/12) / (1319*2), //3
65536 - (11059200/12) / (1397*2), //4
65536 - (11059200/12) / (1568*2), //5
65536 - (11059200/12) / (1760*2), //6
65536 - (11059200/12) / (1976*2), //7
};
//两只老虎音符表
u8 code TwoTigerYin[] = {
1, 2, 3, 1, 1, 2, 3, 1, 3, 4, 5, 3, 4, 5,
5,6, 5,4, 3, 1, 5,6, 5,4, 3, 1, 1, 5, 1, 1, 5, 1,
};
//两只老虎节拍表,4表示一拍,1就是1/4拍,8就是2拍
u8 code TwoTigerYinLen[] = {
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4, 4, 8,
3,1, 3,1, 4, 4, 3,1, 3,1, 4, 4, 4, 4, 8, 4, 4, 8,
};
//1/4拍约500ms,1/16拍=125ms,调节播放速度
u32 pai1p16=125;
u8 TH0RL = 0x00; //T0重载值的高字节
u8 TL0RL = 0x00; //T0重载值的低字节
u16 beepCnt=0;
u16 silentCnt=0;
bit beepBusy=0;
/* 两只老虎乐曲播放函数 */
void PlayTwoTiger()
{
u8 i;
u8 yin;
u16 yinReload;
u8 yinChangN;
u16 yinChang;
u16 yinHz;
u8 cnt=sizeof(TwoTigerYinLen);
for(i=0;i<cnt;i++)
{
//取出音符,转换成频率,转换成T0的初值,设置T0,
yin=TwoTigerYin[i];
yinReload=Frequ2Reload[yin-1];
TH0RL=(u8)(yinReload>>8);
TL0RL=(u8)(yinReload);
TH0=TH0RL;
TL0=TL0RL;
//计算播放时间,取出音符长度,转化成进入中断的次数,与频率有关
//音长的0.75进行播放,0.25静音
yinChangN=TwoTigerYinLen[i];
yinHz=Frequ[yin-1];//取出频率,参与进入中断次数的计算
yinChang=(yinChangN*pai1p16*yinHz*2/1000);//要用i32,否则高位丢失
silentCnt=yinChang>>2; //音长的0.75进行播放,0.25静音
beepCnt=yinChang-silentCnt;//音长的0.75进行播放,0.25静音
//开启T0,去播放改频率(音)
ET0=TR0=1;
beepBusy=1;
while(beepBusy==1);//等待这个音播放完毕,切换下一个音
}
}
int main(void)
{
u16 i;
EA = 1; //使能全局中断
TMOD = 0x01; //配置T0工作在模式1
while (1)
{
PlayTwoTiger(); //播放乐曲--两支老虎
for (i=0; i<40000; i++); //停止一段时间
}
}
/* T0中断服务函数,用于控制蜂鸣器发声 */
void InterruptTimer0() interrupt 1
{
TH0 = TH0RL; //重新加载重载值
TL0 = TL0RL;
if(beepCnt)
{
beepCnt--;
BUZZ=~BUZZ;
}else if(silentCnt)
{
silentCnt--;
BUZZ=1;
}
else
{
beepBusy=0;
ET0=TR0=0;
}
}
//用T0播放频率,用T1控制时间的方式
#include <reg52.h>
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
typedef signed char i8;
typedef signed int i16;
typedef signed long i32;
sbit BUZZ = P1^6; //蜂鸣器控制引脚
u16 code Frequ[] = { //中音1-7和高音1-7对应频率列表
523, 587, 659, 698, 784, 880, 988, //中音1-7
1047, 1175, 1319, 1397, 1568, 1760, 1976 //高音1-7
};
u16 code Frequ2Reload[] = { //中音1-7和高音1-7对应的定时器重载值
65536 - (11059200/12) / (523*2), //中音1
65536 - (11059200/12) / (587*2), //2
65536 - (11059200/12) / (659*2), //3
65536 - (11059200/12) / (698*2), //4
65536 - (11059200/12) / (784*2), //5
65536 - (11059200/12) / (880*2), //6
65536 - (11059200/12) / (988*2), //7
65536 - (11059200/12) / (1047*2), //高音1
65536 - (11059200/12) / (1175*2), //2
65536 - (11059200/12) / (1319*2), //3
65536 - (11059200/12) / (1397*2), //4
65536 - (11059200/12) / (1568*2), //5
65536 - (11059200/12) / (1760*2), //6
65536 - (11059200/12) / (1976*2), //7
};
//两只老虎音符表,,,该音用来查询频率,T0的初值
u8 code TwoTigerYin[] = {
1, 2, 3, 1, 1, 2, 3, 1, 3, 4, 5, 3, 4, 5,
5,6, 5,4, 3, 1, 5,6, 5,4, 3, 1, 1, 5, 1, 1, 5, 1,
};
//两只老虎节拍表,4表示一拍,1就是1/4拍,8就是2拍,,该拍用来计算播放时长
u8 code TwoTigerYinLen[] = {
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4, 4, 8,
3,1, 3,1, 4, 4, 3,1, 3,1, 4, 4, 4, 4, 8, 4, 4, 8,
};
//1/4拍约500ms,1/16拍=125ms,调节播放速度
u32 pai1p16=125; //1/16拍=125ms,
u8 TH0RL = 0x00; //T0重载值的高字节
u8 TL0RL = 0x00; //T0重载值的低字节
u16 beepCnt=0; //每个音的发声时长
u16 silentCnt=0; //每个音的静音时长
bit beepBusy=0; //0=一个音播放完毕,可以切换下一个;1=一个音正在播放,不能切换下一个
/* 两只老虎乐曲播放函数 */
void PlayTwoTiger()
{
u8 i;
u8 yin;
u16 yinReload;
u8 yinChangN;
u16 yinChang;
u8 cnt=sizeof(TwoTigerYinLen);
for(i=0;i<cnt;i++)
{
//取出音符,转换成频率,转换成T0的初值,设置T0,
yin=TwoTigerYin[i];//取出音符
yinReload=Frequ2Reload[yin-1];//根据音符查询到T0初值
TH0RL=(u8)(yinReload>>8);
TL0RL=(u8)(yinReload);
//T0负责发出指定频率的声音
TH0=TH0RL;
TL0=TL0RL;
//计算播放时间,取出音符长度,转换成时间ms,再转化成进入0.25ms中断的次数
//音长的0.75进行播放,0.25静音
yinChangN=TwoTigerYinLen[i];//取出(1/16拍)的倍数
yinChang=(yinChangN*pai1p16*4);//0.25ms,所以乘4 要用i32,否则高位丢失
silentCnt=yinChang>>2; //音长的0.75进行播放,0.25静音
beepCnt=yinChang-silentCnt;//音长的0.75进行播放,0.25静音
//开启T0,去播放改频率(音),,开启T1去控制播放时间
ET0=TR0=1;
TH1=TL1=0x1A; //方式2自动重装,0.25ms一次中断
ET1=TR1=1;
beepBusy=1;//控制播放下一个音
while(beepBusy==1);//等待这个音播放完毕,切换下一个音
}
}
int main(void)
{
u16 i;
EA = 1; //使能全局中断
TMOD = 0x21; //配置T0工作在模式1; T2工作在方式2, 0.25ms进入一次
PT0=1;//T0优先级高,效果好
while (1)
{
PlayTwoTiger(); //播放乐曲--两支老虎
for (i=0; i<40000; i++); //停止一段时间
}
}
/* T0中断服务函数,用于控制蜂鸣器发声频率 */
void Timer0_ISR() interrupt 1
{
TH0 = TH0RL; //重新加载重载值
TL0 = TL0RL;
BUZZ=~BUZZ;
}
/* T1中断服务函数,用于控制蜂鸣器发声时间 */
void Timer1_ISR(void) interrupt 3
{
if(beepCnt)//发声时间段
{
beepCnt--;
}
else if(silentCnt)//禁止发声时间段
{
silentCnt--;
TR0=0;
}
else //这个音播放完毕
{
beepBusy=0;
TR1=0;
}
}