Pico PIO 中断开发:原理、时序与实战全解析

示例代码如下:

# Python env   : MicroPython v1.23.0
# -*- coding: utf-8 -*-        
# @Time    : 2024/7/28 上午10:32   
# @Author  : 李清水            
# @File    : main.py       
# @Description : PIO类实验,在PIO程序中使用irq指令触发中断,并打印中断标志位

# ======================================== 导入相关模块 ========================================

# 导入时间相关的模块
import time
# 导入RP2040相关的模块
import rp2

# ======================================== 全局变量 ============================================

# ======================================== 功能函数 ============================================

# irq_test() 函数使用 rp2.asm_pio() 装饰器定义了一个 PIO(Programmable I/O)程序
@rp2.asm_pio()
def irq_test() -> None:
    """
​    定义一个用于测试中断的 PIO 程序。

​    Args:
​        None

​    Returns:
​        None

​    Description:
​        该 PIO 程序通过执行 nop 指令和触发中断来测试中断功能。
​        程序会依次触发状态机 0 和状态机 1 的中断,并在每次中断后插入延迟。
​    """
​    ​# 标记了程序的开始位置
    wrap_target()
    # 4 个 nop() 无操作指令,每个指令都有 31 个时钟周期的延迟
    nop()          [31]
    nop()          [31]
    nop()          [31]
    nop()          [31]
    # 触发状态机 0 的中断
    irq(0)
    # 4 个 nop() 无操作指令,每个指令都有 31 个时钟周期的延迟
    nop()          [31]
    nop()          [31]
    nop()          [31]
    nop()          [31]
    # 触发状态机 1 的中断
    irq(1)
    # 标记了程序的结束位置,并返回到开始位置
    wrap()

# 转为固定位数的二进制数据
def to_bin(value: int, num: int) -> str:
    """
​    将一个十进制数转为固定位数的二进制数。

​    Args:
​        value (int): 需要转换的十进制数。
​        num (int): 二进制数的固定位数。

​    Returns:
​        str: 转换后的二进制字符串。
​    """
​    ​# 初始化一个空字符串 bin_chars 来存储最终的二进制数据
    bin_chars = ""
    # 将原始的十进制数 value 保存到一个临时变量 temp 中
    temp = value
    # 进行 num 次循环
    for i in range(num):
        # 获取 temp 除以 2 的余数,即二进制数的最后一位,转换为字符串并赋值给 bin_char
        bin_char = bin(temp % 2)[-1]
        # 将 temp 除以 2 (整除),得到新的值赋值给 temp
        temp = temp // 2
        # 将 bin_char 拼接到 bin_chars 的开头,建立正确的二进制位顺序
        bin_chars = bin_char + bin_chars
    # 返回转换后的二进制字符串 bin_chars,并将其转换为大写形式
    return bin_chars.upper()

# ======================================== 自定义类 ============================================

# ======================================== 初始化配置 ==========================================

# 上电延时3s
time.sleep(3)
# 打印调试信息
print("FreakStudio: PIO IRQ Test")

# 设置了一个 lambda 函数作为 PIO 0 的中断处理程序。当发生 IRQ 时,该函数会打印中断标志位和中断标志位对应的二进制数(12位宽)
rp2.PIO(0).irq(lambda pio: print(pio.irq().flags(),to_bin(pio.irq().flags(),12)))
# 创建了一个状态机,将 irq_test() 函数作为程序,并设置频率为 系统时钟/2000 Hz
sm = rp2.StateMachine(0, irq_test, freq=2000)

# ========================================  主程序  ===========================================

# 启动状态机
sm.active(1)
# 等待 5 秒
time.sleep(5)
# 停止状态机
sm.active(0)

这里,在 PIO0 的中断处理程序部分:

# 设置了一个 lambda 函数作为 PIO 0 的中断处理程序。当发生 IRQ 时,该函数会打印中断标志位和中断标志位对应的二进制数(12位宽)
rp2.PIO(0).irq(lambda pio: print(pio.irq().flags(),to_bin(pio.irq().flags(),12)))

在这里,pio 是 lambda 函数的参数,表示传入的 PIO 实例,其后为表达式部分:

  • pio.irq() 获取当前 PIO 的中断对象,.flags() 是中断对象的一个方法,返回当前的中断标志位;
  • to_bin() 是一个自定义函数,用于将整数转换为固定位数的二进制字符串

即每次中断都会打印中断标志位的十进制值和中断标志位的 12 位二进制字符串。

将代码烧录到 Pico 中,远程连接中断,数据输出如下:

dfaae9eb-62b6-4d63-bcef-0c9e2fcc945f.png

mmexport1781002698218.gif

我们来看一下 PIO0 的中断掩码输出寄存器:

5122832a-497d-4e2e-a5f1-b8cb44ee3e0d.png

可以看到:

  • 512 对应二进制数据为 0b001000000000,表示 SM1 产生中断
  • 256 对应二进制数据为 0b000100000000,表示 SM0 产生中断
posted @ 2026-09-01 15:54  FreakStudio  阅读(7)  评论(0)    收藏  举报