STM32F4 PWM蜂鸣器播放歌曲中途停止问题求助及解决
STM32F407 PWM蜂鸣器播放歌曲中断问题排查与解决
嘿,看你描述的问题——能出音调但播到一半停住,过会儿还自动重启,这事儿我之前调STM32定时器的时候也踩过坑!先给你拆解下问题根源,再结合你的代码说清楚怎么把它彻底搞定:
问题核心原因
你直接修改定时器ARR寄存器的时候,没同步重置CNT(计数器)寄存器。举个例子:当前定时器计数到了3000,你突然把ARR改成2000,这时候CNT已经大于ARR了,定时器会进入异常状态,要么PWM输出直接挂掉,要么触发硬件错误触发看门狗复位(这就是为啥过几分钟会重启——大概率是看门狗超时了)。
针对你代码的修复方案
首先,必须在每次更新ARR和CCR1之后手动清零CNT,另外你的循环次数硬写55明显不对——你的notes数组只有25个元素,硬写55会导致数组越界,这也是可能崩溃的原因!修改后的playSong函数应该是这样:
uint32_t Frequency = C; uint32_t CLOCK = 16000000; int i; /* Hap py Birth Day to you, Hap py birth day to C4 C4 D4 C4 F4 E4 C4 C4 D4 C4 G4 */ unsigned int notes[] = { 262, 262, 294, 262, 349, 330, 262, 262, 294, 262, 392, /* you, Hap py Birth Day dear xxxx Hap py birth F4 C4 C4 C5 A4 F4 E4 D4 B4b B4b A4 */ 349, 262, 262, 523, 440, 349, 330, 294, 466, 466, 440, /* day to you F4 G4 F4 */ 349, 392, 349 }; unsigned int duration[] = {1,1,2,2,2,2,1,1,2,2,2,2,1,1,2,2,2,2,2,1,1,2,2,2,2}; void noTone(){ htim2.Instance->CCR1=0; HAL_Delay(50); } void playSong(){ // 用sizeof动态获取数组长度,避免硬编码导致越界 for (i = 0; i < sizeof(notes)/sizeof(notes[0]); i++) { Frequency = CLOCK/notes[i]; htim2.Instance->ARR=Frequency; htim2.Instance->CCR1=Frequency/2; htim2.Instance->CNT = 0; // 关键:重置计数器,避免CNT > ARR触发异常 HAL_Delay(400*duration[i]); noTone(); } }
额外优化建议(让代码更健壮)
- 尽量用HAL库函数代替直接操作寄存器:虽然直接改寄存器能工作,但HAL库封装了很多细节,代码更易维护,比如:
__HAL_TIM_SET_AUTORELOAD(&htim2, Frequency); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, Frequency/2); __HAL_TIM_SET_COUNTER(&htim2, 0); // HAL方式清零计数器 - 优化蜂鸣器启停逻辑:可以用
HAL_TIM_PWM_Start/Stop来控制输出,比只改CCR1更可靠:void noTone(){ HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1); HAL_Delay(50); } - 检查看门狗配置:如果你的板子开启了看门狗,长时间的
HAL_Delay可能导致喂狗不及时触发重启,记得在循环里添加喂狗操作(如果用了看门狗的话)。
很高兴你已经找到了解决方向——清零CNT寄存器确实是这类定时器异常问题的核心修复点,上面的优化建议可以帮你让代码更稳定!
内容的提问来源于stack exchange,提问作者Altus Cilliers




