Nuvoton M487KM GPIO中断标志无法清除,按键重复触发中断
针对你在Nuvoton M487KM开发板上遇到的按键控制LED功能中,短按按键终端多次打印触发信息、长按仅触发一次的问题,结合现象和你尝试过的方案,以下是具体的排查方向和解决方法:
核心现象分析
短按触发多次、长按仅触发一次的表现,本质是按键机械抖动导致的电平跳变:短按时按键触点的快速通断会产生多次边沿变化,触发多轮中断;长按过程中触点稳定接触,电平无跳变,因此仅触发一次中断。你之前尝试的清中断标志、切换触发边沿、临时禁用中断未解决问题,大概率是没有针对抖动的核心原因处理。
具体排查与修复方案
1. 确认中断标志清除的正确性
Nuvoton M487的GPIO中断标志必须通过GPIO_CLR_INT_FLAG()函数明确清除,且建议在中断服务函数最开头执行该操作,避免未清除的标志被重复检测:
void GPIOx_IRQHandler(void) { // 优先清除中断标志,避免重复触发 if (GPIO_GET_INT_FLAG(GPIO_PORT, GPIO_PIN)) { GPIO_CLR_INT_FLAG(GPIO_PORT, GPIO_PIN); // 后续按键逻辑处理 } }
注意:请勿仅依赖硬件自动清除标志,必须调用官方提供的清除函数。
2. 添加按键消抖机制
针对机械抖动,推荐两种消抖方式:
方式1:软件延时消抖(简单但不推荐在中断中长时间延时)
在清除中断标志后,短延时再检测按键电平,确认稳定后再执行逻辑:
void GPIOx_IRQHandler(void) { if (GPIO_GET_INT_FLAG(GPIO_PORT, GPIO_PIN)) { GPIO_CLR_INT_FLAG(GPIO_PORT, GPIO_PIN); // 5ms延时消抖(根据按键特性调整时长) CLK_SysTickDelay(5000); // 再次检测按键电平,确认有效触发 if (!(GPIO_GET_IN_DATA(GPIO_PORT) & GPIO_PIN)) // 假设按键为低电平触发 { GPIO_TOGGLE(LED_PORT, LED_PIN); printf("按键触发\r\n"); } } }
方式2:定时器消抖(更优,避免阻塞中断)
通过定时器实现非阻塞消抖,中断触发后先禁用按键中断,启动定时器;定时器超时后再检测按键电平,确认有效后执行逻辑并重新启用按键中断:
volatile uint8_t g_key_valid = 0; // 按键中断服务函数 void GPIOx_IRQHandler(void) { if (GPIO_GET_INT_FLAG(GPIO_PORT, GPIO_PIN)) { GPIO_CLR_INT_FLAG(GPIO_PORT, GPIO_PIN); GPIO_DISABLE_INT(GPIO_PORT, GPIO_PIN); // 临时禁用按键中断 TIMER_Start(TIMER0); // 启动5ms定时器 } } // 定时器中断服务函数 void TIMER0_IRQHandler(void) { if (TIMER_GetIntFlag(TIMER0)) { TIMER_ClearIntFlag(TIMER0); TIMER_Stop(TIMER0); // 检测按键电平是否稳定 if (!(GPIO_GET_IN_DATA(GPIO_PORT) & GPIO_PIN)) { GPIO_TOGGLE(LED_PORT, LED_PIN); printf("按键触发\r\n"); } GPIO_ENABLE_INT(GPIO_PORT, GPIO_PIN); // 重新启用按键中断 } }
提前需配置定时器为5ms定时(根据按键抖动特性调整),并开启定时器中断。
3. 检查GPIO引脚配置
确认按键引脚的上下拉电阻是否正确配置:如果按键为低电平触发,需配置引脚为上拉输入;高电平触发则配置为下拉输入,避免引脚悬空时的杂散电平导致误触发。配置示例:
GPIO_SetMode(GPIO_PORT, GPIO_PIN, GPIO_MODE_INPUT); GPIO_EnablePullUp(GPIO_PORT, GPIO_PIN, GPIO_PULLUP_EN);
4. 排查中断触发边沿配置
确保未误设为双边沿触发,否则按键按下和松开时都会触发中断,导致多次打印。配置单边沿触发的示例:
// 配置下降沿触发(按键按下时电平从高到低) GPIO_EnableInt(GPIO_PORT, GPIO_PIN, GPIO_INT_FALLING);
总结
你的问题核心是按键机械抖动导致的重复中断触发,结合上述方案调整后即可解决。优先推荐定时器消抖方案,既能避免中断阻塞,又能有效过滤抖动干扰。
内容的提问来源于stack exchange,提问作者Harshal Chavan

