边缘计算:Python在IoT中的应用

目 录

    • 摘要
    • [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 开发者打开了嵌入式世界的大门,让物联网开发变得更加简单和高效。

本文的核心要点如下:

  1. 边缘计算优势:低延迟、带宽节省、隐私保护、离线运行,使计算更靠近数据源头。

  2. MicroPython 特点:精简高效的 Python 实现,支持多种硬件平台,适合专业嵌入式开发。

  3. CircuitPython 特点:教育友好,USB 虚拟磁盘开发模式,丰富的库生态,适合初学者和快速原型。

  4. 核心编程概念:GPIO 控制、PWM 输出、传感器接口、中断处理,是微控制器编程的基础。

  5. 低功耗设计:睡眠模式、传感器电源管理、通信优化,是电池供电设备的关键技术。

  6. 网络通信:Wi-Fi 连接、HTTP 请求、MQTT 协议,让 IoT 设备能够互联互通。

思考题

  1. 在你的物联网项目中,哪些计算可以下沉到边缘端执行?
  2. 对于电池供电的设备,你会如何平衡采样频率和电池寿命?
  3. MicroPython 和 CircuitPython,哪个更适合你的下一个 IoT 项目?

参考资料

相关推荐
何双新6 分钟前
Odoo 技术演进全解析:从 Widget 到 Owl,从 Old API 到声明式 ORM
python
山川行33 分钟前
关于《项目C语言》专栏的总结
c语言·开发语言·数据结构·vscode·python·算法·visual studio code
星辰徐哥38 分钟前
C语言游戏开发:Pygame、SDL、OpenGL深度解析
c语言·python·pygame
xcLeigh1 小时前
Python入门:Python3基础练习题详解,从入门到熟练的 25 个实例(六)
开发语言·python·教程·python3·练习题
不懒不懒1 小时前
安装python3.9.7和pycharm-community-2022.3.2.exe以及linux
linux·ide·python·pycharm
Jasonakeke1 小时前
我的编程来时路
java·c++·python
Yvonne爱编码1 小时前
Java 中的 hashCode () 与 equals () 核心原理、契约规范、重写实践与面试全解
java·开发语言·数据结构·python·hash
HappyAcmen1 小时前
理解Python中的global与nonlocal
python
测试老哥2 小时前
Web自动化测试:Cypress 测试框架概述
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
曲幽2 小时前
FastAPI项目半夜报警吵醒你?聊聊告警这事儿怎么搞!
python·logging·fastapi·web·monitoring·webserver·health·uptimerobot