MicroPython微控制器程序开发入门指南
投稿人:DigiKey 北美编辑
2017-09-07
实时嵌入式系统变得非常复杂,不仅要深入了解复杂的 32 位微控制器,还要了解传感器、算法、因特网协议以及各种不同的终端用户应用。随着开发周期缩短和功能增多,开发团队需要设法加速设计并将代码移植到新产品中,因此,他们需要一个集成且灵活的开发平台。
有几个微控制器特定的平台可帮助加快开发流程,但这种解决方案的问题在于,开发人员只能依赖单一的微控制器供应商。将软件从一个平台移植到另一个平台非常耗时,而且成本很高。
有一种独特且新颖的解决方案获得了广泛的认可和接受:将低级微控制器硬件与高级编程语言(如 Python)相结合。MicroPython 就是这样的解决方案。这种方案可在几个不同的微控制器供应商的零部件上运行,而且是开源的,使开发人员能够随时使用和自定义需求。
MicroPython.org 将其描述为精益高效的 Python 3 编程语言的执行,其中包括 Python 标准库的较小子集,该库经过优化可在微控制器和受限环境中运行。MicroPython 项目采用众筹形式,不仅可以成功获得资金,而且吸引了大量关注,现已成功应用于多个行业的项目,例如基于工业与空间的系统。
选择正确的微控制器
MicroPython 可在几个不同的微控制器上运行。如果微控制器具有足够的 RAM、闪存和处理能力来运行解释器,那么将 MicroPython 移植到更多微控制器就不会遇到太大的限制。也就是说,对于运行 MicroPython 的微控制器,开发人员应关注几个关键要求:
- 至少 256 KB 闪存
- 至少 16 KB RAM
- 至少 80 MHz 时钟频率
这些只是一般建议,开发人员可根据实际的应用需求和定制 MicroPython 内核的预期时间来进行调整。例如,可以修改 MicroPython,以使用远低于 256 KB 的闪存。这些建议旨在为开发人员提供最佳体验并为应用代码提供改进空间。
MicroPython 已被移植到几个不同的微控制器系列,这是一个很好的起点,之后可以将其移植到新平台或选择已经受支持的微控制器。图 1 展示了 MicroPython 源代码的主目录。读取器可以从这个目录读取到几个不同的受支持的微控制器,如:
- 基于 ARM® 的微控制器
- Texas Instruments 的 CC3200
- Adafruit 的 ESP8266
- Microchip Technology 的 16 位 PIC 微控制器
- STMicrolectronics 的 STM32
图 1: 示例文件夹目录结构展示了目前支持 MicroPython 的可用的微控制器平台。这些微控制器包括 ARM、CC3200、esp8266、Microchip PIC 和 STM32。(图片来源: Beningo Embedded Group)
根目录列出的每个文件夹都是高级文件夹,包含一般驱动器和针对该芯片系列的支持。每个文件夹可能支持几个不同的开发板或处理器。例如,stmhal 文件夹支持 STMicroelectronics 的 STM32F429 Discovery Board 和 STM32 IoT Discovery Node (STM32L) 以及 Adafruit Industries 的 STM32F405 pyboard 等开发板。ESP8266 文件夹支持 Adafruit 的 Huzzah 分线板(用于 ESP8266)以及 Feather Huzzah Stack Board。
可运行 MicroPython 的开发板价格低廉,开发人员可以购买多个开发板来摸索应用程序需要多少内存、存储空间和处理能力。例如,开发人员刚开始可使用 STM32F405 pyboard,之后决定移到最终产品中的 STM32F429,以实现面向未来的功能和升级。STM32F429 具有 2 MB 闪存、24 KB RAM 和特殊的零瓦等待状态的 RAM(称为 CCM)。
开发人员编写的 MicroPython 应用代码不一定要存储在微控制器的内部闪存中。MicroPython 内核需要存在于微控制器,但应用代码可放在外部存储介质,例如 Panasonic 的 microSD 8 GB 卡。将应用代码存储在外部存储介质,就能够使用内存更低的微控制器,节省了整体系统成本。
入门及使用 MicroPython
MicroPython 已预装到 Adafruit STM32F405 pyboard 上。对于其他开发套件或定制硬件,开发人员都需要下载 MicroPython 源代码,为目标板构建源代码,然后使用软件刷新微控制器。MicroPython 全部存放在 GitHub 中,可以轻松访问。开发人员需遵循几个步骤来设置工具链并配置构建 MicroPython 的环境。在这个例子中,我们将为 STM32F429 Discovery 开发板构建 MicroPython。
首先,开发人员需要创建一个基于 Linux 的虚拟机或使用原生 Linux 安装。可从终端获得 Linux 之后,开发人员可使用以下命令来安装 ARM 编译器工具链:
sudo apt-get install gcc-arm-none-eabi
如果安装的是新版本的 Linux,可能不带版本控制系统 Git。可使用以下命令从终端安装 Git:
sudo apt-get install git
安装 Git 之后,可以通过在终端中执行以下命令来检验存储库的 MicroPython 源代码:
git clone https://github.com/micropython/micropython.git
这个过程可能需要几分钟,但开发人员可以看到演示的序列(图 2)。
图 2: 将 MicroPython 存储库克隆到本地文件系统,以便开发人员为目标板构建 MicroPython 或根据具体应用定制内核。 (图片来源: Beningo Embedded Group)
将 MicroPython 源代码克隆到本地文件系统之后,应将其更改到该目录,然后在终端执行“cd stmhal”。stmhal 目录包含 STM32 微控制器的 MicroPython 的编译脚本。还有一个供开发人员查看的“boards”文件夹,显示了目前支持的所有 STM32 开发板。开发人员可以从终端构建任何位于“boards”文件夹的开发板。例如,开发人员可键入以下命令来构建 STM32F4 Discovery 开发板:
make BOARD=STM32F4DISC
MicroPython 的构建过程需要几分钟。在构建过程中,开发人员可以安装设备固件更新 (DFU) 工具,用于通过 USB 将 MicroPython 编程到微控制器中。该工具只需安装一次,可通过在终端输入以下命令来完成:
sudo apt-get install dfu-util
MicroPython 构建完成并安装 dfu-util 之后,开发人员即可将 MicroPython 加载到他们的微控制器上。开发人员需要先将微控制器设置到 DFU 引导程序模式。要完成这一步,可以设置引导引脚来复位加载内部引导程序,而不是从闪存执行代码。
当微控制器处于引导程序模式并通过 USB 连接到主机时,可通过以下命令来使用 dfu-util 下载 MicroPython:
dfu-util -a 0 -d 0483:df11 -D build-STM32F4DISC/firmware.dfu
dfu-util 将使用编译过程输出的 dfu 文件。这个过程需要几分钟时间,因为微控制器将被完全擦除并重新编程。这个过程与图 3 所示的过程非常相似。工具完成之后,应将引导跳线设置为从内部闪存加载,然后重启微控制器的电源。现在,MicroPython 已经在目标微控制器上运行。
图 3: 使用 dfu-util 将 MicroPython 加载到微控制器。(图片来源: Beningo Embedded Group)
连接传感器和设备
使用 MicroPython 等高级编程语言来开发实时嵌入式软件的最大优点在于:软件独立于基础硬件。这意味着开发人员可以编写一个 MicroPython 脚本在 pyboard 上运行,而且可以稍作修改或原封不动地在 ESP8266 或 STM32F4 Discovery 开发板上运行该脚本。让我们来看看基本的 MicroPython 脚本如何将一个 Bosch Sensortec BMP280 气压计和温度传感器连接到 I2C 总线,然后使用 Microchip Technology RN-42 蓝牙模块通过蓝牙串行链路传输数据。
BMP280 是一款基于 I2C 的气压计和温度传感器,具有默认的十进制 119 的 I2C 从地址。将其连接到 pyboard 的最简单的方法是使用 DFRobot 的 Gravity 板,它提供了一个强大的连接器,可轻松启动设备和访问 I2C。开发人员可选择 I2C1 或 I2C2 总线来连接 Gravity 板。连接板之后,MicroPython 脚本就很简单了。
首先,开发人员需要从 pyb 库导入 I2C 类。通过 pyb 库可访问微控制器外设功能,如 SPI、I2C 和 UART。在使用任何外设之前,开发人员必须实例化外设类,以创建可用于控制外设的对象。外设类初始化之后,开发人员可以执行任何其他初始化,例如在进入主应用程序循环之前验证设备是否存在。主应用代码将每秒对传感器进行一次采样。代码列表 1 是这个过程的示例。
Copy
from pyb import I2C
GlobalTemp = 0.0
GlobalBarometer = 0.0
# Initialize and Instantiate I2C peripheral 2
I2C2 = I2C(2,I2C.MASTER, baudrate=100000)
while True:
SensorSample()
pyb.delay(1000)
def SensorSample():
#Read the Temperature Data
TempSample = I2C2.readfrom_mem(119, 0xFA,3)
#Read the Pressure Data
PressureSample = I2C2.readfrom_mem(119, 0xF7,3)
代码列表 1: MicroPython 脚本用于初始化 I2C 外设并与 DFRobot Gravity 板通信,以获取温度和气压计传感器数据。(代码来源: Beningo Embedded Group)
如果只对传感器数据进行采样却不使用,开发团队就无法体验到 MicroPython 有力的帮助。许多开发团队面临一个技术挑战:使用蓝牙将传感器设备连接到因特网或本地传感器中枢。
为项目添加蓝牙功能的一个简单方法是使用 RN-42。RN-42 可以进入一个模式:微控制器只需发送应通过蓝牙传输的 UART 数据,由 RN-42 处理整个蓝牙堆栈(图 4)。
图 4: 通过 UART 将运行 MicroPython 的 pyboard 连接到 RN-42 蓝牙模块。(图片来源: Beningo Embedded Group)
连接蓝牙板之后,开发人员就可以创建一个非常简单的脚本,将接收到的传感器数据通过蓝牙传输到移动设备,之后可以保存数据或发送到云端进行进一步分析。代码列表 2 是这个过程的示例。在这个例子中,UART1 配置为 115200 bps、8 位传输、无奇偶校验和单个停止位。
Copy
from pyb import uart
from pyb import I2C
GlobalTemp = 0.0
GlobalBarometer = 0.0
# Initialize and Instantiate I2C peripheral 2
I2C2 = I2C(2,I2C.MASTER, baudrate=100000)
# Configure Uart1 for communication
Uart1 = pyb.UART(1,115200)
Uart1.init(115200, bits=8, parity=None, stop=1)
while True:
SampleSensor()
pyb.delay(1000)
def SensorSample():
#Read the Temperature Data
TempSample = I2C2.readfrom_mem(119, 0xFA,3)
#Read the Pressure Data
PressureSample = I2C2.readfrom_mem(119, 0xF7,3)
#Convert Sample data to string
data = “#,temperature=”str(TempSample)+”,pressure”+str(PressureSample)+”,#,\n\r”
#Write the data to Bluetooth
Uart1.write(data)
代码列表 2: MicroPython 脚本初始化 UART1 并与外部设备通信的示例。(代码来源: Beningo Embedded Group)
该应用不仅可以将 Python 应用代码轻松地移植到其他硬件平台上,还能使用已实现的常用库和功能来帮助开发人员加速开发。上述应用程序的创建可以在一个小时或更短的时间内完成;如果开发人员从最低软件层面开始逐步创建,可能就需要一周或更长时间。
开发实时软件的技巧与窍门
使用 MicroPython 开发嵌入式应用非常简单,但从系统获得实时性能可能就没有想象中那么简单了。MicroPython 提供了简化和重用代码这一巨大的优势,但如果开发人员不了解一些有趣的事实和资源库,从系统获取可预测和一致的时序可能就会是一项有挑战性的任务。
MicroPython 包含一个在后台运行的垃圾回收器,用于管理堆栈和其他内存资源。垃圾回收器是非确定性的,如果开发人员希望垃圾回收器在关键时间段开始执行时能做出确定性的行为,可能就会遇到麻烦。以下几个建议可帮助开发人员避免这种麻烦。
首先,开发人员可以导入垃圾回收库 gc,并使用“启用”和“禁用”方法来控制启用或禁用垃圾回收器的时间。如代码列表 3 所示,开发人员可以在关键时间段之前禁用垃圾回收,之后再启用。
Copy
import gc
gc.disable()
#My time critical code
gc.enable()
代码列表 3: 在时间关键代码段之前禁用 MicroPython 垃圾回收器。(代码来源: Beningo Embedded Group)
其次,开发人员也可以手动控制垃圾回收过程。开发人员创建并销毁对象时,即在堆栈上分配内存。垃圾回收器运行并释放未使用的空间。由于它是不定期进行的,开发人员可使用收集方法定期运行垃圾回收,以确保堆栈空间不会被垃圾填满。完成这个操作后,垃圾回收运行可以从每次 10 毫秒降低到 1 毫秒以内。手动调用垃圾回收还可确保开发人员的应用程序可以控制非确定性的定时代码。这使他们可以决定何时运行垃圾回收,并确保他们的应用程序具有实时性能。
对编写实时代码感兴趣的开发人员可以关注其他几个最佳实践。其中包括:
- 使用预分配的用于通信通道的缓冲器
- 使用通信外设时采用 readinto 方法
- 使用 ### 避免传统的 Python 文档
- 在运行时最大限度地减少对象的创建和析构
- 监控应用程序执行时间
有兴趣了解更多“最佳实践”的开发人员可以在这里查看 MicroPython 优化文档。
总结
对于想要实现独立于基础微控制器硬件的实时嵌入式应用程序的开发人员来说,MicroPython 是一个值得关注的平台。开发人员可以使用 MicroPython 提供的标准库来编写高级 Python 脚本,并在任何受支持的微控制器上运行脚本。这为开发人员带来了很多好处,包括:
- 提高了应用重复使用率
- 缩短了产品上市时间
- 将应用程序从硬件中独立开来
MicroPython 并不适用于所有应用,但迄今为止已在工业与空间系统应用领域取得了成功,同时还实现了快速的原型开发和概念验证。
免责声明:各个作者和/或论坛参与者在本网站发表的观点、看法和意见不代表 DigiKey 的观点、看法和意见,也不代表 DigiKey 官方政策。