蜂鸣器开发笔记
1. 蜂鸣器类型
常用的蜂鸣器类型主要分为两类。
- 有源蜂鸣器,内置震荡电路,固定频率(固定音调)。依靠高低电平驱动。可以播放简单提示音。
- 无源蜂鸣器,五震荡电路,依靠PWM驱动。可以播放旋律。
有源蜂鸣器通常比无源蜂鸣器便宜约20%-50%,通常尺寸越大越贵,普通蜂鸣器均价在8毛左右。
典型蜂鸣器工作范围大概在500Hz - 5kHz。
无源蜂鸣器频率与音高的关系:频率越高,声音越尖锐。本人对音乐没有什么造诣,很难分辨哆来咪发唆,感觉差不太多。
2. 无源蜂鸣器控制
控制要点:通过不同的PWM频率来调整音高,占空比用50%即可。
关键在于重装载值的计算,根据目标频率反推计算重装载值(ARR)
- 计算PWM频率 = 时钟频率 / (预分频 × ARR)
- 占空比 = CRR / ARR = 50%
/**
* @brief 计算TIM3的ARR值(自动重装载值)
* @param u16FreqHz 目标频率(Hz)
* @return ARR值,0表示频率超出范围
*/
static uint16_t BspBeepCalculateArr(uint16_t u16FreqHz)
{
uint32_t u32Arr;
if (u16FreqHz < BEEP_FREQ_MIN || u16FreqHz > BEEP_FREQ_MAX) {
return 0;
}
// 计算公式:ARR = (Fpclk / (预分频 * 频率)) - 1
// Fpclk = 48MHz, 预分频 = 1
u32Arr = (SYSTEM_CLOCK_FREQ / u16FreqHz) - 1;
// ARR必须是16位无符号整数
if (u32Arr > 0xFFFF) {
return 0;
}
return (uint16_t)u32Arr;
}
/**
* @brief 设置蜂鸣器频率
* @param u16FreqHz 目标频率(Hz),范围:500-8000Hz
* @note 频率设置立即生效,但不会自动启动蜂鸣器
*/
void BspBeepSetFrequency(uint16_t u16FreqHz)
{
uint16_t u16Arr, u16Ccr;
// 检查频率范围
if (u16FreqHz < BEEP_FREQ_MIN || u16FreqHz > BEEP_FREQ_MAX) {
LOG_WARN("Beep frequency %dHz out of range (%d-%d)",
u16FreqHz, BEEP_FREQ_MIN, BEEP_FREQ_MAX);
return;
}
// 计算ARR和CCR值
u16Arr = BspBeepCalculateArr(u16FreqHz);
if (u16Arr == 0) {
LOG_ERROR("Failed to calculate ARR for frequency %dHz", u16FreqHz);
return;
}
u16Ccr = BspBeepCalculateCcr(u16Arr);
// 保存频率
s_stBeepCtrl.frequency = u16FreqHz;
// 如果TIM3已经初始化,更新配置
if (s_bTimer3Initialized) {
bool wasActive = s_stBeepCtrl.isActive;
// 如果正在响铃,先停止
if (wasActive) {
BspBeepOff();
}
// 重新配置TIM3
BspTimer3Cfg(u16Arr, u16Ccr);
// 如果之前正在响铃,重新启动
if (wasActive) {
BspBeepOn();
}
} else {
// 首次配置TIM3
BspTimer3Cfg(u16Arr, u16Ccr);
}
LOG_DEBUG("Beep frequency set to %dHz (ARR=0x%04X, CCR=0x%04X)",
u16FreqHz, u16Arr, u16Ccr);
}