4、GPIO中断与轮询读取:中断服务函数编写、轮询模式对比、去抖动处理

好,咱们今天聊点实在的。GPIO怎么读?说白了就两种方式:轮询和中断。很多新手上来就写轮询,觉得简单。但实际项目里,这两种方式的选择,直接决定了你的系统能不能扛得住。

我个人习惯是:能用中断就别轮询。但这话也不绝对,咱们得看场景。

4.1 轮询模式:简单但“傻等”

轮询,就是CPU一直在那盯着引脚看。像这样:

while(1) {
    if(GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1) {
        // 检测到高电平
        do_something();
    }
}

你想想看,CPU大部分时间都在空转。我在一个智能家居项目里就吃过这个亏——用轮询读门磁传感器,结果主循环里其他任务全被拖慢了。说白了,轮询适合那种“你本来就要一直等”的场景,比如按键扫描。

轮询的优缺点:

  • 优点:代码简单,逻辑直观,没有中断嵌套的烦恼
  • 缺点:CPU利用率低,响应延迟不可控(取决于轮询周期)

4.2 中断模式:让CPU“随叫随到”

中断就不一样了。CPU平时该干嘛干嘛,引脚一有变化,立马跳过来处理。嗯,这里要注意:中断服务函数(ISR)要短小精悍,千万别在里面做延时或者复杂运算。

我曾经在一个项目中,ISR里调了个printf,结果整个系统卡死。为什么?因为printf本身可能触发中断,造成递归调用。血的教训啊。

标准的中断服务函数写法:

void EXTI0_IRQHandler(void) {
    if(EXTI_GetITStatus(EXTI_Line0) != RESET) {
        // 清除中断标志位(必须做!)
        EXTI_ClearITPendingBit(EXTI_Line0);
        
        // 设置一个标志位,主循环去处理
        g_button_pressed = 1;
    }
}

我的习惯:ISR里只做两件事——清标志位、设全局标志。真正的业务逻辑放到主循环里。这样既保证了响应速度,又避免了ISR过长导致的问题。

4.3 中断 vs 轮询:怎么选?

我整理了一个对比表,你一看就明白:

对比项 轮询 中断
响应延迟 取决于轮询周期,通常ms级 us级,几乎实时
CPU占用 高(一直在查) 低(有事件才处理)
代码复杂度 中(需处理中断优先级、嵌套)
适用场景 按键扫描、低速传感器 边沿触发、紧急事件、高速信号

我个人建议:如果信号变化频率低于100Hz,轮询也能凑合。但一旦超过这个数,或者你需要精确捕捉边沿,果断上中断。

4.4 去抖动处理:别让毛刺坑了你

机械按键、碰撞传感器这类东西,按下瞬间会弹跳。你想想看,一个按键按下去,实际上在几毫秒内会反复通断好几次。如果不处理,一次按键可能触发十几次中断。

我遇到过最夸张的一次——一个门磁传感器,因为没做去抖,一晚上触发了2000多次报警。业主差点报警说家里闹鬼。

去抖的常见做法有两种:

4.4.1 硬件去抖(RC滤波)

在GPIO引脚和地之间加一个电容(通常0.1uF),再串一个电阻(10kΩ)。简单粗暴,但电容值要算好,不然会把有效信号也滤掉。

4.4.2 软件去抖(延时采样)

检测到边沿后,等10-20ms再读一次。如果状态一致,才认为是有效信号。代码示例:

void EXTI0_IRQHandler(void) {
    if(EXTI_GetITStatus(EXTI_Line0) != RESET) {
        EXTI_ClearITPendingBit(EXTI_Line0);
        
        // 软件去抖:延时10ms后再次确认
        delay_ms(10);
        if(GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1) {
            g_button_pressed = 1;
        }
    }
}

注意:在ISR里直接调用delay_ms()其实不推荐,因为会阻塞其他中断。更好的做法是:在ISR里启动一个定时器,定时器到期后再去读引脚。这样既去抖又不阻塞。

4.5 知识体系总览

下面这张图,把咱们今天讲的核心逻辑串起来了:

GPIO读取方式:中断 vs 轮询 GPIO读取方式 轮询模式 中断模式 CPU持续查询 响应延迟不可控 事件触发响应 ISR需短小精悍 去抖动处理 硬件RC滤波 软件延时采样

你看,从读取方式的选择,到中断服务函数的编写,再到去抖处理,这是一条完整链路。任何一个环节出问题,数据都可能不准。

避坑指南:我曾经在一个工业项目里,因为没做去抖,传感器每触发一次就连续上报3-5次数据。后来加了10ms的软件去抖,问题立刻解决。记住:机械触点必有抖动,别偷懒。

好了,这一节的内容就到这。中断和轮询没有绝对的好坏,关键看你的系统对实时性和CPU利用率的要求。去抖处理更是不能省——你总不想被“幽灵触发”折磨吧?


公众号:蓝海资料掘金营,微信deep3321