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

MicroPython RP2040 PIO中断仅在状态机0触发及替代方案咨询

问题分析与解决方案

你的代码仅在状态机0下能触发中断的核心原因是:PIO汇编代码里固定用了irq(0),这会触发全局中断号0,而其他状态机绑定的中断处理函数,并没有接收到PIO触发的对应信号——本质是全局中断号与状态机的绑定关系没对应上。

下面提供两种可行的解决方案:

方案1:触发状态机自身关联的中断(推荐)

在PIO汇编里用irq(rel(0))替换irq(0),rel(0)代表触发当前状态机对应的相对中断线,不管你用0-3中的哪个状态机,都会触发该状态机绑定的中断处理函数,无需固定全局中断号。

修改后的完整代码:

from machine import Pin
from time import sleep
import rp2

class PioLoader():
    
    @rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
    def blink():
        wrap_target()
        set(pins, 1)   [31]
        nop()          [31]
        nop()          [31]
        nop()          [31]
        nop()          [31]
        set(pins, 0)   [31]
        nop()          [31]
        nop()          [31]
        nop()          [31]
        nop()          [31]
        irq(rel(0))  # 改为触发当前状态机的相对中断
        wrap()

    def irqHandler(self, sm):  # 修正:添加self参数,直接接收触发中断的状态机实例
        sm.active(0)
        print(f"状态机{sm.id()}触发中断,已停止") 
     
    def __init__(self): 
        pass

    def test(self, sm_id=0):
        # 支持传入任意合法状态机ID(0-3)
        sm = rp2.StateMachine(sm_id, self.blink, freq=2000, set_base=Pin(25))
        sm.irq(lambda sm: self.irqHandler(sm))  # 通过lambda传递self
        print(f"启动状态机{sm.id()}")
        sm.active(1)
        sleep(2) 
        sm.active(0)    

# 测试状态机1
loader = PioLoader()
loader.test(sm_id=1)

方案2:绑定全局中断号到指定状态机

如果需要使用全局中断号,可以在创建状态机时,指定监听的全局中断触发源,同时让PIO代码触发对应编号的全局中断。比如用状态机1触发全局中断1:

  1. PIO汇编中改为irq(1)
  2. 创建状态机时绑定对应中断:
sm = rp2.StateMachine(1, self.blink, freq=2000, set_base=Pin(25))
sm.irq(self.irqHandler, trigger=rp2.PIO.IRQ_SM1)  # 指定监听状态机1的全局中断

这种方式适合多状态机触发不同全局中断的场景,但灵活性不如方案1。

额外修正:中断处理函数的问题

你原代码里的irqHandler有两个明显问题:

  • 缺少self参数,作为类方法无法访问实例上下文
  • 使用self.sm但sm是test方法的局部变量,会触发AttributeError
    修改后的处理函数直接接收触发中断的状态机实例,避免了变量作用域错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 06:20:28