STM446RET sw_mode重启后蜂鸣器中途断音问题修复请求
STM32F446RET蜂鸣器重启断音问题排查与修复
我基于STM32F446RET开发了一款程序,功能逻辑如下:
- 播放音乐时按下开关2,计数器值增加,当计数器超过设定阈值时判定为成功
- 无音乐播放时按下开关2,则判定为失败
完成代码编写与测试后,发现成功后按下开关1通过sw_mode重启程序时,蜂鸣器会出现中途断音的问题,多次修改重置条件仍无法解决,以下是相关代码片段:
void Timer2_PWM_Init(uint16_t psc, uint16_t arr) { RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; GPIOA->MODER |= GPIO_MODER_MODE15_1; GPIOA->AFR[1] |= 0x1 << GPIO_AFRH_AFSEL15_Pos; TIM2->PSC = psc - 1; TIM2->ARR = arr - 1; TIM2->CCR1 = arr / 2; TIM2->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; TIM2->CCER |= TIM_CCER_CC1E; TIM2->CR1 |= TIM_CR1_CEN; } void Timer2_Stop(void) { TIM2->CR1 &= ~TIM_CR1_CEN; TIM2->CCR1 = 0; } void Play_Tones(void) { num_tones = sizeof(tone_psc) / sizeof(tone_psc[0]); for (i = 0; i < num_tones; i++) { state =10; Timer2_PWM_Init(tone_psc[i], melody_arr[i]); TimeDelay(melody_delay[random_case%3][i] * 1000); Timer2_Stop(); if (i != num_tones - 1) { TimeDelay(500000); } } state =11; } void Play_success_Tone(void) { LED0_GPIO_Port->BSRR = (1UL << LED0_Pin) << 16; LED1_GPIO_Port->BSRR = (1UL << LED1_Pin) << 16; LED2_GPIO_Port->BSRR = (1UL << LED2_Pin) << 16; LED3_GPIO_Port->BSRR = (1UL << LED3_Pin) << 16; LED4_GPIO_Port->BSRR = (1UL << LED4_Pin) << 16; LED5_GPIO_Port->BSRR = (1UL << LED5_Pin) << 16; LED6_GPIO_Port->BSRR = (1UL << LED6_Pin) << 16; LED7_GPIO_Port->BSRR = (1UL << LED7_Pin) << 16; for (i = 0; i < 3; i++) { Timer2_PWM_Init(tone_psc_success[i], success_tones[i]); TimeDelay(success_delays[i] * 1000); Timer2_Stop(); TimeDelay(200000); } } void Play_Fail_Tone(void) { LED0_GPIO_Port->BSRR = (1UL << LED0_Pin) << 16; LED1_GPIO_Port->BSRR = (1UL << LED1_Pin) << 16; LED2_GPIO_Port->BSRR = (1UL << LED2_Pin) << 16; LED3_GPIO_Port->BSRR = (1UL << LED3_Pin) << 16; LED4_GPIO_Port->BSRR = (1UL << LED4_Pin) << 16; LED5_GPIO_Port->BSRR = (1UL << LED5_Pin) << 16; LED6_GPIO_Port->BSRR = (1UL << LED6_Pin) << 16; LED7_GPIO_Port->BSRR = (1UL << LED7_Pin) << 16; for (i = 0; i < 2; i++) { Timer2_PWM_Init(tone_psc_fail[i], fail_tones[i]); TimeDelay(fail_delays[i] * 1000); TimeDelay(200000); } TimeDelay(500000); TimeDelay(500000); for (i = 3; i < 4; i++) { Timer2_PWM_Init(tone_psc_fail[i], fail_tones[i]); TimeDelay(fail_delays[i] * 1000); Timer2_Stop(); TimeDelay(200000); } } void game_play(void){ while(num_game>0){ state =11; if (fail_count == 1) { Play_Fail_Tone(); break; //game over } else if(f_count >= 80){ Play_success_Tone(); break; } else if (num_game >0) { random_case = rand() % 3; sw_mode = 0; Play_Tones(); state =11; random_case = 0; if (fail_count == 1) { Play_Fail_Tone(); break; //game over } TimeDelay(10000); } if (fail_count == 1) { Play_Fail_Tone(); break; //game over } num_game--; TimeDelay(1000000); TimeDelay(1000000); TimeDelay(1000000); TimeDelay(1000000); TimeDelay(1000000); } } void Reset_Game(void) { sw_mode = 0; fail_count = 0; f_count = 0; mitter = 80; state = 0; num_game = 10; random_case = 0; Timer2_Stop(); // ??? ?? } int main(void) { pb_initialize(); pb_interrupt_init(); led_initialize(); while (1) { if(sw_mode==1 && end_1 == 0){ Reset_Game(); game_play(); Reset_Game(); } } } void EXTI2_IRQHandler(void) { if ((EXTI->PR & EXTI_PR_PR2) == EXTI_PR_PR2) { sw_mode = 1; EXTI->PR |= EXTI_PR_PR2; } } void EXTI4_IRQHandler(void) { if ((EXTI->PR & EXTI_PR_PR4) == EXTI_PR_PR4) { if (state == 10) { f_count++; mitter -= 1; if (f_count % 10 == 0) { rotate_left(); } } else if(state ==11){ fail_count= 1; end_1 =1; } EXTI->PR |= EXTI_PR_PR4; } }
问题根源分析
- 重置时机冲突:
main函数中game_play()执行完成后立即调用Reset_Game(),而Play_success_Tone()可能还在播放过程中就被Timer2_Stop()强制停止,直接导致断音。 - 全局变量未同步:成功流程中未重置
end_1标记,重启逻辑的条件判断会出现异常。 - Timer重复初始化:
Timer2_PWM_Init()每次都重复开启时钟、配置GPIO,多次操作会导致硬件状态混乱,影响重启后的PWM输出。 - 失败音效逻辑漏洞:
Play_Fail_Tone()前两次循环未调用Timer2_Stop(),Timer持续运行会干扰后续音效输出。
修复方案
1. 调整重置时机,等待音效播放完成
修改game_play()和main()逻辑,确保成功音效播放完毕后再执行重置:
void game_play(void){ while(num_game>0){ state =11; if (fail_count == 1) { Play_Fail_Tone(); break; } else if(f_count >= 80){ Play_success_Tone(); end_1 = 1; // 标记成功结束 break; } else if (num_game >0) { random_case = rand() % 3; sw_mode = 0; Play_Tones(); state =11; random_case = 0; if (fail_count == 1) { Play_Fail_Tone(); break; } TimeDelay(10000); } if (fail_count == 1) { Play_Fail_Tone(); break; } num_game--; TimeDelay(1000000); TimeDelay(1000000); TimeDelay(1000000); TimeDelay(1000000); TimeDelay(1000000); } } int main(void) { pb_initialize(); pb_interrupt_init(); led_initialize(); Reset_Game(); // 初始化时执行一次重置 while (1) { if(sw_mode==1 && end_1 == 1){ Reset_Game(); game_play(); } else if(sw_mode==1 && end_1 ==0){ game_play(); } } }
2. 拆分Timer初始化逻辑,避免重复配置
将GPIO和时钟配置移到单独的初始化函数中,仅在程序启动时执行一次:
void Timer2_Gpio_Init(void) { RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; GPIOA->MODER |= GPIO_MODER_MODE15_1; GPIOA->AFR[1] |= 0x1 << GPIO_AFRH_AFSEL15_Pos; } void Timer2_PWM_Init(uint16_t psc, uint16_t arr) { TIM2->PSC = psc - 1; TIM2->ARR = arr - 1; TIM2->CCR1 = arr / 2; TIM2->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; TIM2->CCER |= TIM_CCER_CC1E; TIM2->CR1 |= TIM_CR1_CEN; } // 在main的初始化部分添加调用 int main(void) { pb_initialize(); pb_interrupt_init(); led_initialize(); Timer2_Gpio_Init(); // 初始化Timer相关GPIO和时钟 Reset_Game(); while (1) { // ...原有逻辑 } }
3. 完善重置函数的变量同步
在Reset_Game()中添加end_1的重置,确保重启时状态正确:
void Reset_Game(void) { sw_mode = 0; fail_count = 0; f_count = 0; mitter = 80; state = 0; num_game = 10; random_case = 0; end_1 = 0; // 重置成功结束标记 Timer2_Stop(); }
4. 修复失败音效的Timer停止逻辑
在Play_Fail_Tone()的前两次循环中添加Timer2_Stop(),避免Timer持续运行:
void Play_Fail_Tone(void) { // LED关闭代码... for (i = 0; i < 2; i++) { Timer2_PWM_Init(tone_psc_fail[i], fail_tones[i]); TimeDelay(fail_delays[i] * 1000); Timer2_Stop(); // 添加Timer停止操作 TimeDelay(200000); } // 延时代码... for (i = 3; i < 4; i++) { Timer2_PWM_Init(tone_psc_fail[i], fail_tones[i]); TimeDelay(fail_delays[i] * 1000); Timer2_Stop(); TimeDelay(200000); } }
内容的提问来源于stack exchange,提问作者Clear_love_man
相关产品推荐
相关产品推荐

