文章目录
条件跳转 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:不满足条件,不跳转,继续执行下一行指令。
- 如果
- 第一步:x 寄存器自减 1
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
