【树莓派 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

相关推荐
狐572 小时前
2026-01-19-LeetCode刷题笔记-1292-元素和小于等于阈值的正方形的最大边长
笔记·算法·leetcode
张祥6422889042 小时前
误差理论与测量平差基础笔记六
笔记·算法·概率论
zpedu2 小时前
软考想一次过,有一个学习衡量标准吗?
人工智能·笔记
孞㐑¥4 小时前
算法—滑动窗口
开发语言·c++·经验分享·笔记·算法
历程里程碑4 小时前
Linux 3 指令(3):进阶指令:文件查看、资源管理、搜索打包压缩详解
linux·运维·服务器·c语言·数据结构·笔记·算法
智者知已应修善业5 小时前
【输出一个N*N的01矩阵,表示最后的汉字点阵图】2024-10-22
c语言·数据结构·c++·经验分享·笔记·算法·矩阵
速冻鱼Kiel5 小时前
Lyra的相机系统
笔记·ue5·游戏引擎·虚幻
鄭郑6 小时前
【Playwright 学习笔记 05】Xpath选择
笔记·学习
wdfk_prog6 小时前
[Linux]学习笔记系列 -- [drivers][base]syscore
linux·笔记·学习