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为例):

  1. 下载MicroPython固件(.bin文件)
  2. 安装esptool:pip install esptool
  3. 擦除Flash:esptool.py --port COM3 erase_flash
  4. 烧录固件: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驱动常见的传感器和执行器,敬请期待。