You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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; 
  }
}

问题根源分析

  1. 重置时机冲突:main函数中game_play()执行完成后立即调用Reset_Game(),而Play_success_Tone()可能还在播放过程中就被Timer2_Stop()强制停止,直接导致断音。
  2. 全局变量未同步:成功流程中未重置end_1标记,重启逻辑的条件判断会出现异常。
  3. Timer重复初始化:Timer2_PWM_Init()每次都重复开启时钟、配置GPIO,多次操作会导致硬件状态混乱,影响重启后的PWM输出。
  4. 失败音效逻辑漏洞: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 19:43:11