4、Python在嵌入式AI中的角色:MicroPython与CPython的区别、固件烧录、REPL交互式调试、GPIO控制基础
说到嵌入式AI,很多人第一反应是C语言。没错,C是底层的主力。但Python呢?它在嵌入式AI里到底扮演什么角色?
我个人的看法是:Python是嵌入式AI的“快速验证层”和“胶水层”。你想想看,模型训练阶段几乎全是Python,数据预处理、模型导出、精度验证,这些环节用C去搞,开发效率会低得让人崩溃。而到了部署阶段,Python又能帮你快速调试硬件、验证外设逻辑。
说白了,Python不是来替代C的,它是来帮你把“从训练到部署”这条路走通的。
4.1 MicroPython与CPython:同源不同路
很多初学者会问:MicroPython和CPython到底有啥区别?我能不能把PC上的Python代码直接扔到开发板上跑?
答案很明确:不能。至少不能直接跑。
| 对比维度 | CPython | MicroPython |
|---|---|---|
| 运行环境 | PC、服务器(x86/ARM Linux) | MCU、嵌入式设备(STM32、ESP32等) |
| 内存占用 | 几十MB起步 | 几十KB到几百KB |
| 标准库支持 | 完整(os、sys、numpy、torch等) | 精简版(仅核心模块,无numpy等) |
| 浮点运算 | 原生支持,性能强 | 软件模拟或硬件FPU(视芯片而定) |
| 文件系统 | 完整文件系统 | Flash文件系统(FAT/VFAT) |
| 交互式调试 | IPython/Jupyter | REPL(串口或USB) |
MicroPython是CPython的一个子集,但它不是简单的“阉割版”。它针对资源受限的MCU做了大量优化。比如,它去掉了复杂的元类机制,简化了内存管理,甚至允许你直接操作寄存器。
我在项目中遇到过一个问题:用CPython写的GPIO控制逻辑,直接复制到MicroPython里跑,结果报错说没有RPi.GPIO模块。嗯,这很正常。MicroPython有自己的硬件抽象层,叫machine模块。你得用machine.Pin来操作GPIO,而不是RPi.GPIO。
核心区别一句话总结:
CPython是“全能型选手”,适合做模型训练和复杂逻辑验证;MicroPython是“轻量级特种兵”,适合做嵌入式端的快速原型和硬件调试。
4.2 固件烧录:把Python解释器塞进MCU
要让开发板跑MicroPython,第一步就是烧录固件。说白了,就是把MicroPython的解释器写进芯片的Flash里。
我习惯用esptool.py来烧录ESP32系列的板子。为什么?因为它跨平台,而且支持命令行批量操作。你想想看,如果每次烧录都要打开一个图形界面点来点去,那效率得多低。
烧录步骤(以ESP32为例):
- 下载MicroPython固件(.bin文件)
- 安装esptool:
pip install esptool - 擦除Flash:
esptool.py --port COM3 erase_flash - 烧录固件:
esptool.py --port COM3 --baud 460800 write_flash -z 0x1000 firmware.bin
注意:我曾经因为忘记擦除Flash,导致烧录后系统启动异常。后来排查了半天,发现是旧固件残留和新固件冲突了。所以,擦除Flash这一步千万别省。
烧录完成后,你打开串口工具(比如PuTTY、screen、或者Thonny自带的串口终端),就能看到MicroPython的启动信息。如果看到类似这样的输出,说明固件烧录成功了:
MicroPython v1.20.0 on 2023-04-26; ESP32 module with ESP32
Type "help()" for more information.
>>>
4.3 REPL交互式调试:实时反馈的快乐
REPL(Read-Eval-Print Loop)是MicroPython最吸引我的地方。你想想看,在C语言开发中,你要编译、烧录、复位,才能看到效果。而MicroPython呢?你敲一行代码,回车,立刻就能看到结果。
这种“所见即所得”的调试方式,对于验证硬件逻辑来说,简直是神器。
REPL常用操作:
help():查看帮助信息dir():查看当前命名空间import machine:导入硬件模块machine.freq():查看CPU频率Ctrl+C:中断当前程序Ctrl+D:软复位
我记得有一次调试一个I2C传感器,数据死活读不出来。用C语言的话,我得反复修改代码、编译、烧录,至少折腾半小时。但用MicroPython的REPL,我直接在终端里敲:
>>> from machine import I2C, Pin
>>> i2c = I2C(scl=Pin(22), sda=Pin(21))
>>> i2c.scan()
[60]
看到返回的地址是60,我立刻知道I2C总线是通的。然后继续敲几行代码,就把传感器的数据读出来了。整个过程不到5分钟。
小技巧:在REPL中,你可以用Tab键自动补全。比如输入machine.然后按Tab,它会列出所有可用的属性和方法。这个功能在记不住API的时候特别有用。
4.4 GPIO控制基础:让Python控制物理世界
GPIO(通用输入输出)是嵌入式开发最基础的操作。在MicroPython中,控制GPIO非常简单。
控制LED闪烁:
from machine import Pin
import time
# 初始化GPIO2为输出模式
led = Pin(2, Pin.OUT)
while True:
led.value(1) # 点亮LED
time.sleep(0.5)
led.value(0) # 熄灭LED
time.sleep(0.5)
这段代码在CPython里跑不了,因为CPython没有machine模块。但在MicroPython里,它就能直接控制开发板上的LED。
读取按键输入:
from machine import Pin
# 初始化GPIO0为输入模式,并启用内部上拉电阻
button = Pin(0, Pin.IN, Pin.PULL_UP)
# 读取按键状态
if button.value() == 0:
print("按键被按下")
else:
print("按键未按下")
这里有个坑,我必须要提醒你。很多开发板的按键是低电平有效的,也就是按下时读到0,松开时读到1。如果你用外部下拉电阻,逻辑可能正好相反。所以,写代码前一定要先看原理图。
GPIO控制的核心要点:
- 输出模式:控制LED、蜂鸣器、继电器等
- 输入模式:读取按键、传感器信号等
- 上拉/下拉电阻:确保输入引脚在悬空时有确定电平
- 中断模式:响应外部事件,避免轮询浪费CPU
说到中断,MicroPython也支持。比如你想在按键按下时立刻响应,而不是一直轮询,可以这样写:
from machine import Pin
def button_handler(pin):
print("按键被按下!")
button = Pin(0, Pin.IN, Pin.PULL_UP)
button.irq(trigger=Pin.IRQ_FALLING, handler=button_handler)
这样,当按键按下(电平从高变低)时,系统会自动调用button_handler函数。你想想看,如果不用中断,你得在主循环里不断检查按键状态,不仅代码冗余,还浪费CPU资源。
好了,这一章的内容就到这里。Python在嵌入式AI中的角色,说白了就是“快速验证”和“灵活调试”。MicroPython让你能用Python的方式去控制硬件,而REPL交互式调试则让开发过程变得高效又直观。下一章,我们会深入探讨如何用MicroPython驱动常见的传感器和执行器,敬请期待。