【树莓派 004】 RP2040 PIO JMP指令 : jmp()条件跳转+jmp 指令的常用条件+示例解释

文章目录

    • [条件跳转 jmp()](#条件跳转 jmp())
    • [RP2040 PIO 1Hz 闪烁的代码](#RP2040 PIO 1Hz 闪烁的代码)
        • [PIO 状态机的运行机制](#PIO 状态机的运行机制)
        • [执行流程拆解(x 从 31 到 0):](#执行流程拆解(x 从 31 到 0):)
    • CG

条件跳转 jmp()

  • 汇编指令jmp(*, *) 是 RP2040 PIO 中带条件的跳转指令 ,micropython对于 jmp() 指令的描述为:将控制权转移到代码的其他部分

  • jmp(x_dec, "delay_high") 为例,可以拆成三部分理解:

部分 含义
jmp 指令核心:表示"跳转",是 PIO 中实现循环/分支的基础指令
x_dec 跳转条件:x_dec = x decrement,即"先将 x 寄存器的值减 1,再判断"
"delay_high" 跳转目标:如果条件满足,跳转到名为 delay_high 的标签处继续执行

核心执行逻辑

  • 这条指令的执行分为两个不可拆分的步骤 (PIO 指令是原子操作,要么全执行,要么不执行):
    • 第一步:x 寄存器自减 1
      不管跳转是否发生,x 的值都会先减 1(比如 x 原本是 31,执行后变成 30;x 是 1,执行后变成 0)。
    • 第二步:判断是否跳转
      检查减 1 后的 x 值:
      • 如果 x ≠ 0:满足条件,跳转到 delay_high 标签;
      • 如果 x = 0:不满足条件,不跳转,继续执行下一行指令。

jmp 指令的常用条件

条件 含义 适用场景
x_dec x 减 1 后 ≠0 则跳转 固定次数循环(最常用)
x_not_zero x ≠0 则跳转(x 不自减) 判断 x 是否为 0
pin 引脚电平为高则跳转 检测引脚电平
not pin 引脚电平为低则跳转 检测引脚电平
always 无条件跳转 无限循环

RP2040 PIO 1Hz 闪烁的代码

python 复制代码
# 1. 导入必要的模块
from machine import Pin          # 导入 Pin 类,用于控制 GPIO 引脚
import rp2                       # 导入 rp2 模块,用于操作 PIO 外设

# 2. PIO 汇编函数装饰器:定义 PIO 程序的配置
# @rp2.asm_pio:声明这是一个 PIO 汇编程序
# set_init=rp2.PIO.OUT_LOW:初始化 PIO 要控制的引脚为输出模式,初始电平为低
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def blink_1hz():
    # 注释:高电平延时的时钟周期计算:1 + 7 + 32 * (30 + 1) = 1000 个周期
    # 作用:将引脚电平设置为高(LED 亮)
    set(pins, 1)
    
    # 指令1:set(x, 31) ------ 将 x 寄存器赋值为 31
    # [6] ------ 指令延迟:执行完 set 后,空等 6 个时钟周期
    set(x, 31)                  [6]
    
    # 定义标签 delay_high,用于循环延时
    label("delay_high")
    
    # 指令2:nop() ------ 空操作(什么都不做,仅消耗 1 个时钟周期)
    # [29] ------ 指令延迟:执行完 nop 后,空等 29 个时钟周期
    nop()                       [29]
    
    # 指令3:jmp(x_dec, "delay_high") ------ x 寄存器自减 1,若结果≠0 则跳回 delay_high 标签
    jmp(x_dec, "delay_high")

    # 注释:低电平延时的时钟周期计算:和高电平完全一致,也是 1000 个周期
    # 作用:将引脚电平设置为低(LED 灭)
    set(pins, 0)
    
    # 重复高电平的延时逻辑,实现低电平 500ms 延时
    set(x, 31)                  [6]
    label("delay_low")
    nop()                       [29]
    jmp(x_dec, "delay_low")

# 3. 创建并配置 PIO 状态机(StateMachine)
# 参数说明:
# 0 ------ 状态机编号(RP2040 有 8 个状态机,编号 0-7)
# blink_1hz ------ 要运行的 PIO 汇编程序
# freq=2000 ------ 设置 PIO 时钟频率为 2000Hz(即 2KHz,每个周期 500μs)
# set_base=Pin(25) ------ 指定 PIO 控制的引脚为 25(Pico 板载 LED 引脚)
sm = rp2.StateMachine(0, blink_1hz, freq=2000, set_base=Pin(25))

# 4. 启动 PIO 状态机:一旦启动,PIO 就会循环执行 blink_1hz 程序,LED 开始闪烁
sm.active(1)
PIO 状态机的运行机制
  • sm = rp2.StateMachine(...):创建状态机时,会把 blink_1hz 汇编程序加载到 PIO 内存中;
  • sm.active(1):启动状态机后,PIO 会从程序第一行开始执行,执行到最后一行(jmp(x_dec, "delay_low"))后,会自动跳回程序开头,无限循环; 整个过程完全由 PIO 硬件执行,CPU 无需干预,即使 CPU 去执行其他代码
  • set_base 指定 PIO 中 set(pins, 1)/set(pins, 0) 指令控制的"基准引脚",如果需要控制多个引脚,还可以用 set_base + set_count 来指定引脚范围(比如控制引脚 25-27)。pins 不是一个普通变量,而是 PIO 汇编指令 set() 中的一个目标操作数(destination operand),代表"由 set_base 指定的引脚组"。
执行流程拆解(x 从 31 到 0):
  • 初始:x = 31,执行到 jmp(x_dec, "delay_high") → x 减 1 变成 30(≠0)→ 跳回 delay_high
  • 第2次:x=30 → 减1成29 → 跳转;
  • ...(重复 31 次)...
  • 第32次:x=1 → 减1成0(=0)→ 不跳转,退出循环,执行下一行 set(pins, 0)
  • 通过 x 寄存器的计数 + 跳转指令,实现了32 次循环 ,配合 nop() [29] 的延时,最终凑出 992 个时钟周期的延时(32 × 31 = 992),是实现 500ms 高电平延时的核心。

CG

相关推荐
羊群智妍9 小时前
2026 AI搜索流量密码:免费GEO监测工具,优化效果看得见
笔记·百度·微信·facebook·新浪微博
山岚的运维笔记11 小时前
SQL Server笔记 -- 第18章:Views
数据库·笔记·sql·microsoft·sqlserver
lpruoyu13 小时前
【Android第一行代码学习笔记】Android架构_四大组件_权限_持久化_通知_异步_服务
android·笔记·学习
wdfk_prog13 小时前
[Linux]学习笔记系列 -- [drivers][mmc][mmc_sdio]
linux·笔记·学习
果果燕13 小时前
今日学习笔记:双向链表、循环链表、栈
笔记·学习·链表
觉醒大王13 小时前
AI写的青基中了
人工智能·笔记·深度学习·学习·职场和发展·学习方法
明月醉窗台13 小时前
qt使用笔记六之 Qt Creator、Qt Widgets、Qt Quick 详细解析
开发语言·笔记·qt
Hello_Embed16 小时前
libmodbus 移植 STM32(USB 串口后端篇)
笔记·stm32·单片机·嵌入式·freertos·libmodbus
张祥64228890416 小时前
RTKLIB源码和理论结合分析笔记三
笔记
日更嵌入式的打工仔16 小时前
0欧电阻作用
笔记