关于树莓派Pico里的PIO(Programmed I/O)编程,前面写过3篇文章:
PIO里的汇编语句只有9条,但能组合出很多强大的功能,为了研究out指令的效果,我用了6个LED小灯,分别接上了GP16~GP21引脚。 在《Raspberry Pi Pico C/C++ SDK》这本书里,对于OUT指令有比较详细的描述,如下图:
Delay/side-set共用5个二进制位,与其它指令都一样。 Destination可以是:
- PINS
- X
- Y
- NULL(黑洞)
- PINDIRS(暂时不介绍)
- PC(Programm Counter)
- ISR
- EXEC(暂时不介绍)
Bit count取值范围为1到32,占5个二进制位,32在内部编码为0b00000。
OUT指令的意思是:从OSR寄存器里移出 Bit count 个二进制位的数据,把这些位写进 Destination 里。
例如:out(pins, 6) 意思就是从OSR里取出6个二进制位,把它们写入pins,如果out_base的起始引脚为GP16,那么这6个二进制位将分别写入GP16~GP21,1就是高电位,0就是低电位。因为OSR是32位的寄存器,这时OSR里还剩26个位的数据未取出,可以用out指令继续取出。
移位的方向由out_shiftdir指定,默认是从左侧移出(高位),如果是SHIFT_RIGHT,则表示从右侧移出,我画了一个示意图: 现在可以写出程序了:
import machine
import utime
import rp2
@rp2.asm_pio(out_init=(rp2.PIO.OUT_LOW, rp2.PIO.OUT_LOW, rp2.PIO.OUT_LOW,
rp2.PIO.OUT_LOW, rp2.PIO.OUT_LOW, rp2.PIO.OUT_LOW),
out_shiftdir=rp2.PIO.SHIFT_RIGHT)
def pio_out():
wrap_target()
pull()
out(pins, 6)
wrap()
sm = rp2.StateMachine(0, pio_out, out_base=machine.Pin(16))
sm.active(1)
cmd = 0b011010 # 十进制:23
while True:
sm.put(cmd)
cmd = int(input("输入一个整数:"))
utime.sleep(0.01)
状态机执行pull(),这里没有noblock参数,状态机会一直等待FIFO队列里的数据,当sm.put(0b011010)后,FIFO里的数据立刻被取出放到OSR里,这里的数据是32位的二进制,out(pins, 6) 设置GP16~GP21的电位,这样达到了同时设置6个引脚电位的目的。
现在可以在程序里输入一个整数(不要超过63),可以用LED灯的亮暗来表示其二进制。
也可以用PIO给七段数码管的引脚设置电位,虽然有点大材小用,但对于研究pioasm还是有帮助的。
倒计时显示9到0的代码如下:
import machine
import utime
import rp2
@rp2.asm_pio(out_init=(rp2.PIO.OUT_LOW, rp2.PIO.OUT_LOW, rp2.PIO.OUT_LOW,
rp2.PIO.OUT_LOW, rp2.PIO.OUT_LOW, rp2.PIO.OUT_LOW,
rp2.PIO.OUT_LOW),
out_shiftdir=rp2.PIO.SHIFT_RIGHT)
def pio_out():
wrap_target()
pull()
out(pins, 7)
wrap()
sm = rp2.StateMachine(0, pio_out, out_base=machine.Pin(14))
sm.active(1)
# 0到9的段选码
mask_digits = [0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f]
for code in reversed(mask_digits):
sm.put(~code)
utime.sleep(1)
sm.put(~0x0) #全灭
这里的起始引脚是GP14,没有连接小数点的LED,我的七段数码管是共阳极的,所以高电位1不亮,低电位0才亮。
每次pull()有点麻烦,可以设置autopull,这样遇到out()指令时自动从OSR里取数,配合使用的参数是pull_thresh,明确一次取出几个二进制位,我猜thresh是threshhold的缩写。
@rp2.asm_pio(out_init=(rp2.PIO.OUT_LOW, rp2.PIO.OUT_LOW, rp2.PIO.OUT_LOW,
rp2.PIO.OUT_LOW, rp2.PIO.OUT_LOW, rp2.PIO.OUT_LOW,
rp2.PIO.OUT_LOW),
autopull=True, pull_thresh=7,
out_shiftdir=rp2.PIO.SHIFT_RIGHT)
def pio_out():
out(pins, 7)
小结一下: 1)sm.put()把32位整数放入FIFO 2)pull()等FIFO里有数据的时候,取出放到OSR里 3)pull(noblock)不阻塞,如果FIFO里没数据,也继续执行 4)out(pins, 6)从OSR里移出6位二进制数,移位的方向由 out_shiftdir 定义,起始引脚由out_base定义,剩下还有26位二进制数据
|