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

STM32F401 Nucleo板按键中断控制PWM失效问题求助

问题排查与修正方案

你的代码存在多处寄存器配置错误,导致按键中断无法正常触发,以下是具体问题和修正方法:

1. 中断服务函数与NVIC配置不匹配

PC13对应EXTI13,属于EXTI10~15范围,共用EXTI15_10_IRQn中断通道,而非EXTI1_IRQn。同时中断服务函数名称必须对应为EXTI15_10_IRQHandler,否则中断触发后无法进入正确的处理函数。

2. EXTICR寄存器配置错误

  • PC13对应EXTI13,需配置SYSCFG->EXTICR[3](EXTICR数组索引3对应EXTI12~13位),而非EXTICR[2]。
  • 移位位置应使用SYSCFG_EXTICR3_EXTI13_Pos,而非SYSCFG_EXTICR1_EXTI1_Pos(后者对应EXTI1引脚)。
  • 正确值为0x2(对应GPIOC,0x0=GPIOA,0x1=GPIOB,0x2=GPIOC)。

3. EXTI掩码与触发位配置错误

  • EXTI->IMR需开启MR13位(EXTI_IMR_MR13_Pos),而非MR1位。
  • PC13按键通常是低电平有效(按下时接地),建议配置下降沿触发(EXTI->FTSR |= (0x1<<EXTI_FTSR_TR13_Pos)),而非上升沿,避免上电误触发。

4. 中断标志位清除错误

EXTI的PR寄存器需要写入1来清除中断标志,你的代码写入0等于未清除,会导致中断持续触发或无法响应后续按键。正确写法:EXTI->PR |= EXTI_PR_PR13;

5. GPIO配置顺序错误

必须先开启GPIOC时钟并配置引脚为输入模式,再配置EXTI中断,否则EXTI无法正确关联GPIO引脚。

6. 主函数错误手动调用中断服务函数

主函数中EXTI1_IRQHandler();是错误的,这会在程序启动时直接修改flag值,导致初始状态异常,必须删除。


修正后的代码片段

中断配置与服务函数

#include <stdbool.h>

void INTERRUPT_CONFIG(){
    // 确保GPIOC已配置为输入模式(主函数中提前配置)
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
    
    // 将EXTI13映射到GPIOC
    SYSCFG->EXTICR[3] |= (0x2 << SYSCFG_EXTICR3_EXTI13_Pos);
    
    // 开启EXTI13中断掩码
    EXTI->IMR |= (0x1 << EXTI_IMR_MR13_Pos);
    
    // 配置下降沿触发(适配PC13低电平有效按键)
    EXTI->FTSR |= (0x1 << EXTI_FTSR_TR13_Pos);
    EXTI->RTSR &= ~(0x1 << EXTI_RTSR_TR13_Pos);
    
    // 配置NVIC优先级并开启中断
    NVIC_SetPriority(EXTI15_10_IRQn, 1);
    NVIC_EnableIRQ(EXTI15_10_IRQn);
}

bool flag = false;

// 对应EXTI10~15的中断服务函数
void EXTI15_10_IRQHandler(){
    if(EXTI->PR & EXTI_PR_PR13){
        // 清除中断标志位(写1清除)
        EXTI->PR |= EXTI_PR_PR13;
        flag = !flag;
    }
}

主函数

int main(void)
{
    TIM2_INIT();
    
    // 先配置PC13为输入模式
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
    GPIOC->MODER &= ~(GPIO_MODER_MODE13_Msk); // 清除原有配置,设为输入
    GPIOC->PUPDR |= (0x1 << GPIO_PUPDR_PUPD13_Pos); // 上拉电阻
    
    // 再配置中断
    INTERRUPT_CONFIG();

    while (1)
    {
        if(flag == true){
            TIM2->CR1 &= ~TIM_CR1_CEN; // 停止TIM2
        }
        else{
            TIM2->CR1 |= TIM_CR1_CEN; // 恢复TIM2运行(防止停止后无法重启)
            int x;
            for(x=0; x<500; x++)
            {
                TIM2->CCR1 = x;
                delayFunct(1);
            }
            for(x=500; x>0; x--)
            {
                TIM2->CCR1 = x;
                delayFunct(1);
            }
        }
    }
}

额外建议:实际使用中建议加入按键消抖逻辑(比如在中断服务函数中添加短延时后再次检测引脚状态,或使用定时器消抖),避免按键抖动导致flag频繁切换。

内容的提问来源于stack exchange,提问作者Petar Ristic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 09:47:10