本帖最后由 lulugl 于 2023-9-24 15:39 编辑
有源蜂鸣器与无源蜂鸣器的驱动方式:
注意:这里的“源”不是指电源,而是指震荡源。
也就是说,有源蜂鸣器内部带震荡源,所以只要一通电就会叫;而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫,必须用2K-5K的方波去驱动它。
有源蜂鸣器往往比无源的贵,就是因为里面多个震荡电路。
无源蜂鸣器的优点是:
1. 便宜
2. 声音频率可控,可以做出“多来米发索拉西”的效果
3. 在一些特例中,可以和LED复用一个控制口
单片机驱动他激蜂鸣器的方式有两种:一种是PWM输出口直接驱动,另一种是利用I/O 定时翻转电平产生驱动波形对蜂鸣器进行驱动。
PWM 输出口直接驱动是利用PWM输出口本身可以输出一定的方波来直接驱动蜂鸣器。在单片机的软件设置中有几个系统寄存器是用来设置PWM口的输出的,可以设置占空比、周期等等,通过设置这些寄存器产生符合蜂鸣器要求的频率的波形之后,只要打开PWM输出,PWM输出口就能输出该频率的方波,这个时候利用这个波形就可以驱动蜂鸣器了。比如频率为2000Hz的蜂鸣器的驱动,可以知道周期为500μs,这样只需要把PWM的周期设置为500μs,占空比电平设置为250μs,就能产生一个频率为2000Hz的方波,通过这个方波再利用三极管就可以去驱动这个蜂鸣器了。
而利用I/O定时翻转电平来产生驱动波形的方式会比较麻烦一点,必须利用定时器来做定时,通过定时翻转电平产生符合蜂鸣器要求的频率的波形,这个波形就可以用来驱动蜂鸣器了。
比如为2500Hz的蜂鸣器的驱动,可以知道周期为400μs,这样只需要驱动蜂鸣器的I/O口每200μs翻转一次电平就可以产生一个频率为2500Hz,占空比为1/2duty的方波,再通过三极管放大就可以驱动这个蜂鸣器了。
驱动的原理图
音阶频率转换表
Cw32L031 pwm波形频率计算:
F=PLCK/((PSC+1)*(ADDR+1))
根据以上面的计算公式,我们的PLCK是已知的,PSC在初始化PWM时也是已知的,我们就只需要改变ADDR的装载值就可以实现不同频率的PWM波,用于驱动无源蜂鸣器发出指定音调的声音了。
根据开发板的原理图,我们驱动蜂鸣器的IO为PB3,经查数据手册,为GTIMI2的通道2,为此初始化代码如下:
void RCC_Configuration(void)
{
///< 当使用的时钟源HCLK大于24M,小于等于48MHz:设置FLASH 读等待周期为2 cycle
__RCC_FLASH_CLK_ENABLE();
FLASH_SetLatency(FLASH_Latency_2);
/* 0. HSI使能并校准 */
RCC_HSI_Enable(RCC_HSIOSC_DIV1);
/* 1. 设置HCLK和PCLK的分频系数 */
RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
RCC_SystemCoreClockUpdate(48000000);
}
void GPIO_Configuration(void)
{
/* PB3作为GTIM2的CH2 PWM 输出 */
__RCC_GPIOB_CLK_ENABLE();
PB03_AFx_GTIM2CH2();//复用为GTIM2-2
PB03_DIGTAL_ENABLE();
PB03_DIR_OUTPUT();
PB03_PUSHPULL_ENABLE();
}
void PWM_OutputConfig(void)
{
GTIM_InitTypeDef GTIM_InitStruct = {0};
__RCC_GTIM2_CLK_ENABLE();//启用GTIM2时钟
GTIM_InitStruct.Mode = GTIM_MODE_TIME; //设置为定时器模式
GTIM_InitStruct.OneShotMode = GTIM_COUNT_CONTINUE; //为连续计时模式
GTIM_InitStruct.Prescaler = 11; // 计数时钟TCLKD = TCLK/(PSC+1)
GTIM_InitStruct.ReloadValue = 0xffff; //GTIM的重载值
GTIM_InitStruct.ToggleOutState = DISABLE; //GTIM的翻转输出使能选择
GTIM_TimeBaseInit(CW_GTIM2, >IM_InitStruct);
GTIM_OCInit(CW_GTIM2, GTIM_CHANNEL2, GTIM_OC_OUTPUT_PWM_HIGH);//CHy 通道输出高电平
GTIM_SetCompare2(CW_GTIM2, 0xffff); //设置占空比为100%,PB3输出低电平,蜂鸣器停止
GTIM_Cmd(CW_GTIM2, ENABLE);
}
根据上面的公式,我们确定ARR的计算公式为
ADRR= (48000000/((11+1)* 音频频率))-1
简化为ADRR= (4000000/音频频率)-1
乐谱的计算,我们先用宏定义指定声音的频率值:
//定义低音音名E
#define L1 330
#define L2 370
#define L3 415
#define L4 440
#define L5 494
#define L6 554
#define L65 587
#define L7 622
//定义中音音名E
#define M1 659
#define M2 740
#define M3 831
#define M4 880
#define M5 988
#define M6 1109
#define M7 1245
//定义高音音名E
#define H1 1319
#define H2 1480
#define H3 1661
#define H4 1760
#define H5 1976
声明一个结构体用于存放对应的音阶与节拍时长
typedef struct
{
short mName; //音名
short mTime; //时值,全音符,二分音符,四分音符
}tNote;
一个节拍定义时间长度为2S
//定义时值单位,决定演奏的速度 ms为单位 2000为佳
#define TT 2000
在网上找的一个现成的曲谱为:
const tNote YourScore[]=
{
{M6,TT/4},{H3,TT/8+TT/16},{H2,TT/16},{H2,TT/4},{H1,TT/8},{M6,TT/8},
{M5,TT/4},{H1,TT/8+TT/16},{H2,TT/16},{M6,TT/4},{0,TT/4},
{M6,TT/4},{H2,TT/4},{H1,TT/4},{M6,TT/8},{M5,TT/8},
{M2,TT/4},{M5,TT/8},{M6,TT/8},{M5,TT/8},{M3,TT/4},{0,TT/8},
//好运来祝你好运来,好运带来了喜和爱
{M3,TT/4},{M6,TT/8+TT/16},{M5,TT/16},{M6,TT/4},{M6,TT/8},{M5,TT/8},
{M6,TT/4},{H2,TT/8+TT/16},{H1,TT/16},{H2,TT/4},{0,TT/4},
{H1,TT/8+TT/16},{H1,TT/16},{H1,TT/8},{H2,TT/8},{H3,TT/8},{H3,TT/8},{H2,TT/8},{H1,TT/8},
{M5,TT/4},{H1,TT/8+TT/16},{M6,TT/16}, {M6,TT/2+TT/4},{0,TT/4},
//好运来我们好运来,迎着好运兴旺发达通四海
{M6,TT/8+TT/16},{M6,TT/16},{H1,TT/8},{H1,TT/8},{M6,TT/4},{0,TT/8},{M6,TT/8},
{M5,TT/8},{M3,TT/8},{M5,TT/8},{H1,TT/8},{M6,TT/4},{0,TT/4},
//叠个千纸鹤,再系个红腰带
{M6,TT/8},{H1,TT/8},{H1,TT/8+TT/16},{H1,TT/16},{H1,TT/8},{M6,TT/8},{M5,TT/4},
{M6,TT/8},{M5,TT/8},{M2,TT/8},{M5,TT/8},{M3,TT/4},{0,TT/8},{M2,TT/8},
//愿善良的人们天天好运来
{M3,TT/8},{M2,TT/8},{M1,TT/8},{M3,TT/8},{M2,TT/4},{0,TT/8},{M3,TT/8},
{M6,TT/8},{M5,TT/8},{M3,TT/8},{M6,TT/8},{M6,TT/8},{M5,TT/4},{0,TT/8},
//你勤劳生活美,你健康春常在
{M6,TT/8},{H1,TT/8},{H1,TT/8+TT/16},{M6,TT/16},{H2,TT/8},{H2,TT/8},{H2,TT/8},{H1,TT/8},
{M6,TT/4},{M5,TT/8},{H1,TT/8},{M6,TT/2+TT/4},{0,TT/4},
//你一生的忙碌为了笑逐颜开
{M6,TT/4},{H3,TT/8+TT/16},{H2,TT/16},{H2,TT/4},{H1,TT/8},{M6,TT/8},
{M5,TT/4},{H1,TT/8+TT/16},{H2,TT/16},{M6,TT/4},{0,TT/4},
{M6,TT/4},{H2,TT/4},{H1,TT/4},{M6,TT/8},{M5,TT/8},
{M2,TT/4},{M5,TT/8},{M6,TT/8},{M5,TT/8},{M3,TT/4},{0,TT/8},
//好运来祝你好运来,好运带来了喜和爱
{M3,TT/4},{M6,TT/8+TT/16},{M5,TT/16},{M6,TT/4},{M6,TT/8},{M5,TT/8},
{M6,TT/4},{H2,TT/8+TT/16},{H1,TT/16},{H2,TT/4},{0,TT/4},
{H1,TT/8+TT/16},{H1,TT/16},{H1,TT/8},{H2,TT/8},{H3,TT/8},{H3,TT/8},{H2,TT/8},{H1,TT/8},
{M5,TT/4},{H1,TT/8+TT/16},{M6,TT/16}, {M6,TT/2+TT/4},{0,TT/4},
//好运来我们好运来,迎着好运兴旺发达通四海
{H2,TT/4+TT/2},{0,TT/4},{H3,TT/4+TT/2},{0,TT/4},{M6,TT/4+TT/2},
{0,TT/4},{M5,TT/8},{M5,TT/8},{M6,TT/4},{0,TT/4},
//通四海,好运来
//Brave Heart
{L6,TT/2},{M3,TT/2},{M2,TT/2},{M5,TT/2},
{L7,TT/2},{0,TT/8},{M1,TT/8},{M2,TT/8},{M1,TT/8+TT/4}, //jump
{0,TT/2},{L5,TT/4},//A
{L6,TT/2},{M3,TT/2},{M2,TT/2},{M6,TT/2},
{M5,TT/2},{0,TT/8},{M2,TT/8},{M7,TT/8},{H1,TT/8},
{H1,TT/4},{0,TT/2},{H1,TT/8},{H2,TT/8},
{H3,TT/4},{H3,TT/8},{H2,TT/8+TT/2},{0,TT/2+TT/8},{M6,TT/8},{H1,TT/8},{H4,TT/8},
{H3,TT/4},{H3,TT/8},{H2,TT/8+TT},{0,TT/2+TT/4},//Jump
{L6,TT/8},{L5,TT/8},{L6,TT/8},{L7,TT/4},{M1,TT/8},
{0,TT/8},{M1,TT/8},{M1,TT/8},{M2,TT/8},{L7,TT/8},{L6,TT/8},{L5,TT/8},{L6,TT/8+TT/4},//Jump
{0,TT/8},{L6,TT/8},{L6,TT/8},{L5,TT/4},{L3,TT/8+TT},//B
{0,TT/4},{L6,TT/8},{L5,TT/8},{L6,TT/8},{L7,TT/4},{M1,TT/8},
{0,TT/8},{M1,TT/8},{M1,TT/8},{M2,TT/8},{L7,TT/8},{L6,TT/8},{L5,TT/8},{L6,TT/8+TT/4},//Jump
{0,TT/8},{L6,TT/8},{L6,TT/8},{L7,TT/4},{M1,TT/4},//Jump
{L7,TT/8},{M1,TT/8},{M2,TT/8},{M2,TT/4},{L5,TT/4},
{M4,TT/4+TT/8},{M3,TT/8},{M3,TT/4+TT/8},{M1,TT/8},
{M2,TT/4},{M2,TT/8},{M5,TT/8+TT/16},{0,TT/16},{M2,TT/8},{M3,TT/8},{M2,TT/8},//question
{M2,TT/4+TT/8},{M1,TT/8},{M1,TT/2},
{L7,TT/4},{L7,TT/8},{M3,TT/4+TT/8},{L7,TT/8},{L6,TT/8},
{L6,TT/2},{L6,TT/8},{L7,TT/4},{M1,TT/8},{M2,TT/4},{L6,TT/4},{L7,TT/4},{M1,TT/8},{L7,TT/8},
{L7,TT/2},{M1,TT/4+TT/8},{M2,TT/8},{M2,TT},//C
{0,TT/2},{0,TT/4+TT/8},{M1,TT/16},{M2,TT/16},
{M3,TT/4+TT/8},{M3,TT/8},{M5,TT/8+TT/16},{M4,TT/16+TT/8},{M3,TT/8},
{M2,TT/4+TT/8},{L5,TT/8},{L5,TT/4},{0,TT/8},{L7,TT/16},{M1,TT/16},
{M2,TT/4+TT/8},{M2,TT/8},{M4,TT/8+TT/16},{M3,TT/16+TT/8},{M2,TT/8},
{M2,TT/4+TT/8},{M1,TT/8},{M1,TT/2},//D
{0,TT/4},{L6,TT/4},{L7,TT/4},{M1,TT/4},
{M4,TT/4},{M3,TT/4},{M2,TT/4},{M1,TT/8},{M3,TT/4},{0,TT/8},//Jump //question
{0,TT/4},{M3,TT/8},{M2,TT/8},{M1,TT/8},{M2,TT/8+TT/2+TT/4},//Jump E
{0,TT/8},{M1,TT/16},{M2,TT/16},
{M3,TT/4},{0,TT/8},{M3,TT/8},{M5,TT/8+TT/16},{M4,TT/16+TT/8},{M3,TT/8},
{M2,TT/4+TT/8},{L5,TT/8},{L5,TT/4},{0,TT/8},{L7,TT/16},{M1,TT/16},
{M2,TT/4},{0,TT/8},{M2,TT/8},{M4,TT/8+TT/16},{M3,TT/16+TT/8},{M2,TT/8},
{M2,TT/4+TT/8},{M1,TT/8},{M1,TT/2}, //F
{M4,TT/8+TT/16},{M3,TT/16+TT/8},{M2,TT/8},{M1,TT/8},{L7,TT/8},{0,TT/4},
{M5,TT/8+TT/16},{M4,TT/16+TT/8},{M3,TT/8},{M2,TT/8},{M1,TT/8},{0,TT/4},
{M4,TT/8+TT/16},{M3,TT/16+TT/8},{M2,TT/8},{M1,TT/8},{L7,TT/4},
{M1,TT},{0,TT/8},{0,TT/4},{L65,TT/8},{L65,TT/8},{L65,TT/8},{L65,TT/8},{M1,TT/8},
{M1,TT},//G
};
以下函数实现发声功能:
//蜂鸣器发出声音
//usFreq即发声频率
void buzzerSound(unsigned short usFraq) //usFraq是发声频率,即真实世界一个音调的频率。
//取值是(系统时钟/65536)+1~20000,单位为Hz。即122~20000Hz。
{
unsigned long ulVal;
if((usFraq<=4000000/65536UL)||(usFraq>20000))
{
buzzerQuiet();
}
else
{
ulVal=(4000000/usFraq)-1;//系统时钟除以现实频率,装入ARR
GTIM_SetCompare2(CW_GTIM2, ulVal/2); //占空比,决定音量的大小
GTIM_SetReloadValue(CW_GTIM2,ulVal); //重载值,频率的大小——》音调的高与低。
GTIM_Cmd(CW_GTIM2, ENABLE);
}
}
播放一整首哥的函数:
//Play Music
void musicPlay(void)
{
uint8_t i=0;
while(1)
{
if(YourScore.mTime==0)
break;
buzzerSound(YourScore.mName);
SysTickDelay(YourScore.mTime);
i++;
SysTickDelay(10); //10ms,加不加差别不大
}
}
下载好后,就可以实现播放音乐了。
|
|