EXTI+定时器消抖:按键中断的正确姿势

短文标题:EXTI+定时器消抖:按键中断的正确姿势

你有没有想过一个问题:按键一按,中断触发了。但按下瞬间触点弹跳,中断进了好几次------怎么办?EXTI检测边沿 + 定时器延时消抖。 这才是按键中断的标准姿势。EXTI配置三步骤

1. GPIO配置:输入模式,上拉/下拉(确保不浮空)

GPIOA->CRL &= ~(0x0F << 0);

GPIOA->CRL |= (0x08 << 0); // 上拉/下拉输入模式

GPIOA->ODR |= (1 << 0); // 使能内部上拉

2. AFIO配置:选择GPIO端口连接到EXTI线

AFIO->EXTICR0 &= ~(0x0F << 0);

AFIO->EXTICR0 |= (0x00 << 0); // PA0→EXTI0

3. EXTI配置:边沿触发 + 中断使

EXTI->FTSR |= (1 << 0); // 下降沿触发(按键按下)

EXTI->IMR |= (1 << 0); // 中断使能

NVIC_EnableIRQ(EXTI0_IRQn); // NVIC使能

按键中断 + 定时器消抖(标准流程)中断服务函数里只做一件事:启动定时器延时20ms,不清除挂起位会反复触发。

void EXTI0_IRQHandler(void)

{

if (EXTI->PR & (1 << 0)) {

EXTI->PR = (1 << 0); // 清挂起位

TIM6->ARR = 20000; // 20ms @ 1MHz

TIM6->CR1 |= TIM_CR1_CEN; // 启动定时器

}

}

定时器中断里确认按键状态:

void TIM6_IRQHandler(void)

{

if (TIM6->SR & TIM_SR_UIF) {

TIM6->SR &= ~TIM_SR_UIF;

if (GPIO_ReadInputPin(GPIOA, GPIO_PIN_0) == 0) {

// 按键真的按下了,执行动作

}

}

}

原理: 中断触发后等20ms(躲过抖动期),再读引脚电平确认。真按下了才处理,抖动被滤除。为什么不能直接在EXTI中断里延时?

void EXTI0_IRQHandler(void)

{

HAL_Delay(20); // ❌ 大忌!

}

  1. 阻塞其他中断:高优先级中断进不来
  2. 浪费CPU:20ms空转
  3. 按键响应变慢:中断处理时间太长

中断线共享(教程5.12节), EXTI0连接PA0、PB0、PC0......多个引脚共享同一中断线。需要多个中断引脚时,分散到不同编号(PA0、PA1、PA2)。如果只能同编号,在中断里读各引脚电平判断。**优先级配置建议(教程5.6节)**按键中断的抢占优先级设中低(如3~5),不要设太高(0留给紧急任务如过流保护)。优先级太高会阻塞其他关键中断。

这个故事的启示, EXTI中断不是"检测到边沿就处理按键",而是"检测到边沿启动消抖流程"。中断只做标记,定时器负责确认。别在中断里做耗时的事。

写在最后, 按键中断的正确姿势:**EXTI触发→清挂起→启动定时器→定时器确认→处理按键。**三步走,抖动去无踪。


(本文灵感源于于振南《新概念ARM32单片机》教程第5.6节、第5.12节、第6.1节。)

觉得有用?点赞、转发,让更多人学会EXTI+定时器消抖的标准流程。