第9章-步進(jìn)電機(jī)與蜂鳴器(下:蜂鳴器播放音樂)
無源蜂鳴器發(fā)聲;需要方波,可以控制頻率
挺繞的,一方面要控制頻率,一方面要控制發(fā)聲時(shí)間
有源蜂鳴器:給電就響,控制簡(jiǎn)單

老師的只能看懂一半,
用自己的理解改寫了一半,成功
//用T0播放頻率,T0控制時(shí)間的方式
#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對(duì)應(yīng)頻率列表
?? ?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對(duì)應(yīng)的定時(shí)器重載值
?? ?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,
};
//兩只老虎節(jié)拍表,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,調(diào)節(jié)播放速度
u32 pai1p16=125;
u8 TH0RL = 0x00;? //T0重載值的高字節(jié)
u8 TL0RL = 0x00;? //T0重載值的低字節(jié)
u16 beepCnt=0;
u16 silentCnt=0;
bit beepBusy=0;
/* 兩只老虎樂曲播放函數(shù) */
void PlayTwoTiger()
{
?? ?u8 i;
?? ?u8 yin;
?? ?u16 yinReload;
?? ?u8 yinChangN;
?? ?u16 yinChang;
?? ?u16 yinHz;
?? ?u8 cnt=sizeof(TwoTigerYinLen);
?? ?
?? ?for(i=0;i<cnt;i++)
?? ?{
?? ??? ?//取出音符,轉(zhuǎn)換成頻率,轉(zhuǎn)換成T0的初值,設(shè)置T0,
?? ??? ?yin=TwoTigerYin[i];
?? ??? ?yinReload=Frequ2Reload[yin-1];
?? ??? ?TH0RL=(u8)(yinReload>>8);
?? ??? ?TL0RL=(u8)(yinReload);
?? ??? ?TH0=TH0RL;
?? ??? ?TL0=TL0RL;
?? ??? ?
?? ??? ?//計(jì)算播放時(shí)間,取出音符長(zhǎng)度,轉(zhuǎn)化成進(jìn)入中斷的次數(shù),與頻率有關(guān)
?? ??? ?//音長(zhǎng)的0.75進(jìn)行播放,0.25靜音
?? ??? ?yinChangN=TwoTigerYinLen[i];
?? ??? ?yinHz=Frequ[yin-1];//取出頻率,參與進(jìn)入中斷次數(shù)的計(jì)算
?? ??? ?yinChang=(yinChangN*pai1p16*yinHz*2/1000);//要用i32,否則高位丟失
?? ??? ?silentCnt=yinChang>>2;???? //音長(zhǎng)的0.75進(jìn)行播放,0.25靜音
?? ??? ?beepCnt=yinChang-silentCnt;//音長(zhǎng)的0.75進(jìn)行播放,0.25靜音
?? ??? ?
?? ??? ?//開啟T0,去播放改頻率(音)
?? ??? ?ET0=TR0=1;
?? ??? ?beepBusy=1;
?? ??? ?
?? ??? ?while(beepBusy==1);//等待這個(gè)音播放完畢,切換下一個(gè)音
?? ?}?? ?
}
int main(void)
{
?? ?u16 i;
?? ?
?? ?EA = 1;?????? //使能全局中斷
?? ?TMOD = 0x01;? //配置T0工作在模式1
?? ?
?? ?while (1)
?? ?{
?? ??? ?PlayTwoTiger();? //播放樂曲--兩支老虎
?? ??? ?for (i=0; i<40000; i++);? //停止一段時(shí)間
?? ?}
}
/* T0中斷服務(wù)函數(shù),用于控制蜂鳴器發(fā)聲 */
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控制時(shí)間的方式
#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對(duì)應(yīng)頻率列表
?? ?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對(duì)應(yīng)的定時(shí)器重載值
?? ?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,
};
//兩只老虎節(jié)拍表,4表示一拍,1就是1/4拍,8就是2拍,,該拍用來計(jì)算播放時(shí)長(zhǎng)
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,調(diào)節(jié)播放速度
u32 pai1p16=125; //1/16拍=125ms,
u8 TH0RL = 0x00;? //T0重載值的高字節(jié)
u8 TL0RL = 0x00;? //T0重載值的低字節(jié)
u16 beepCnt=0; //每個(gè)音的發(fā)聲時(shí)長(zhǎng)
u16 silentCnt=0; //每個(gè)音的靜音時(shí)長(zhǎng)
bit beepBusy=0; //0=一個(gè)音播放完畢,可以切換下一個(gè);1=一個(gè)音正在播放,不能切換下一個(gè)
/* 兩只老虎樂曲播放函數(shù) */
void PlayTwoTiger()
{
?? ?u8 i;
?? ?u8 yin;
?? ?u16 yinReload;
?? ?u8 yinChangN;
?? ?u16 yinChang;
?? ?u8 cnt=sizeof(TwoTigerYinLen);
?? ?
?? ?for(i=0;i<cnt;i++)
?? ?{
?? ??? ?//取出音符,轉(zhuǎn)換成頻率,轉(zhuǎn)換成T0的初值,設(shè)置T0,
?? ??? ?yin=TwoTigerYin[i];//取出音符
?? ??? ?yinReload=Frequ2Reload[yin-1];//根據(jù)音符查詢到T0初值
?? ??? ?TH0RL=(u8)(yinReload>>8);
?? ??? ?TL0RL=(u8)(yinReload);
?? ??? ?//T0負(fù)責(zé)發(fā)出指定頻率的聲音
?? ??? ?TH0=TH0RL;
?? ??? ?TL0=TL0RL;
?? ??? ?
?? ??? ?//計(jì)算播放時(shí)間,取出音符長(zhǎng)度,轉(zhuǎn)換成時(shí)間ms,再轉(zhuǎn)化成進(jìn)入0.25ms中斷的次數(shù)
?? ??? ?//音長(zhǎng)的0.75進(jìn)行播放,0.25靜音
?? ??? ?yinChangN=TwoTigerYinLen[i];//取出(1/16拍)的倍數(shù)
?? ??? ?yinChang=(yinChangN*pai1p16*4);//0.25ms,所以乘4???? 要用i32,否則高位丟失
?? ??? ?silentCnt=yinChang>>2;???? //音長(zhǎng)的0.75進(jìn)行播放,0.25靜音
?? ??? ?beepCnt=yinChang-silentCnt;//音長(zhǎng)的0.75進(jìn)行播放,0.25靜音
?? ??? ?
?? ??? ?//開啟T0,去播放改頻率(音),,開啟T1去控制播放時(shí)間
?? ??? ?ET0=TR0=1;
?? ??? ?TH1=TL1=0x1A; //方式2自動(dòng)重裝,0.25ms一次中斷
?? ??? ?ET1=TR1=1;
?? ??? ?beepBusy=1;//控制播放下一個(gè)音
?? ??? ?
?? ??? ?while(beepBusy==1);//等待這個(gè)音播放完畢,切換下一個(gè)音
?? ?}
?? ?
}
int main(void)
{
?? ?u16 i;
?? ?
?? ?EA = 1;?????? //使能全局中斷
?? ?TMOD = 0x21;? //配置T0工作在模式1; T2工作在方式2, 0.25ms進(jìn)入一次
?? ?PT0=1;//T0優(yōu)先級(jí)高,效果好
?? ?while (1)
?? ?{
?? ??? ?PlayTwoTiger();? //播放樂曲--兩支老虎
?? ??? ?for (i=0; i<40000; i++);? //停止一段時(shí)間
?? ?}
}
/* T0中斷服務(wù)函數(shù),用于控制蜂鳴器發(fā)聲頻率 */
void Timer0_ISR() interrupt 1
{
?? ?TH0 = TH0RL;?? //重新加載重載值
?? ?TL0 = TL0RL;
?? ?BUZZ=~BUZZ;
}
/* T1中斷服務(wù)函數(shù),用于控制蜂鳴器發(fā)聲時(shí)間 */
void Timer1_ISR(void) interrupt 3
{
?? ?if(beepCnt)//發(fā)聲時(shí)間段
?? ?{
?? ??? ?beepCnt--;
?? ?}
?? ?else if(silentCnt)//禁止發(fā)聲時(shí)間段
?? ?{
?? ??? ?silentCnt--;
?? ??? ?TR0=0;
?? ?}
?? ?else //這個(gè)音播放完畢
?? ?{
?? ??? ?beepBusy=0;
?? ??? ?TR1=0;
?? ?}
}