STM32 EXTI 外部中断:按键消抖与中断优先级冲突的工程处理
按键是最常见的外部中断源,也是最容易踩坑的地方。一个看似简单的"按下按键触发一次中断",实测常常变成一次按下触发三五次,或者按下没反应、松开反而触发。本文结合实测,把机械抖动、消抖方法与中断优先级冲突一次讲清楚。
一、机械抖动:一次按下,示波器上是多次边沿
机械按键的触点在闭合瞬间会反复弹跳,持续时间一般 5~20ms。用示波器抓按键引脚波形能看到:按下瞬间电平在高低之间来回跳变多次,才稳定在低电平;松开时同样有一串抖动。如果 EXTI 配置成下降沿触发,这串抖动会产生多次中断,程序以为用户按了好几次。
硬件上可以在按键两端并联 100nF 电容做 RC 滤波,但电容只能减小抖动幅度,不能彻底消除,而且会拖慢边沿、影响响应。可靠的做法还是软件消抖,硬件滤波只作辅助。
二、EXTI 配置的三个要点
第一,GPIO 模式要配对:按键一端接地时,引脚配上拉输入(GPIO_PULLUP),按下为低电平,用下降沿触发;按键一端接 VCC 时配下拉输入,用上升沿触发。上拉下拉配反了,引脚悬空,干扰一来就误触发。
第二,边沿选择:只检测按下用下降沿,只检测松开用上升沿,需要同时检测按下和松开才用双边沿。双边沿会让一次按键产生两次中断,必须在回调里读引脚电平区分。
第三,别忘了开 SYSCFG 时钟并配置 EXTI 线映射。PA0 对应 EXTI0,PB5 对应 EXTI5,同一个 EXTI 线号只能映射一个引脚,PA5 和 PB5 不能同时用 EXTI5,这是新手常犯的错误。
三、中断里做消抖是错误做法
最常见的错误写法是在 EXTI 回调里加 HAL_Delay(20) 再读电平确认。中断里延时 20ms,期间所有同级和低优先级中断都被堵住:串口接收会丢字节,定时器节拍会漂移,系统响应明显变差。更糟的是,如果按键一直按住不放,延时判断还会反复进入。
正确思路是:中断里只做最轻的事——记录时间戳并退出;真正的确认交给主循环或定时器。
四、推荐做法:时间戳 + 定时器二次确认
#define DEBOUNCE_MS 20
static volatile uint32_t key_press_tick = 0;
static volatile uint8_t key_event = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == KEY_Pin)
{
/* 中断里只记录时间戳,不做延时、不做业务 */
key_press_tick = HAL_GetTick();
key_event = 1;
}
}
/* 主循环或 10ms 定时器里确认 */
void Key_Process(void)
{
if (key_event)
{
if (HAL_GetTick() - key_press_tick >= DEBOUNCE_MS)
{
if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET)
{
/* 20ms 后仍为低电平,确认为有效按下 */
Key_Action();
}
key_event = 0;
}
}
}
关键点:抖动期间每次边沿都会刷新时间戳,只有电平稳定 20ms 以上才算一次有效按下。多次抖动只会推迟确认时间,不会产生多次事件。20ms 这个值按实测取:普通轻触按键取 10~20ms,行程大的按键取 20~30ms,取太小消不干净,取太大手感迟滞。
五、优先级冲突:按键中断别抢串口的道
NVIC 分组一旦定下来,所有中断的抢占优先级就按这个分组分配。按键中断通常配成较低的抢占优先级,比如抢占 2、子优先级 0;串口接收、定时器节拍这类实时性要求高的配抢占 0 或 1。反过来配,按键抖动期间频繁进中断,会把串口接收中断顶掉,表现就是按键一按,串口就丢数据。
还有一个容易被忽略的点:同一个 EXTI 线组共享中断向量,EXTI9_5_IRQHandler 管 5~9 号线,EXTI15_10_IRQHandler 管 10~15 号线。回调里一定要用 HAL_GPIO_EXTI_IRQHandler(GPIO_Pin) 分发到具体引脚,否则一个引脚的中断会误触发另一个引脚的处理。
六、实测数据与检查清单
实测一块 STM32F103 开发板:轻触按键抖动时间 8~15ms,消抖取 20ms 后,连续按 100 次,误触发 0 次、漏触发 0 次;中断回调执行时间小于 2us,对串口 115200 波特率接收无影响。上线前按这张清单自查:引脚上下拉与边沿方向是否配对;EXTI 线号有没有和其他引脚冲突;回调里有没有延时和耗时操作;消抖时间是否按实测抖动时间留出余量;按键中断优先级是否低于串口和定时器。
结语:外部中断的坑从来不在中断本身,而在抖动和优先级这两处。记住两条原则——中断里只做最轻的事,消抖靠时间戳不在中断里等;优先级按实时性排,按键永远排在串口和定时器后面。这两条做到了,按键中断就稳了。
- 点赞
- 收藏
- 关注作者
评论(0)