蜂鸣器一般可以分为两种,一种是有源蜂鸣器,另一种是无源蜂鸣器。
有源蜂鸣器中的源是指震荡源,也就是给了电压再给个触发信号就会以固定的频率发出声响。
而无源蜂鸣器内部没有震荡源,我们可以将触发信号的频率传给无源蜂鸣器,这样就可以发出不同音阶的声响了。
下面是我买的无源蜂鸣器的原理图以及实物图。
可以看得出有三个引脚,VCC接3.3V~5V(以你们手上的无源蜂鸣器为准),GND接地。
中间的 I/O 接PWM信号。
我这里是低电平驱动,因此给的PWM信号中低电平占比越高,发出的声响越大。也就是占空比越小,声音越大。
而无源蜂鸣器发出的音调是和PWM的频率有关。
具体怎么发出PWM,可以查看我同专栏之前的文章。
简而言之就是利用STM32的定时器来发出PWM,也就是说PWM的频率和定时器的频率是一样的。
定时器溢出频率=72MHz/预分频器的值+1/自动重装器的值
所以PWM的频率跟两个参数有关,一个是预分频器,一个是自动重装器。
而自动重装器跟PWM的阈值有关,也就是调整占空比的,因此我们一般不会去动。所以我们就只能是通过调整预分频器来调整频率了。
第三个参数(表格中输入参数1,输入参数2好像有点问题,因为上面函数原型中参数有三个)我们就选择即时装入。
在输出PWM的基础上,我们再通过上面的函数来动态调增预分频器,以此来改变PWM的频率,就可以发出不同声调的声音了。
根据我几乎没有的乐理知识编写了下面的代码,“演奏”了副歌部分的一半,依稀可以听出来大概的调调。
需要注意的是我这里用的是TIM2,输出通道1,所以PWM输出在GPIOA的0号引脚,如果要改动的话,需要去参考引脚定义表。
#include "stm32f10x.h" // Device header
#include "Delay.h"
const uint16_t music[3][8]={ //低中高音对应频率所需的预分频数
{0,381,340,303,286,255,227,202},
{0,191,170,151,143,127,113,101},
{0,95,85,75,71,63,56,50}
};
void play(uint8_t i,uint8_t j,uint16_t time){
//调整定时器的预分频器达到调整频率的效果
TIM_PrescalerConfig(TIM2,music[i][j],TIM_PSCReloadMode_Immediate);
Delay_ms(time);
}
int main(void){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //打开TIM2的外设时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef gitd;
gitd.GPIO_Mode=GPIO_Mode_AF_PP; //配置为复用推挽输出
gitd.GPIO_Pin=GPIO_Pin_0;
gitd.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOA,&gitd);
TIM_InternalClockConfig(TIM2); //选择内部时钟(72MHz)作为时钟源
TIM_TimeBaseInitTypeDef itd;
itd.TIM_ClockDivision=TIM_CKD_DIV1; //时钟1分频
itd.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
itd.TIM_Period=720-1; //设置自动重装器的值
itd.TIM_Prescaler=0; //设置预分频器的值
itd.TIM_RepetitionCounter=0; //重复计数器的值,但是仅高级定时器有效
TIM_TimeBaseInit(TIM2,&itd);
TIM_OCInitTypeDef itd1;
itd1.TIM_OCMode = TIM_OCMode_PWM1; //比较输出模式为PWM1
itd1.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性为高电平
itd1.TIM_OutputState=TIM_OutputState_Enable; //使能
itd1.TIM_Pulse=710; //初始化输出比较的阈值
TIM_OC1Init(TIM2,&itd1);
TIM_Cmd(TIM2,ENABLE); //使能定时器
while(1){
play(1,5,1200);
play(1,6,800);
play(1,7,400);
play(1,6,400);
play(1,5,400);
play(1,3,800);
play(1,2,800);
TIM_SetCompare1(TIM2,720);
Delay_ms(800);
TIM_SetCompare1(TIM2,710);
play(1,5,1200);
play(1,3,400);
play(1,2,600);
play(1,1,600);
play(1,2,400);
play(1,1,400);
play(1,2,400);
play(1,3,800);
TIM_SetCompare1(TIM2,720);
Delay_ms(800);
TIM_SetCompare1(TIM2,710);
play(0,7,400);
play(1,1,400);
play(1,2,400);
play(1,3,400);
play(1,2,400);
play(1,3,400);
play(1,5,400);
play(1,3,400);
play(1,2,400);
play(1,1,200);
play(1,2,400);
play(0,6,400);
TIM_SetCompare1(TIM2,720);
Delay_ms(800);
TIM_SetCompare1(TIM2,710);
play(1,1,800);
play(1,2,400);
play(1,3,400);
play(1,2,400);
play(1,3,400);
play(1,5,400);
play(1,6,400);
play(1,5,600);
play(1,3,1200);
play(1,2,600);
TIM_SetCompare1(TIM2,720);
Delay_ms(800);
TIM_SetCompare1(TIM2,710);
}
}
《STM32F103xx固件函数库用户手册》