Raspberry Pico作为一种超小型化的开发板,相比普通版的树莓开发板,其更像是一个单片机——其没有操作系统,启动后自动加载默认的代码。但带来的好处也是更加简单可控,对于处理简单的硬件控制更加好用,同时体积和功耗也更低,一些精简化的Pico体积仅有邮票大小,非常适合部署在体积极为有限的设备内,并且价格仅有几十元,相比标准的树莓也有巨大的优势。
Pico同样可使用C或Python进行开发,但既然选择使用Pico那肯定用Python会更加简单高效,但其不能使用完整的Python系统,使用的为MicroPython,其实现了Python的基本功能,同时还提供了一些针对Pico的功能,例如UART、I2C端口的通信API等。代码直接可运行,不需要进行编译,调试也非常方便,不过为了保护代码也可以将代码编译成二进制。
首次使用时需要对Pico进行固件的安装,按住Pico的Boot按键将Pico通过USB连接至PC,此时会识别出一个移动磁盘设备,此时将下载的固件拖入其中即可完成固件的安装,完成后Pico会重启并开始加载固件。
开发可以使用Thonny,其为一个针对MicroPython和Pico的IDE,可以直接连接Pico,并上载代码运行和查看运行结果。
Pico在加载固件后会自动运行main.py,为此可将代码的入口放在这里,通电启动后即开始执行这里的代码,执行结束后退出,一些版本的Pico中也支持通过一个按键进行复位从头再开始执行一次main.py。
对于一些需要一直保持运行状态的应用场景,可以将其主循环放在main.py中,其他的代码放在其余文件中,通过import引入进行调用。
通信接口
Pico有26个GPIO针脚,其中很多针脚可以实现多种用途,并且都可以进行PWM信号输出,详细可参考官方的文档
#引入Pico中的基础API from machine import Pin, PWM, UART, I2C; #定义对应的通信针脚代号 I2C_SCL_PIN = 3; I2C_SDA_PIN = 2; UART_TX_PIN = 0; UART_RX_PIN = 1; #初始化对应通信接口 i2c = I2C(1, scl=Pin(I2C_SCL_PIN), sda=Pin(I2C_SDA_PIN)); uart = UART(0, baudrate=9600, tx=Pin(UART_TX_PIN), rx=Pin(UART_RX_PIN));协程实现异步操作
由于MicroPython中没有完成的多线程支持,为此只能通过协程实现IO部分的异步处理
#接收串口数据 async def uart_rx_task(uart, q): #循环接收数据 while True: #如果收到数据则放入队列中 if uart.any(): data = uart.read(); q.append(data); else: pass; #交出执行权给主线程 await asyncio.sleep(0.1); #主程序 async def main(): #启动数据接收协程 asyncio.create_task(uart_rx_task(uart, q)); #主循环 while True: #处理队列中的消息 while len(q) > 0: data = q.popleft(); #处理其他工作... #交出执行权给接收协程 await asyncio.sleep(0.05);在main.py中启动主程序的写入如下
if __name__ == '__main__': asyncio.run(main());
有时我们不想暴露Pico中代码的实现细节,可以使用工具将代码编译成二进制,虽然编译成的二进制也可通过反编译等手段进行代码的还原,但还原后的代码的可读性要差很多,还是可以起到一定的保护作用。一般推荐的工具为mpy-cross,可以将python代码编程成为mpy文件。编译时需要指定CPU架构,Pico对应的CPU架构为armv6m。
mpy-cross -march=armv6m core.py会得到一个core.mpy文件,这里不使用main.py的原因是因为Pico不会自己自动运行main.mpy,所以为了能够自动运行可以将代码封装到core.py中编译为core.mpy,另外写一个main.py调用core.mpy中的运行方法执行代码。
import core.main; if __name__ == '__main__': core.main();