【雕爷学编程】MicroPython手册之 RP2040 特定端口库 rp2.PIO.state_machine

在这里插入图片描述

MicroPython是为了在嵌入式系统中运行Python 3编程语言而设计的轻量级版本解释器。与常规Python相比,MicroPython解释器体积小(仅100KB左右),通过编译成二进制Executable文件运行,执行效率较高。它使用了轻量级的垃圾回收机制并移除了大部分Python标准库,以适应资源限制的微控制器。

MicroPython主要特点包括:
1、语法和功能与标准Python兼容,易学易用。支持Python大多数核心语法。
2、对硬件直接访问和控制,像Arduino一样控制GPIO、I2C、SPI等。
3、强大的模块系统,提供文件系统、网络、图形界面等功能。
4、支持交叉编译生成高效的原生代码,速度比解释器快10-100倍。
5、代码量少,内存占用小,适合运行在MCU和内存小的开发板上。
6、开源许可,免费使用。Shell交互环境为开发测试提供便利。
7、内置I/O驱动支持大量微控制器平台,如ESP8266、ESP32、STM32、micro:bit、掌控板和PyBoard等。有活跃的社区。

MicroPython的应用场景包括:
1、为嵌入式产品快速构建原型和用户交互。
2、制作一些小型的可 programmable 硬件项目。
3、作为教育工具,帮助初学者学习Python和物联网编程。
4、构建智能设备固件,实现高级控制和云连接。
5、各种微控制器应用如物联网、嵌入式智能、机器人等。

使用MicroPython需要注意:
1、内存和Flash空间有限。
2、解释执行效率不如C语言。
3、部分库函数与标准版有差异。
4、针对平台优化语法,订正与标准Python的差异。
5、合理使用内存资源,避免频繁分配大内存块。
6、利用原生代码提升速度关键部位的性能。
7、适当使用抽象来封装底层硬件操作。

总体来说,MicroPython让Python进入了微控制器领域,是一项重要的创新,既降低了编程门槛,又提供了良好的硬件控制能力。非常适合各类物联网和智能硬件的开发。
在这里插入图片描述

RP2040 是一款由树莓派公司设计的 32 位双核 ARM Cortex-M0+ 微控制器芯片,于 2021 年 1 月发布,作为树莓派 Pico 开发板的核心部件。RP2040 的特点是高性能、低成本、小封装、灵活的 I/O 和独特的可编程 I/O(PIO)子系统。RP2040 还支持 MicroPython、C/C++ 和 TensorFlow Lite 等编程语言和框架,适用于各种创意项目和机器学习应用。

MicroPython 的特定于 RP2040 的库包括以下模块:

rp2:包含特定于 RP2040 的函数和类,如 PIO 相关功能、Flash 类和 StateMachine 类。
machine:包含通用的硬件控制功能,如 Pin、Timer、UART、PWM、ADC 等。
utime:包含时间相关的函数,如 sleep、ticks_ms、ticks_diff 等。
uos:包含操作系统相关的函数,如 uname、mount、remove 等。

这些模块使得 MicroPython 可以充分利用 RP2040 的硬件特性,实现各种创意项目。

在这里插入图片描述

MicroPython的rp2.PIO.state_machine()是一个方法,用于获取该PIO实例的状态机对象。

它的主要特点有:

它接受一个或多个参数,第一个参数是id,表示要获取的状态机的编号,后面的参数是可选的,用于初始化状态机对象。
id是一个整数,表示要获取的状态机的编号。在RP2040上,每个PIO实例有四个状态机,编号为0到3。
后面的可选参数与rp2.StateMachine.init()方法的参数相同,用于配置状态机对象运行的程序和相关参数。
它返回一个rp2.StateMachine对象,表示该PIO实例的状态机对象。

它的应用场景有:

当需要使用PIO实现一些特殊的协议或功能时,可以使用rp2.PIO.state_machine()方法来获取和初始化状态机对象。例如,如果需要使用PIO实现一个UART协议,可以使用rp2.asm_pio()函数来编写一个UART发送功能的程序,并使用rp2.PIO.state_machine()方法来获取和初始化一个状态机对象,并将其关联到该程序。
当需要动态生成或加载PIO程序时,可以使用rp2.PIO.state_machine()方法来获取和初始化状态机对象。例如,如果需要根据用户的输入或其他变量来生成或加载不同的PIO程序,可以使用rp2.PIOProgram类来构造一个PIO程序对象,并使用rp2.PIO.state_machine()方法来获取和初始化一个状态机对象,并将其关联到该程序。
当需要调试或分析PIO程序时,可以使用rp2.PIO.state_machine()方法来获取和初始化状态机对象。例如,如果需要检查或比较不同的PIO程序的运行结果或性能,可以使用rp2.PIO.state_machine()方法来获取和初始化多个状态机对象,并将它们关联到不同的程序。

它需要注意的事项有:

在使用rp2.PIO.state_machine()方法时,需要确保id参数是一个有效的状态机编号,否则会抛出ValueError异常。
在使用rp2.PIO.state_machine()方法时,需要确保后面的可选参数是有效的配置参数,否则会抛出TypeError或ValueError异常。
在使用rp2.PIO.state_machine()方法时,需要注意与rp2.StateMachine类和rp2.StateMachine.init()方法的区别和配合。rp2.StateMachine类是一个更高级别的接口,用于直接创建一个状态机对象,并自动将其关联到相应的PIO实例和程序。rp2.StateMachine.init()方法是用于重新配置一个已经存在的状态机对象,并自动将其关联到相应的PIO实例和程序。通常情况下,推荐使用rp2.StateMachine类或rp2.StateMachine.init()方法来创建和管理状态机对象。

以下是MicroPython的rp2.PIO.state_machine()几个实际运用程序参考代码案例:

案例1:使用rp2.asm_pio()函数编写一个UART发送功能的程序,并使用rp2.PIO.state_machine()方法获取和初始化第0个PIO实例的第0个状态机对象,并将其关联到该程序

import rp2
import machine

# 使用rp2.asm_pio()函数编写一个UART发送功能的程序
@rp2.asm_pio(out_shiftdir=rp2.PIO.SHIFT_LEFT)
def uart_tx():
    pull()
    set(y, 31)
    out(pins, 1) [31]
    out(x, 8) [31]
    out(pins, 1) [31]

# 获取第0个PIO实例对象
pio = rp2.PIO(0)

# 使用rp2.PIO.state_machine()方法获取和初始化第0个PIO实例的第0个状态机对象,并将其关联到uart_tx程序
sm = pio.state_machine(0, uart_tx, freq=9600, out_base=machine.Pin(0))

# 启动状态机
sm.active(1)

案例2:使用rp2.PIOProgram类构造一个根据用户输入产生不同频率方波信号的程序,并使用rp2.PIO.state_machine()方法获取和初始化第0个PIO实例的第0个状态机对象,并将其关联到该程序

import rp2
import machine

# 定义一个根据用户输入产生不同频率方波信号的函数
def generate_wave(freq):
    # 计算y寄存器需要设置的值,以便产生所需频率
    y_value = int(125000000 / (freq * 2) - 1)

    # 使用rp2.asm_pio_encode()函数将y寄存器的值编码为机器码指令
    set_y_code = rp2.asm_pio_encode(f"set (y, {y_value})", 0)

    # 使用rp2.asm_pio_encode()函数将其他固定的PIO指令编码为机器码指令
    out_code = rp2.asm_pio_encode("out (pins, 1)", 0)
    jmp_code = rp2.asm_pio_encode("jmp y_dec", 0)

    # 将所有的机器码指令组合成一个字节数组
    program = bytearray([set_y_code & 0xff, set_y_code >> 8, out_code & 0xff, out_code >> 8, jmp_code & 0xff, jmp_code >> 8])

    # 使用rp2.PIOProgram类构造一个PIO程序对象,并设置一些配置参数
    pio_program = rp2.PIOProgram(program, freq=125000000, out_base=machine.Pin(0))

    # 获取第0个PIO实例对象
    pio = rp2.PIO(0)

    # 使用rp2.PIO.state_machine()方法获取和初始化第0个PIO实例的第0个状态机对象,并将其关联到pio_program对象
    sm = pio.state_machine(0, pio_program)

    # 启动状态机
    sm.active(1)

# 调用函数,生成一个频率为100Hz的方波信号
generate_wave(100)

案例3:使用rp2.PIO.state_machine()方法获取和初始化第0个PIO实例的两个状态机对象,并将它们分别关联到两个不同的闪烁LED的程序

import rp2
import machine

# 定义两个不同的闪烁LED的程序
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def blink_1hz():
    irq(rel(0))
    set(pins, 1)
    set(x, 31) [5]
    label("delay_high")
    nop() [29]
    jmp(x_dec, "delay_high")
    nop()
    set(pins, 0)
    set(x, 31) [5]
    label("delay_low")
    nop() [29]
    jmp(x_dec, "delay_low")

@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def blink_2hz():
    irq(rel(0))
    set(pins, 1)
    set(x, 15) [5]
    label("delay_high")
    nop() [29]
    jmp(x_dec, "delay_high")
    nop()
    set(pins, 0)
    set(x, 15) [5]
    label("delay_low")
    nop() [29]
    jmp(x_dec, "delay_low")

# 获取第0个PIO实例对象
pio = rp2.PIO(0)

# 使用rp2.PIO.state_machine()方法获取和初始化第0个PIO实例的第0个状态机对象,并将其关联到blink_1hz程序,指定GPIO25引脚用于set()指令
sm1 = pio.state_machine(0, blink_1hz, freq=2000000, set_base=machine.Pin(25))

# 使用rp2.PIO.state_machine()方法获取和初始化第0个PIO实例的第1个状态机对象,并将其关联到blink_2hz程序,指定GPIO26引脚用于set()指令
sm2 = pio.state_machine(1, blink_2hz, freq=2000000, set_base=machine.Pin(26))

# 启动两个状态机
sm1.active(1)
sm2.active(1)

案例4:读取PIO引脚状态:

import rp2
from machine import Pin

# 创建PIO状态机对象
state_machine = rp2.PIO(0)

# 配置PIO状态机为输入模式
state_machine.in_(Pin(2))

# 读取PIO引脚状态
pin_state = state_machine.state()

# 处理读取的引脚状态
print(pin_state)

在这个示例中,我们创建了一个PIO状态机对象,并将其与GPIO引脚2关联。通过调用state_machine.state()方法,我们可以读取PIO引脚的状态并进行处理。

案例5:设置PIO引脚状态::

import rp2
from machine import Pin

# 创建PIO状态机对象
state_machine = rp2.PIO(0)

# 配置PIO状态机为输出模式
state_machine.out(Pin(2))

# 设置PIO引脚状态为高电平
state_machine.set()

# 其他代码...

在这个示例中,我们同样创建了一个PIO状态机对象,并将其与GPIO引脚2关联。通过调用state_machine.set()方法,我们可以将PIO引脚的状态设置为高电平。

案例6:使用PIO状态机实现PWM输出::

import rp2
from machine import Pin

# 创建PIO状态机对象
state_machine = rp2.PIO(0)

# 配置PIO状态机为输出模式
state_machine.out(Pin(2))

# 设置PIO状态机频率和占空比
state_machine.freq(1000)
state_machine.duty_u16(32768)

# 启动PIO状态机
state_machine.active(1)

# 其他代码...

在这个示例中,我们同样创建了一个PIO状态机对象,并将其与GPIO引脚2关联。通过调用state_machine.freq()和state_machine.duty_u16()方法,我们可以设置PIO状态机的频率和占空比,从而实现PWM输出。最后,通过调用state_machine.active()方法,我们启动PIO状态机以开始PWM输出。

请注意,以上示例中的引脚配置和参数设置仅供参考,实际应用中需要根据具体硬件和需求进行适当的调整。

案例7:LED闪烁

import rp2
from machine import Pin

@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW)  
def blink():
  wrap_target()
  label('loop')
  out(x, 1)  
  jmp(not_x, 'loop')

sm = rp2.PIO(0) 
sm.init(blink)

led = Pin(25, Pin.OUT)
sm.put(led, freq=500)

这个示例实现了LED闪烁的PIO状态机。

示例8:步进电机控制

import rp2
from machine import Pin

@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW)
def stepper():
  wrap_target()  
  label('halfstep')
  out(pins, 1)  
  set(pins, 0)
  jmp(x, 'halfstep')

sm = rp2.PIO(0)
sm.init(stepper, freq=1000) 

pins = [Pin(i) for i in (10, 11, 12, 13)]
sm.put(pins)

这个示例用PIO控制步进电机。

示例9:ADC读取

import rp2
from machine import ADC

@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def adc():
  pull(block)
  mov(x, osr)

sm = rp2.PIO(0)
adc = ADC(Pin(28))  
sm.init(adc, freq=20000)
sm.put(adc)

val = sm.get() # 读取ADC值

这个示例实现了利用PIO读取ADC的功能。

这些示例展示了PIO状态机的强大功能,可以用来控制硬件、读取数据等。

请注意,以上示例仅供参考,具体的使用方法可能因不同的硬件平台和MicroPython版本而有所差异。在实际编程中,你需要根据你所使用的硬件和具体需求进行适当的调整。

在这里插入图片描述

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

驴友花雕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值