STM32G0矩阵键盘中断消抖问题及SSD显示异常求助
问题:STM32G0矩阵键盘EXTI中断按键抖动与显示异常排查
基于STM32G0芯片,为4x3矩阵键盘实现了EXTI4_15_IRQHandler中断处理函数,搭配4位SSD数码管。当前存在以下问题:
- 按下按键时出现抖动问题,所有SSD数码管显示相同数字,但调试模式下一切正常
- 添加延时后问题仍未解决
- 移除中断内延时后,仅最后编写的Row3按键功能正常,其他行按键触发时所有SSD显示相同数字
原代码
中断处理函数
/* Interrupt Handler */ void EXTI4_15_IRQHandler(void){ /* keypad press from C1 */ KeypadAllRows_RESET(); GPIOB->ODR |= (1U << 0); //Row4 if((GPIOB->IDR & (1U << 5)) == (1U << 5)) //2 KeyPress = 0; KeypadAllRows_RESET(); GPIOA->ODR |= (1U << 8); //Row1 if((GPIOB->IDR & (1U << 4)) == (1U << 4)) //1 KeyPress = 1; if((GPIOB->IDR & (1U << 5)) == (1U << 5)) //2 KeyPress = 2; if((GPIOB->IDR & (1U << 9)) == (1U << 9)) //3 KeyPress = 3; KeypadAllRows_RESET(); GPIOB->ODR |= (1U << 8); //Row2 if((GPIOB->IDR & (1U << 4)) == (1U << 4)) //4 KeyPress = 4; if((GPIOB->IDR & (1U << 5)) == (1U << 5)) //5 KeyPress = 5; if((GPIOB->IDR & (1U << 9)) == (1U << 9)) //6 KeyPress = 6; KeypadAllRows_RESET(); GPIOB->ODR |= (1U << 2); //Row3 if((GPIOB->IDR & (1U << 4)) == (1U << 4)) //7 KeyPress = 7; if((GPIOB->IDR & (1U << 5)) == (1U << 5)) //8 KeyPress = 8; if((GPIOB->IDR & (1U << 9)) == (1U << 9)) //9 KeyPress = 9; SSD_Digit1 = SSD_Digit2; SSD_Digit2 = SSD_Digit3; SSD_Digit3 = SSD_Digit4; SSD_Digit4 = KeyPress; EXTI->RPR1 |= (1U << 4); EXTI->RPR1 |= (1U << 5); EXTI->RPR1 |= (1U << 9); KeypadAllRows_SET(); }
主循环代码
while(1) { SSD_Close(); GPIOA->ODR |= (1U << 7); //D4 SSD_SET(SSD_Digit4); delay(200); SSD_Close(); GPIOB->ODR |= (1U << 7); //D3 SSD_SET(SSD_Digit3); delay(200); SSD_Close(); GPIOA->ODR |= (1U << 15); //D2 SSD_SET(SSD_Digit2); delay(200); SSD_Close(); GPIOA->ODR |= (1U << 9); //D1 SSD_SET(SSD_Digit1); delay(200); }
问题根源分析
- 中断扫描逻辑缺陷:中断触发后,未在找到按键时立即停止扫描,后续行的电平检测会覆盖
KeyPress值,最终只有最后一行的设置生效。 - 按键抖动未处理:调试模式下执行速度慢,抖动被自然过滤,但实际运行时抖动会导致电平误判或多次触发中断。
- 数码管扫描延时过长:主循环中200ms的延时会严重拖慢中断响应,导致按键事件处理不及时。
- EXTI标志位清除不规范:直接操作寄存器时容易出现遗漏,增加中断重复触发的概率。
修复方案
1. 优化中断内按键扫描逻辑
找到按键后立即终止扫描,避免值被覆盖:
void EXTI4_15_IRQHandler(void){ KeyPress = -1; // 初始化无效值 KeypadAllRows_RESET(); GPIOB->ODR |= (1U << 0); //Row4 if((GPIOB->IDR & (1U << 5)) == (1U << 5)) { //2 KeyPress = 0; goto KEY_SCAN_FINISH; } KeypadAllRows_RESET(); GPIOA->ODR |= (1U << 8); //Row1 if((GPIOB->IDR & (1U << 4)) == (1U << 4)) { //1 KeyPress = 1; goto KEY_SCAN_FINISH; } if((GPIOB->IDR & (1U << 5)) == (1U << 5)) { //2 KeyPress = 2; goto KEY_SCAN_FINISH; } if((GPIOB->IDR & (1U << 9)) == (1U << 9)) { //3 KeyPress = 3; goto KEY_SCAN_FINISH; } KeypadAllRows_RESET(); GPIOB->ODR |= (1U << 8); //Row2 if((GPIOB->IDR & (1U << 4)) == (1U << 4)) { //4 KeyPress = 4; goto KEY_SCAN_FINISH; } if((GPIOB->IDR & (1U << 5)) == (1U << 5)) { //5 KeyPress = 5; goto KEY_SCAN_FINISH; } if((GPIOB->IDR & (1U << 9)) == (1U << 9)) { //6 KeyPress = 6; goto KEY_SCAN_FINISH; } KeypadAllRows_RESET(); GPIOB->ODR |= (1U << 2); //Row3 if((GPIOB->IDR & (1U << 4)) == (1U << 4)) { //7 KeyPress = 7; goto KEY_SCAN_FINISH; } if((GPIOB->IDR & (1U << 5)) == (1U << 5)) { //8 KeyPress = 8; goto KEY_SCAN_FINISH; } if((GPIOB->IDR & (1U << 9)) == (1U << 9)) { //9 KeyPress = 9; goto KEY_SCAN_FINISH; } KEY_SCAN_FINISH: if(KeyPress != -1) { // 仅有效按键更新数码管 SSD_Digit1 = SSD_Digit2; SSD_Digit2 = SSD_Digit3; SSD_Digit3 = SSD_Digit4; SSD_Digit4 = KeyPress; } // 规范清除EXTI中断标志 EXTI->RPR1 |= (EXTI_RPR1_RP4 | EXTI_RPR1_RP5 | EXTI_RPR1_RP9); KeypadAllRows_SET(); }
2. 添加软件消抖逻辑
检测到按键后延时10ms再次确认,避免抖动误判:
// 以Row4的按键检测为例 if((GPIOB->IDR & (1U << 5)) == (1U << 5)) { delay_ms(10); // 使用短延时函数,避免阻塞中断过久 if((GPIOB->IDR & (1U << 5)) == (1U << 5)) { KeyPress = 0; goto KEY_SCAN_FINISH; } }
更优方案是使用定时器消抖:第一次中断触发后启动定时器,定时器中断时再扫描按键,彻底避免中断阻塞。
3. 优化数码管扫描延时
缩短主循环延时至2ms,利用视觉暂留实现动态扫描,同时提升中断响应速度:
while(1) { SSD_Close(); GPIOA->ODR |= (1U << 7); //D4 SSD_SET(SSD_Digit4); delay_ms(2); SSD_Close(); GPIOB->ODR |= (1U << 7); //D3 SSD_SET(SSD_Digit3); delay_ms(2); SSD_Close(); GPIOA->ODR |= (1U << 15); //D2 SSD_SET(SSD_Digit2); delay_ms(2); SSD_Close(); GPIOA->ODR |= (1U << 9); //D1 SSD_SET(SSD_Digit1); delay_ms(2); }
4. 规范GPIO操作
使用STM32 HAL库函数操作GPIO,确保原子性和可读性:
// 替换直接操作ODR的代码 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // Row4
内容的提问来源于stack exchange,提问作者AnatolianPerseus
相关产品推荐
相关产品推荐

