You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派Pico中断服务程序(ISR)陷入无限循环问题排查

树莓派Pico水位控制ISR无限循环问题排查与解决

核心问题分析

你的问题大概率由两个关键因素导致:

  1. 金属探针的接触弹跳(抖动):裸金属探针接触/离开水时,尤其是水位波动(比如暴雨),会产生多次快速电平跳变,反复触发中断,看起来像无限循环。
  2. 中断处理逻辑的竞态与不规范操作:ISR内的标志位修改、中断禁用范围不当,可能导致中断反复触发或逻辑冲突。

具体解决方法

一、硬件层面:解决探针抖动

给探针输入引脚添加RC滤波电路:在引脚与GND之间并联100nF电容,同时串联1kΩ电阻,平滑电平跳变,从源头减少误触发。如果条件允许,直接换用带防抖模块的水位传感器更省心。

二、软件层面:优化中断处理

1. 给ISR添加软件防抖

注意:ISR内不能用time.sleep()这类阻塞式延时,要用非阻塞的时间差判断实现防抖,示例代码如下:

from machine import Pin
import utime

# 全局标志位与水泵引脚
flag_l = 0
flag_h = 0
pump = Pin(2, Pin.OUT, value=0)

# 防抖装饰器,过滤10ms内的重复触发
def debounce(func):
    last_trigger = 0
    def wrapper(pin):
        nonlocal last_trigger
        now = utime.ticks_ms()
        if utime.ticks_diff(now, last_trigger) > 10:
            func(pin)
            last_trigger = now
    return wrapper

@debounce
def lf_interrupt(pin):
    global flag_l, flag_h
    # 临时禁用当前中断,避免处理中重复触发
    pin.irq(handler=None)
    # 确认电平状态(下降沿=水离开低位探针)
    if pin.value() == 0 and flag_h == 1:
        pump.value(0)
        flag_l = 0
        flag_h = 0
    # 恢复中断
    pin.irq(handler=lf_interrupt, trigger=Pin.IRQ_FALLING)

@debounce
def hr_interrupt(pin):
    global flag_l, flag_h
    pin.irq(handler=None)
    # 确认电平状态(上升沿=水接触高位探针)
    if pin.value() == 1:
        flag_h = 1
        flag_l = 0
        pump.value(1)
    pin.irq(handler=hr_interrupt, trigger=Pin.IRQ_RISING)

# 初始化引脚
lf_pin = Pin(18, Pin.IN, Pin.PULL_DOWN)
hr_pin = Pin(21, Pin.IN, Pin.PULL_DOWN)
lf_pin.irq(handler=lf_interrupt, trigger=Pin.IRQ_FALLING)
hr_pin.irq(handler=hr_interrupt, trigger=Pin.IRQ_RISING)

# 主循环(仅做兜底检查,逻辑主要靠中断)
while True:
    utime.sleep(0.5)

2. 避免中断竞态:处理时屏蔽相关中断

如果高低位中断可能同时触发,处理其中一个时可以临时屏蔽另一个,防止标志位被同时修改:

@debounce
def hr_interrupt(pin):
    global flag_l, flag_h
    # 临时屏蔽两个中断
    pin.irq(handler=None)
    lf_pin.irq(handler=None)
    
    if pin.value() == 1:
        flag_h = 1
        flag_l = 0
        pump.value(1)
    
    # 恢复所有中断
    pin.irq(handler=hr_interrupt, trigger=Pin.IRQ_RISING)
    lf_pin.irq(handler=lf_interrupt, trigger=Pin.IRQ_FALLING)

3. 简化ISR逻辑:复杂操作移到主循环

ISR要尽量简短,只做标志位更新和必要的硬件控制,把水泵启停的判断逻辑移到主循环,减少ISR的执行时间:

# 修改后的主循环
while True:
    if flag_h == 1 and flag_l == 0:
        pump.value(1)
    elif flag_h == 0:
        pump.value(0)
    utime.sleep(0.1)

三、调试技巧

  • 在ISR内添加打印时,带上时间戳(utime.ticks_ms()),看是否是短时间内多次触发同一中断,确认抖动问题。
  • 用万用表或逻辑分析仪观察探针引脚的电平变化,直观看到抖动的次数和持续时间,调整防抖的时间阈值。

内容的提问来源于stack exchange,提问作者Robavh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 08:20:08