目 录
-
- 摘要
- [1. 引言:当 Python 遇见物联网](#1. 引言:当 Python 遇见物联网)
- [2. 边缘计算基础](#2. 边缘计算基础)
-
- [2.1 什么是边缘计算](#2.1 什么是边缘计算)
- [2.2 边缘计算的优势](#2.2 边缘计算的优势)
- [2.3 边缘计算架构层次](#2.3 边缘计算架构层次)
- [3. MicroPython 深度解析](#3. MicroPython 深度解析)
-
- [3.1 MicroPython 简介](#3.1 MicroPython 简介)
- [3.2 支持的硬件平台](#3.2 支持的硬件平台)
- [3.3 MicroPython 架构](#3.3 MicroPython 架构)
- [3.4 安装 MicroPython](#3.4 安装 MicroPython)
- [4. CircuitPython 深度解析](#4. CircuitPython 深度解析)
-
- [4.1 CircuitPython 简介](#4.1 CircuitPython 简介)
- [4.2 CircuitPython 的独特优势](#4.2 CircuitPython 的独特优势)
- [4.3 支持的硬件平台](#4.3 支持的硬件平台)
- [5. 微控制器编程核心概念](#5. 微控制器编程核心概念)
-
- [5.1 GPIO 控制](#5.1 GPIO 控制)
- [5.2 PWM 输出](#5.2 PWM 输出)
- [5.3 传感器接口](#5.3 传感器接口)
-
- [5.3.1 I2C 传感器](#5.3.1 I2C 传感器)
- [5.3.2 SPI 显示器](#5.3.2 SPI 显示器)
- [5.4 中断处理](#5.4 中断处理)
- [6. 低功耗设计](#6. 低功耗设计)
-
- [6.1 功耗优化策略](#6.1 功耗优化策略)
- [6.2 睡眠模式](#6.2 睡眠模式)
- [6.3 低功耗传感器读取](#6.3 低功耗传感器读取)
- [7. 网络通信](#7. 网络通信)
-
- [7.1 Wi-Fi 连接](#7.1 Wi-Fi 连接)
- [7.2 HTTP 请求](#7.2 HTTP 请求)
- [7.3 MQTT 协议](#7.3 MQTT 协议)
- [8. 实战项目:智能环境监测站](#8. 实战项目:智能环境监测站)
-
- [8.1 项目概述](#8.1 项目概述)
- [8.2 硬件清单](#8.2 硬件清单)
- [8.3 接线图](#8.3 接线图)
- [8.4 完整代码实现](#8.4 完整代码实现)
- [9. MicroPython vs CircuitPython 选择指南](#9. MicroPython vs CircuitPython 选择指南)
-
- [9.1 对比总结](#9.1 对比总结)
- [9.2 选择建议](#9.2 选择建议)
- [10. 总结](#10. 总结)
- 参考资料
摘要
随着物联网(IoT)设备的爆发式增长,边缘计算已成为解决云端延迟、带宽和隐私问题的关键技术。本文深入探讨 Python 在边缘计算和 IoT 领域的应用实践,重点介绍 MicroPython 和 CircuitPython 这两大轻量级 Python 实现。文章从边缘计算的基本原理出发,详细解析微控制器编程的核心概念,包括 GPIO 控制、传感器接口、低功耗设计等关键技术。通过丰富的代码示例和实战项目,展示如何使用 Python 快速开发智能硬件应用,帮助开发者跨越嵌入式开发的门槛,将 Python 技能延伸到物联网领域。
1. 引言:当 Python 遇见物联网
在传统的嵌入式开发领域,C/C++ 长期占据统治地位。开发者需要深入理解寄存器操作、内存管理、中断处理等底层概念,学习曲线陡峭。对于习惯于 Python 简洁语法的开发者而言,转向嵌入式开发往往意味着重新学习一门全新的技术栈。
MicroPython 和 CircuitPython 的出现改变了这一局面。它们是 Python 3 的精简实现,专门针对微控制器和资源受限环境优化。虽然体积小巧,但保留了 Python 语言的核心特性:动态类型、自动内存管理、丰富的标准库子集。这意味着 Python 开发者可以用熟悉的语法,快速开发物联网应用,无需深入嵌入式底层。
边缘计算的兴起进一步推动了这一趋势。将计算从云端下沉到设备端,可以显著降低延迟、减少带宽消耗、保护用户隐私。Python 以其简洁易用的特性,成为边缘计算开发的理想选择。
2. 边缘计算基础
2.1 什么是边缘计算
边缘计算是一种分布式计算范式,将数据处理和存储从中心化的云端下沉到网络边缘,即数据产生的源头附近。这种架构带来了显著的性能和隐私优势。
边缘计算架构
是
否
IoT 设备
边缘节点
本地处理
需要云端?
云端数据中心
本地决策
返回结果
传统云计算架构
IoT 设备
云端数据中心
数据处理
返回结果
2.2 边缘计算的优势
| 优势 | 说明 | 应用场景 |
|---|---|---|
| 低延迟 | 数据本地处理,无需往返云端 | 工业控制、自动驾驶 |
| 带宽节省 | 仅上传处理后的结果 | 视频监控、传感器网络 |
| 隐私保护 | 敏感数据无需离开设备 | 医疗设备、智能家居 |
| 离线运行 | 不依赖网络连接 | 远程监测、户外设备 |
| 实时响应 | 毫秒级决策能力 | 机器人控制、安全系统 |
2.3 边缘计算架构层次
云端层(Cloud Layer)
边缘层(Edge Layer)
设备层(Device Layer)
传感器
执行器
微控制器
边缘网关
本地服务器
边缘计算节点
数据中心
大数据分析
AI 训练
3. MicroPython 深度解析
3.1 MicroPython 简介
MicroPython 是 Python 3 编程语言的精简高效实现,由 Damien George 于 2013 年发起,专门针对微控制器和资源受限环境设计。它包含了 Python 标准库的一个小子集,但足以完成大多数嵌入式开发任务。
MicroPython 的核心特点:
| 特性 | 说明 |
|---|---|
| 极小体积 | 最小仅需 256KB 代码空间和 16KB RAM |
| 完整语法 | 支持完整的 Python 3 语法 |
| 交互式 REPL | 支持实时交互调试 |
| 跨平台 | 支持多种微控制器架构 |
| 模块化 | 可按需编译所需功能 |
3.2 支持的硬件平台
MicroPython 支持多种主流微控制器平台:
| 平台 | 架构 | 特点 | 适用场景 |
|---|---|---|---|
| ESP32 | Xtensa | Wi-Fi + BLE、双核、性价比高 | 智能家居、IoT 网关 |
| ESP8266 | Xtensa | Wi-Fi、低成本 | 简单联网设备 |
| STM32 | ARM Cortex-M | 工业级、丰富外设 | 工业控制、机器人 |
| RP2040 | ARM Cortex-M0+ | Raspberry Pi Pico、双核 | 教育、原型开发 |
| nRF52840 | ARM Cortex-M4 | 低功耗 BLE | 可穿戴设备 |
3.3 MicroPython 架构
硬件层
MicroPython 架构
Python 源代码
编译器
mpy-cross
字节码虚拟机
运行时系统
硬件抽象层
HAL
ESP32
STM32
RP2040
3.4 安装 MicroPython
以 ESP32 为例,安装 MicroPython 固件:
bash
# 安装 esptool
pip install esptool
# 擦除原有固件
esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash
# 烧录 MicroPython 固件
esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 \
write_flash -z 0x1000 esp32-20240105-v1.22.1.bin
# 连接 REPL
picocom /dev/ttyUSB0 -b 115200
成功连接后,你将看到 MicroPython 的交互式提示符:
MicroPython v1.22.1 on 2024-01-05; ESP32 module with ESP32
Type "help()" for more information.
>>>
4. CircuitPython 深度解析
4.1 CircuitPython 简介
CircuitPython 是 Adafruit 基于 MicroPython 开发的分支,专注于教育友好和初学者体验。它简化了许多底层概念,提供了更直观的 API 和更丰富的文档支持。
CircuitPython 与 MicroPython 的主要区别:
| 特性 | MicroPython | CircuitPython |
|---|---|---|
| 目标用户 | 专业开发者、嵌入式工程师 | 初学者、教育场景 |
| API 风格 | 更接近底层硬件 | 更高级、更易用 |
| 库支持 | 通用库为主 | 600+ 硬件驱动库 |
| 开发体验 | REPL + 文件上传 | USB 虚拟磁盘,直接编辑 |
| 文档 | 官方文档 + 社区 | 详尽教程 + 学习指南 |
| 社区 | 全球开源社区 | Adafruit 社区驱动 |
4.2 CircuitPython 的独特优势
USB 虚拟磁盘开发模式:
CircuitPython 最具创新性的特性是其 USB 虚拟磁盘开发模式。连接电脑后,设备会显示为一个 USB 驱动器,你只需将 code.py 文件拖入其中,代码就会自动执行。
CIRCUITPY/
├── code.py # 主程序,自动执行
├── lib/ # 第三方库
│ ├── adafruit_dht/
│ └── adafruit_display/
├── boot.py # 启动配置
└── settings.toml # 系统设置
丰富的库生态系统:
CircuitPython 提供了超过 600 个预编译的库,覆盖各种传感器、显示器、通信模块:
python
# 使用 DHT 温湿度传感器
import adafruit_dht
import board
dht = adafruit_dht.DHT22(board.D2)
temperature = dht.temperature
humidity = dht.humidity
# 使用 OLED 显示器
import adafruit_ssd1306
import displayio
display = adafruit_ssd1306.SSD1306(displayio.I2CDisplay(board.I2C()))
display.text("Hello!", 0, 0, 1)
display.show()
4.3 支持的硬件平台
CircuitPython 支持超过 600 种开发板,主要包括:
| 平台 | 代表开发板 | 特点 |
|---|---|---|
| ESP32-S2/S3 | Feather ESP32-S2 | Wi-Fi、原生 USB |
| ESP32-C3 | QT Py ESP32-C3 | 低成本、RISC-V |
| RP2040 | Raspberry Pi Pico | 双核、性价比高 |
| SAMD21/SAMD51 | Feather M4 | ARM Cortex、高性能 |
| nRF52840 | Feather nRF52840 | BLE、低功耗 |
5. 微控制器编程核心概念
5.1 GPIO 控制
GPIO(通用输入输出)是微控制器与外部世界交互的基础接口。以下示例展示如何使用 MicroPython 控制 LED:
python
# MicroPython GPIO 示例
from machine import Pin
import time
# 创建 LED 对象(输出模式)
led = Pin(2, Pin.OUT) # ESP32 内置 LED 通常在 GPIO 2
# 点亮 LED
led.on() # 或 led.value(1)
# 熄灭 LED
led.off() # 或 led.value(0)
# LED 闪烁
while True:
led.on()
time.sleep(0.5)
led.off()
time.sleep(0.5)
CircuitPython 版本:
python
# CircuitPython GPIO 示例
import board
import digitalio
import time
# 创建 LED 对象
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
# LED 闪烁
while True:
led.value = True
time.sleep(0.5)
led.value = False
time.sleep(0.5)
5.2 PWM 输出
PWM(脉冲宽度调制)用于控制 LED 亮度、电机速度等模拟量:
python
# MicroPython PWM 示例 - LED 呼吸灯
from machine import Pin, PWM
import time
# 创建 PWM 对象
led = PWM(Pin(2), freq=1000) # 1kHz 频率
# 呼吸灯效果
while True:
# 渐亮
for duty in range(0, 1024, 10):
led.duty(duty)
time.sleep(0.01)
# 渐暗
for duty in range(1023, -1, -10):
led.duty(duty)
time.sleep(0.01)
CircuitPython 版本:
python
# CircuitPython PWM 示例
import board
import pwmio
import time
# 创建 PWM 输出
led = pwmio.PWMOut(board.LED, frequency=1000, duty_cycle=0)
# 呼吸灯效果
while True:
# 渐亮
for i in range(0, 65536, 655):
led.duty_cycle = i
time.sleep(0.01)
# 渐暗
for i in range(65535, -1, -655):
led.duty_cycle = i
time.sleep(0.01)
5.3 传感器接口
5.3.1 I2C 传感器
I2C 是最常用的传感器接口协议,以下示例使用 BME280 温湿度气压传感器:
python
# MicroPython BME280 示例
from machine import Pin, I2C
import bme280 # 需要先上传 bme280.py 库
# 初始化 I2C
i2c = I2C(0, scl=Pin(22), sda=Pin(21), freq=400000)
# 创建传感器对象
bme = bme280.BME280(i2c=i2c)
# 读取数据
temperature, pressure, humidity = bme.read_compensated_data()
print(f"温度: {temperature:.1f}°C")
print(f"气压: {pressure/100:.1f} hPa")
print(f"湿度: {humidity:.1f}%")
CircuitPython 版本:
python
# CircuitPython BME280 示例
import board
import adafruit_bme280
# 创建 I2C 连接
i2c = board.I2C()
bme = adafruit_bme280.Adafruit_BME280_I2C(i2c)
# 读取数据
print(f"温度: {bme.temperature:.1f}°C")
print(f"气压: {bme.pressure:.1f} hPa")
print(f"湿度: {bme.relative_humidity:.1f}%")
5.3.2 SPI 显示器
以下示例驱动 SSD1306 OLED 显示器:
python
# MicroPython SSD1306 示例
from machine import Pin, SPI, I2C
import ssd1306
# 使用 I2C 接口
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
display = ssd1306.SSD1306_I2C(128, 64, i2c)
# 清屏
display.fill(0)
# 绘制文本
display.text("Hello IoT!", 0, 0, 1)
display.text("Temperature: 25C", 0, 16, 1)
display.text("Humidity: 60%", 0, 32, 1)
# 绘制图形
display.rect(0, 48, 128, 16, 1) # 矩形边框
display.fill_rect(2, 50, 60, 12, 1) # 填充进度条
# 显示更新
display.show()
5.4 中断处理
中断用于响应外部事件,无需轮询检测:
python
# MicroPython 中断示例 - 按键检测
from machine import Pin
import time
# 配置按键(内部上拉)
button = Pin(0, Pin.IN, Pin.PULL_UP)
led = Pin(2, Pin.OUT)
# 中断计数器
press_count = 0
def button_handler(pin):
"""按键中断处理函数"""
global press_count
press_count += 1
print(f"按键按下 {press_count} 次")
# 切换 LED 状态
led.value(not led.value())
# 配置下降沿中断
button.irq(trigger=Pin.IRQ_FALLING, handler=button_handler)
print("按下按键测试中断...")
# 主循环可以做其他事情
while True:
time.sleep(1)
6. 低功耗设计
6.1 功耗优化策略
对于电池供电的 IoT 设备,低功耗设计至关重要。以下是主要的优化策略:
低功耗设计
硬件层面
软件层面
通信层面
选择低功耗芯片
优化电源电路
使用低功耗传感器
睡眠模式
降低时钟频率
关闭未用外设
减少通信频率
数据压缩
批量传输
6.2 睡眠模式
MicroPython 支持多种睡眠模式:
| 模式 | 功耗 | 唤醒方式 | 适用场景 |
|---|---|---|---|
| Modem Sleep | ~15mA | 定时器 | Wi-Fi 间歇工作 |
| Light Sleep | ~0.8mA | 定时器、GPIO | 短期休眠 |
| Deep Sleep | ~10μA | 定时器、外部唤醒 | 长期休眠 |
Deep Sleep 示例:
python
# MicroPython Deep Sleep 示例
from machine import Pin, deepsleep, RTC
import time
# 配置唤醒源
rtc = RTC()
rtc.alarm((rtc.datetime()[4] + 60) % 86400, 0) # 60秒后唤醒
# 读取传感器数据
def read_sensors():
from machine import ADC
adc = ADC(Pin(34))
adc.atten(ADC.ATTN_11DB)
return adc.read()
# 主程序
print("唤醒,开始工作...")
# 读取并发送数据
data = read_sensors()
print(f"传感器数据: {data}")
# 在这里发送数据到服务器...
print("进入深度睡眠...")
# 进入深度睡眠 60 秒
deepsleep(60000) # 单位:毫秒
6.3 低功耗传感器读取
以下是一个完整的低功耗温度监测示例:
python
# 低功耗温度监测器
from machine import Pin, ADC, deepsleep
import time
class LowPowerSensor:
"""低功耗传感器管理类"""
def __init__(self, sensor_pin, power_pin=None):
self.sensor = ADC(Pin(sensor_pin))
self.sensor.atten(ADC.ATTN_11DB)
self.power_pin = None
if power_pin:
self.power_pin = Pin(power_pin, Pin.OUT)
self.power_pin.value(0) # 默认关闭
def power_on(self):
"""打开传感器电源"""
if self.power_pin:
self.power_pin.value(1)
time.sleep_ms(100) # 等待传感器稳定
def power_off(self):
"""关闭传感器电源"""
if self.power_pin:
self.power_pin.value(0)
def read(self):
"""读取传感器数据"""
self.power_on()
# 多次采样取平均
samples = []
for _ in range(10):
samples.append(self.sensor.read())
time.sleep_ms(10)
self.power_off()
return sum(samples) // len(samples)
# 使用示例
def main():
# 配置传感器(假设传感器由 GPIO 25 供电)
sensor = LowPowerSensor(sensor_pin=34, power_pin=25)
# 读取数据
raw_value = sensor.read()
# 转换为温度(假设使用 NTC 热敏电阻)
# 这里简化处理,实际需要根据传感器特性计算
temperature = (raw_value - 500) / 10 # 示例公式
print(f"温度: {temperature:.1f}°C")
# 如果温度异常,可以在这里发送警报
# 进入深度睡眠
print("进入睡眠...")
deepsleep(300000) # 5 分钟
if __name__ == "__main__":
main()
7. 网络通信
7.1 Wi-Fi 连接
ESP32 是 MicroPython 最常用的平台,内置 Wi-Fi 支持:
python
# MicroPython Wi-Fi 连接示例
import network
import time
def connect_wifi(ssid, password):
"""连接 Wi-Fi 网络"""
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print(f"连接到 {ssid}...")
wlan.connect(ssid, password)
# 等待连接
timeout = 10
while not wlan.isconnected() and timeout > 0:
print(".", end="")
time.sleep(1)
timeout -= 1
print()
if wlan.isconnected():
print("网络配置:")
print(f" IP: {wlan.ifconfig()[0]}")
print(f" 子网掩码: {wlan.ifconfig()[1]}")
print(f" 网关: {wlan.ifconfig()[2]}")
print(f" DNS: {wlan.ifconfig()[3]}")
return True
else:
print("连接失败")
return False
# 连接 Wi-Fi
connect_wifi("Your_SSID", "Your_Password")
7.2 HTTP 请求
连接网络后,可以进行 HTTP 通信:
python
# MicroPython HTTP 请求示例
import urequests
import ujson
def send_data_to_server(url, data):
"""发送数据到服务器"""
headers = {
'Content-Type': 'application/json'
}
try:
response = urequests.post(
url,
data=ujson.dumps(data),
headers=headers
)
print(f"响应状态: {response.status_code}")
print(f"响应内容: {response.text}")
response.close()
return True
except Exception as e:
print(f"请求失败: {e}")
return False
# 发送传感器数据
sensor_data = {
"device_id": "esp32_001",
"temperature": 25.5,
"humidity": 60.2,
"timestamp": "2024-01-15T10:30:00Z"
}
send_data_to_server("https://api.example.com/sensors", sensor_data)
7.3 MQTT 协议
MQTT 是 IoT 领域最常用的消息协议,轻量且高效:
python
# MicroPython MQTT 示例
from umqtt.simple import MQTTClient
import machine
import time
# MQTT 配置
MQTT_BROKER = "broker.example.com"
MQTT_PORT = 1883
MQTT_USER = "your_username"
MQTT_PASSWORD = "your_password"
DEVICE_ID = "esp32_sensor_001"
# 创建 MQTT 客户端
client = MQTTClient(
client_id=DEVICE_ID,
server=MQTT_BROKER,
port=MQTT_PORT,
user=MQTT_USER,
password=MQTT_PASSWORD
)
# 消息回调
def on_message(topic, msg):
"""收到消息时的回调函数"""
print(f"收到消息: {topic} -> {msg}")
# 解析命令
if msg == b"get_status":
# 发布状态
client.publish(
f"device/{DEVICE_ID}/status",
"online"
)
# 设置回调
client.set_callback(on_message)
# 连接服务器
client.connect()
print("已连接到 MQTT 服务器")
# 订阅主题
client.subscribe(f"device/{DEVICE_ID}/command")
# 主循环
while True:
# 发布传感器数据
import random
temperature = 20 + random.random() * 10
client.publish(
f"device/{DEVICE_ID}/temperature",
f"{temperature:.2f}"
)
print(f"已发布温度: {temperature:.2f}°C")
# 检查订阅消息
client.check_msg()
# 等待
time.sleep(10)
8. 实战项目:智能环境监测站
8.1 项目概述
下面我们构建一个完整的智能环境监测站,具备以下功能:
- 温湿度、气压监测
- OLED 实时显示
- 数据上传云端
- 低功耗运行
- 异常告警
8.2 硬件清单
| 组件 | 型号 | 功能 |
|---|---|---|
| 主控板 | ESP32 开发板 | 核心控制器 |
| 温湿度传感器 | BME280 | 温度、湿度、气压 |
| 显示器 | SSD1306 OLED | 数据显示 |
| 蜂鸣器 | 有源蜂鸣器 | 声音告警 |
| 电源 | 18650 电池 + TP4056 | 供电 |
8.3 接线图
蜂鸣器
SSD1306
BME280
ESP32
GPIO 21
SDA
GPIO 22
SCL
GPIO 25
蜂鸣器
3.3V
GND
SDA
SCL
VCC
GND
SDA
SCL
VCC
GND
IN
VCC
GND
8.4 完整代码实现
python
# smart_environment_monitor.py
# 智能环境监测站 - MicroPython 实现
from machine import Pin, I2C, PWM
import time
import network
import urequests
import ujson
import uasyncio as asyncio
# ==================== 配置区 ====================
WIFI_SSID = "Your_SSID"
WIFI_PASSWORD = "Your_Password"
API_URL = "https://api.example.com/sensors/upload"
DEVICE_ID = "env_monitor_001"
# 告警阈值
TEMP_HIGH = 35.0
TEMP_LOW = 10.0
HUMIDITY_HIGH = 80.0
HUMIDITY_LOW = 20.0
# 采样间隔(秒)
SAMPLE_INTERVAL = 60
UPLOAD_INTERVAL = 300 # 5分钟上传一次
# ==================== 硬件驱动 ====================
class BME280Driver:
"""BME280 温湿度气压传感器驱动"""
def __init__(self, i2c, address=0x76):
self.i2c = i2c
self.address = address
# 初始化传感器
self._write_reg(0xF2, 0x01) # 湿度过采样 x1
self._write_reg(0xF4, 0x27) # 温压过采样 x1,正常模式
self._write_reg(0xF5, 0xA0) # 待机 1000ms
# 读取校准参数
self._read_calibration()
def _write_reg(self, reg, value):
self.i2c.writeto_mem(self.address, reg, bytes([value]))
def _read_reg(self, reg, length=1):
return self.i2c.readfrom_mem(self.address, reg, length)
def _read_calibration(self):
"""读取工厂校准数据"""
data = self._read_reg(0x88, 24)
# 简化处理,实际需要完整解析校准参数
self.calib = data
def read(self):
"""读取传感器数据"""
data = self._read_reg(0xF7, 8)
# 解析原始数据(简化版本)
# 实际需要根据 BME280 数据手册进行完整计算
raw_temp = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
raw_press = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
raw_hum = (data[6] << 8) | data[7]
# 简化转换(实际需要使用校准参数)
temperature = raw_temp / 100.0 - 40
pressure = raw_press / 256.0
humidity = raw_hum / 1024.0 * 100
return {
'temperature': temperature,
'pressure': pressure,
'humidity': humidity
}
class OLEDDisplay:
"""SSD1306 OLED 显示驱动"""
def __init__(self, i2c, width=128, height=64, address=0x3C):
self.i2c = i2c
self.width = width
self.height = height
self.address = address
self.buffer = [0] * (width * height // 8)
self._init_display()
def _init_display(self):
"""初始化显示器"""
init_cmds = [
0xAE, # 关闭显示
0xD5, 0x80, # 设置时钟分频
0xA8, 0x3F, # 设置多路复用率
0xD3, 0x00, # 设置显示偏移
0x40, # 设置起始行
0x8D, 0x14, # 开启电荷泵
0x20, 0x00, # 设置内存地址模式
0xA1, # 段重映射
0xC8, # COM 输出扫描方向
0xDA, 0x12, # 设置 COM 引脚
0x81, 0xCF, # 设置对比度
0xD9, 0xF1, # 设置预充电周期
0xDB, 0x40, # 设置 VCOMH 电压
0xA4, # 全屏点亮关闭
0xA6, # 正常显示
0xAF, # 开启显示
]
for cmd in init_cmds:
self._write_cmd(cmd)
def _write_cmd(self, cmd):
self.i2c.writeto(self.address, bytes([0x00, cmd]))
def _write_data(self, data):
self.i2c.writeto(self.address, bytes([0x40] + list(data)))
def clear(self):
"""清屏"""
self.buffer = [0] * len(self.buffer)
self.show()
def text(self, string, x, y):
"""显示文本(简化版本)"""
# 实际需要实现字体渲染
pass
def show(self):
"""刷新显示"""
for page in range(8):
self._write_cmd(0xB0 + page)
self._write_cmd(0x00)
self._write_cmd(0x10)
self._write_data(self.buffer[page * 128:(page + 1) * 128])
class Buzzer:
"""蜂鸣器驱动"""
def __init__(self, pin):
self.pwm = PWM(Pin(pin), freq=1000, duty=0)
def beep(self, times=1, duration=100):
"""蜂鸣"""
for _ in range(times):
self.pwm.duty(512)
time.sleep_ms(duration)
self.pwm.duty(0)
time.sleep_ms(duration)
def alarm(self):
"""告警音"""
for _ in range(3):
self.pwm.freq(1000)
self.pwm.duty(512)
time.sleep_ms(200)
self.pwm.freq(2000)
time.sleep_ms(200)
self.pwm.duty(0)
# ==================== 网络模块 ====================
class NetworkManager:
"""网络管理器"""
def __init__(self, ssid, password):
self.ssid = ssid
self.password = password
self.wlan = network.WLAN(network.STA_IF)
self.wlan.active(True)
def connect(self):
"""连接 Wi-Fi"""
if self.wlan.isconnected():
return True
print(f"连接 Wi-Fi: {self.ssid}")
self.wlan.connect(self.ssid, self.password)
timeout = 20
while not self.wlan.isconnected() and timeout > 0:
time.sleep(1)
timeout -= 1
if self.wlan.isconnected():
print(f"已连接,IP: {self.wlan.ifconfig()[0]}")
return True
else:
print("连接失败")
return False
def is_connected(self):
return self.wlan.isconnected()
class DataUploader:
"""数据上传器"""
def __init__(self, api_url, device_id):
self.api_url = api_url
self.device_id = device_id
self.data_buffer = []
def add_data(self, data):
"""添加数据到缓冲区"""
data['device_id'] = self.device_id
data['timestamp'] = time.time()
self.data_buffer.append(data)
def upload(self):
"""上传缓冲区数据"""
if not self.data_buffer:
return True
try:
response = urequests.post(
self.api_url,
data=ujson.dumps({
'device_id': self.device_id,
'records': self.data_buffer
}),
headers={'Content-Type': 'application/json'}
)
if response.status_code == 200:
print(f"上传成功: {len(self.data_buffer)} 条记录")
self.data_buffer = []
return True
else:
print(f"上传失败: {response.status_code}")
return False
except Exception as e:
print(f"上传错误: {e}")
return False
# ==================== 主程序 ====================
class EnvironmentMonitor:
"""环境监测站主类"""
def __init__(self):
# 初始化 I2C
self.i2c = I2C(0, scl=Pin(22), sda=Pin(21), freq=400000)
# 初始化硬件
self.sensor = BME280Driver(self.i2c)
self.display = OLEDDisplay(self.i2c)
self.buzzer = Buzzer(25)
# 初始化网络
self.network = NetworkManager(WIFI_SSID, WIFI_PASSWORD)
self.uploader = DataUploader(API_URL, DEVICE_ID)
# 状态变量
self.last_upload_time = 0
self.alarm_active = False
def check_thresholds(self, data):
"""检查阈值告警"""
alarms = []
if data['temperature'] > TEMP_HIGH:
alarms.append(f"温度过高: {data['temperature']:.1f}°C")
elif data['temperature'] < TEMP_LOW:
alarms.append(f"温度过低: {data['temperature']:.1f}°C")
if data['humidity'] > HUMIDITY_HIGH:
alarms.append(f"湿度过高: {data['humidity']:.1f}%")
elif data['humidity'] < HUMIDITY_LOW:
alarms.append(f"湿度过低: {data['humidity']:.1f}%")
return alarms
def update_display(self, data):
"""更新显示"""
self.display.clear()
# 简化显示,实际需要实现文本渲染
print(f"""
╔══════════════════════════╗
║ 环境监测站 v1.0 ║
╠══════════════════════════╣
║ 温度: {data['temperature']:>6.1f}°C ║
║ 湿度: {data['humidity']:>6.1f}% ║
║ 气压: {data['pressure']:>6.1f}hPa ║
╠══════════════════════════╣
║ 网络: {'已连接' if self.network.is_connected() else '未连接':^8} ║
║ 缓存: {len(self.uploader.data_buffer):>3} 条 ║
╚══════════════════════════╝
""")
def run(self):
"""主循环"""
print("环境监测站启动...")
# 连接网络
self.network.connect()
while True:
try:
# 读取传感器数据
data = self.sensor.read()
print(f"传感器数据: {data}")
# 检查告警
alarms = self.check_thresholds(data)
if alarms:
print(f"⚠️ 告警: {alarms}")
self.buzzer.alarm()
# 更新显示
self.update_display(data)
# 缓存数据
self.uploader.add_data(data)
# 定时上传
current_time = time.time()
if current_time - self.last_upload_time >= UPLOAD_INTERVAL:
if self.network.is_connected():
self.uploader.upload()
self.last_upload_time = current_time
else:
self.network.connect()
# 等待下次采样
time.sleep(SAMPLE_INTERVAL)
except Exception as e:
print(f"错误: {e}")
time.sleep(5)
# 启动程序
if __name__ == "__main__":
monitor = EnvironmentMonitor()
monitor.run()
9. MicroPython vs CircuitPython 选择指南
9.1 对比总结
| 维度 | MicroPython | CircuitPython |
|---|---|---|
| 学习曲线 | 中等 | 简单 |
| 文档质量 | 良好 | 优秀 |
| 库丰富度 | 中等 | 丰富(600+) |
| 社区支持 | 全球社区 | Adafruit 社区 |
| 性能 | 较高 | 中等 |
| 底层控制 | 灵活 | 抽象化 |
| 开发体验 | REPL + 文件传输 | USB 虚拟磁盘 |
| 适用场景 | 专业项目、性能敏感 | 教育、快速原型 |
9.2 选择建议
是
否
教育/原型
商业产品
高性能
一般
Adafruit 开发板
ESP32/STM32
开始选择
是否初学者?
CircuitPython
项目类型?
性能需求?
MicroPython
硬件平台?
✅ 推荐 CircuitPython
✅ 推荐 MicroPython
10. 总结
Python 在边缘计算和 IoT 领域的应用正在快速发展。MicroPython 和 CircuitPython 为 Python 开发者打开了嵌入式世界的大门,让物联网开发变得更加简单和高效。
本文的核心要点如下:
-
边缘计算优势:低延迟、带宽节省、隐私保护、离线运行,使计算更靠近数据源头。
-
MicroPython 特点:精简高效的 Python 实现,支持多种硬件平台,适合专业嵌入式开发。
-
CircuitPython 特点:教育友好,USB 虚拟磁盘开发模式,丰富的库生态,适合初学者和快速原型。
-
核心编程概念:GPIO 控制、PWM 输出、传感器接口、中断处理,是微控制器编程的基础。
-
低功耗设计:睡眠模式、传感器电源管理、通信优化,是电池供电设备的关键技术。
-
网络通信:Wi-Fi 连接、HTTP 请求、MQTT 协议,让 IoT 设备能够互联互通。
思考题
- 在你的物联网项目中,哪些计算可以下沉到边缘端执行?
- 对于电池供电的设备,你会如何平衡采样频率和电池寿命?
- MicroPython 和 CircuitPython,哪个更适合你的下一个 IoT 项目?