STM32 EXTI中断:PB4按键单次按下变量无限自增问题咨询
STM32 EXTI按键单次触发计数的配置要点
你当前代码出现单次按下变量无限自增的问题,由几个典型配置错误导致,按以下要点修正即可实现预期功能:
- 必须在中断服务函数中清除EXTI挂起标志位:这是中断无限触发的直接原因。STM32 EXTI中断触发后,硬件会自动置位对应通道的挂起标志位,该位不会自动清零,只要标志位为1,NVIC会持续判定中断待响应,反复进入ISR执行。清除方式为向
EXTI->PR1(部分系列命名为EXTI->FPR1)对应通道的bit位写1,注意该寄存器是写1清零,写0无效。 - 补全PB4引脚的基础GPIO配置:你的代码中注释掉了GPIO初始化流程,既未开启GPIOB外设时钟,也未将PB4配置为对应输入模式。引脚浮空状态下电平随机跳变,会持续触发中断。常规按键电路为按下接GND、松开接VCC,需将PB4配置为上拉输入模式。
- 添加机械按键消抖逻辑:机械按键按下、松开瞬间会产生5~10ms的电平抖动,短时间内会生成多个有效触发边沿,即使清除了挂起标志,也会出现单次按键计数多次累加的问题,需通过延时判断、定时器计时等方式做消抖处理。
- 寄存器配置避免残留值干扰:配置
SYSCFG->EXTICR选择EXTI对应的GPIO端口时,要先将对应位域的原有值清零再写入新配置,不要仅做或运算,避免寄存器旧值导致端口选择错误。 - 中断中修改的全局变量需加
volatile修饰:避免编译器对变量做优化,导致调试时读取的变量值和实际运行值不一致。
参考修正代码
初始化函数
void pb4_exti_init(void){ // 开启GPIOB、SYSCFG外设时钟,注意根据你使用的STM32系列匹配时钟位定义 RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN; RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // 配置PB4为上拉输入模式 GPIOB->MODER &= ~(3U << (4 * 2)); // 清空PB4模式配置位,设置为输入模式 GPIOB->PUPDR &= ~(3U << (4 * 2)); GPIOB->PUPDR |= (1U << (4 * 2)); // 开启PB4上拉,按键按下时引脚被拉为低电平 // 配置EXTI4映射到PB4 SYSCFG->EXTICR[1] &= ~(0xFU << 0); // 先清空EXTI4对应的4位配置域 SYSCFG->EXTICR[1] |= (1U << 0); // 写入0b0001,选择GPIOB作为EXTI4的输入源 // 配置EXTI触发规则 EXTI->IMR1 |= (1U << 4); // 取消EXTI4的中断屏蔽 EXTI->FTSR1 |= (1U << 4); // 开启下降沿触发(对应按键按下的高变低边沿) EXTI->RTSR1 &= ~(1U << 4); // 关闭上升沿触发,避免按键松开时误触发 // NVIC中断配置 NVIC_SetPriority(EXTI4_IRQn, 2); // 配置合理的中断优先级 NVIC_EnableIRQ(EXTI4_IRQn); }
中断服务函数
// 全局计数变量加volatile修饰,防止编译器优化 volatile uint32_t z = 0; void EXTI4_IRQHandler(void){ // 先校验中断来源是否为EXTI4 if(EXTI->PR1 & (1U << 4)){ // 10ms消抖:等待抖动周期过去后再次判断引脚电平 HAL_Delay(10); if((GPIOB->IDR & (1U << 4)) == 0){ // 确认按键确实按下,计数加1 z++; } // 最后必须清除EXTI4的挂起标志位,写1清零 EXTI->PR1 |= (1U << 4); } }
不建议在中断服务函数中加入过长延时,更优的实现方式是在中断中仅置位触发标志,将消抖、计数逻辑放到主循环中处理,减少中断占用时间。
内容的提问来源于stack exchange,提问作者cb_ann
相关产品推荐
相关产品推荐

