欢迎光临散文网 会员登陆 & 注册

第9章-步进电机与蜂鸣器(下:蜂鸣器播放音乐)

2023-08-27 23:34 作者:feifeiluan2  | 我要投稿

无源蜂鸣器发声;需要方波,可以控制频率

挺绕的,一方面要控制频率,一方面要控制发声时间

有源蜂鸣器:给电就响,控制简单

老师的只能看懂一半,

用自己的理解改写了一半,成功

//用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;
    }
}



第9章-步进电机与蜂鸣器(下:蜂鸣器播放音乐)的评论 (共 条)

分享到微博请遵守国家法律