1. 从ESP32-C3到C5:为什么这颗新芯片值得你关注
如果你和我一样,玩过不少Seeed Studio的XIAO系列开发板,从最初的ESP32-C3到后来的ESP32-S3,那么当看到XIAO ESP32-C5这个名字时,第一反应可能就是:“又来了一个ESP32变种?” 但这次还真不一样。ESP32-C5这颗芯片,是乐鑫在2023年底正式推出的一个里程碑式产品,它最大的特点,也是我第一时间入手这块板子的原因,就是它首次在单颗芯片上同时集成了2.4GHz和5GHz双频Wi-Fi 6,以及蓝牙5.0。这意味着,在物联网项目里,我们终于有了一款原生支持5GHz Wi-Fi的、性价比极高的微控制器选项。
过去,如果你想在Arduino或者MicroPython项目里用上5GHz Wi-Fi,选择非常有限。要么是树莓派Pico W这类只支持2.4GHz的板子,要么就得用上更复杂、功耗更高的Linux单板机。ESP32-C5的出现,正好填补了这个空白。Seeed Studio的XIAO系列以其极致的紧凑尺寸(大约只有拇指指甲盖大小)和丰富的接口而闻名,这次把C5芯片做到这个尺寸里,可以说是“小身材,大能量”的典型代表。板子虽然小,但该有的都没少:USB-C接口用于供电和编程,一排排针脚引出了几乎所有的GPIO、I2C、SPI、UART等常用接口,甚至还有一个用户LED和一个可编程的RGB LED(NeoPixel)。
那么,为什么要在MicroPython的环境下玩这块板子呢?这就涉及到开发效率的问题。对于物联网原型开发、快速验证想法、或者教育场景,MicroPython的“交互式”和“脚本化”特性是无可比拟的。你不需要经历漫长的编译、烧录、重启循环,在REPL(交互式解释器)里敲一行代码,立刻就能看到结果。这对于调试传感器、测试网络连接、调整算法逻辑来说,效率提升不是一点半点。尤其是当你面对C5这颗支持新协议(Wi-Fi 6)的芯片时,用MicroPython可以让你更专注于网络功能的应用逻辑,而不是陷在底层C语言驱动和协议栈的配置细节里。这篇文章,我就结合自己把玩XIAO ESP32-C5和MicroPython的实际经历,从刷机、联网、到实际项目应用,给你捋一遍完整的流程和其中会遇到的各种“坑”。
2. 为XIAO ESP32-C5构建专属的MicroPython固件
拿到一块新的开发板,第一步往往不是直接写代码,而是准备“土壤”——也就是固件。对于ESP32-C5这样比较新的芯片,乐鑫官方的MicroPython主分支可能还没有完全合并所有支持,或者你需要一些特定的功能模块(比如更快的Wi-Fi连接、低功耗模式等)。因此,从源码编译一个量身定制的固件,通常是获得最佳体验的第一步。这个过程听起来有点硬核,但跟着步骤走一遍,其实并不复杂,而且能让你对MicroPython的构成有更深的理解。
2.1 搭建编译环境:Linux子系统是关键
首先,你需要一个Linux环境。在Windows上,最推荐的方式是使用WSL2(Windows Subsystem for Linux),我使用的是Ubuntu 22.04 LTS发行版。为什么不用虚拟机或者双系统?因为WSL2和Windows文件系统的互通性更好,后续操作起来更方便。打开Windows Terminal,创建一个新的Ubuntu会话,然后依次执行以下命令来安装必要的工具链:
sudo apt update sudo apt install -y git wget flex bison gperf python3 python3-pip python3-setuptools cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0这里安装的包括Git、Python3、CMake、Ninja(更快的构建系统)、以及ESP-IDF所需的各种库。其中dfu-util和libusb是为了后续通过USB烧录固件准备的。接下来,我们需要获取乐鑫的芯片支持包和工具链。ESP32-C5基于RISC-V架构,所以我们需要RISC-V的工具链。乐鑫提供了一个方便的脚本和下载工具:
mkdir -p ~/esp cd ~/esp git clone -b v5.1.4 --recursive https://github.com/espressif/esp-idf.git cd esp-idf ./install.sh esp32c5执行install.sh时会让你选择安装方式,对于MicroPython编译,我们通常只需要“最小化”安装,即只安装C5所需的工具链和基础库,这可以节省大量磁盘空间。安装完成后,记住要执行环境变量设置脚本:source export.sh(或者. ./export.sh)。这个操作需要在你每次打开新的终端窗口进行编译前执行。为了方便,你可以把source ~/esp/esp-idf/export.sh这行命令加到你的~/.bashrc文件末尾。
2.2 获取与配置MicroPython源码
环境准备好后,就可以拉取MicroPython的源码了。我们直接使用官方仓库的主分支,因为它对最新芯片的支持最及时。
cd ~ git clone https://github.com/micropython/micropython.git cd micropython git submodule update --init --recursive进入ESP32-C5的特定端口目录:
cd ports/esp32接下来是关键步骤:配置。MicroPython使用make来管理配置。我们需要指定目标板为ESP32-C5。但请注意,在MicroPython的端口目录中,板型定义可能还没有一个专门的“XIAO_ESP32C5”选项。通常,对于一款新芯片,我们可以先用其通用板型配置。查看boards/目录,你会发现有GENERIC_C5这样的目录。我们可以基于它来编译。编译命令很简单:
make BOARD=GENERIC_C5 clean make BOARD=GENERIC_C5make clean是为了确保之前可能存在的编译缓存被清除,避免奇怪的问题。第一条命令会清理,第二条命令则开始漫长的编译过程。这个过程可能会持续10到30分钟,取决于你的电脑性能。编译成功后,你会在build-GENERIC_C5/目录下找到我们需要的固件文件:firmware.bin。这个文件就是我们要烧录到XIAO ESP32-C5开发板里的MicroPython固件。
注意:如果你在编译过程中遇到关于“
esp_phy_init_data.bin”或类似分区表文件的错误,这通常是ESP-IDF版本与MicroPython源码的兼容性问题。一个可行的解决方法是,回到~/esp/esp-idf目录,检查当前使用的版本。MicroPython的esp32端口通常紧密跟踪ESP-IDF的某个发布版本。你可以尝试切换到ESP-IDF的v5.1.x或v5.2.x的某个稳定标签(如git checkout v5.1.4),然后重新运行install.sh并source export.sh。编译环境的不匹配是新手在此阶段最常见的绊脚石。
3. 烧录固件与首次连接:避开那些“坑”
有了firmware.bin,下一步就是把它放到板子里。XIAO ESP32-C5支持通过USB-C口直接进行串口下载,这非常方便。但这里有几个细节,如果没做对,你可能会对着一个毫无反应的板子发呆半天。
3.1 驱动安装与端口识别
将XIAO ESP32-C5通过USB-C线连接到电脑。对于Windows用户,系统通常会自动安装CH340或CP210x系列的USB转串口驱动(Seeed Studio常用这些芯片)。你可以在设备管理器的“端口(COM和LPT)”下查看是否出现了一个新的COM口,比如“USB-SERIAL CH340 (COM3)”。如果出现黄色感叹号,你需要手动安装驱动,可以去Seeed Studio的Wiki页面或芯片厂商(如沁恒)官网下载。
在Linux(包括WSL2)下,情况稍微特殊一点。板子会被识别为/dev/ttyACM0或/dev/ttyUSB0这样的设备。但是,WSL2默认并不能直接访问Windows的USB设备。我们需要在Windows端安装一个叫usbipd的工具,并将USB设备“附加”到WSL2中。具体步骤如下:
- 在Windows上,以管理员身份打开PowerShell,安装
usbipd:winget install --interactive --exact dorssel.usbipd-win - 在PowerShell中列出USB设备:
usbipd list。找到你的XIAO板子(通常描述里会有“USB Serial”或“CP210x”字样),记下它的总线ID。 - 将设备附加到WSL2:
usbipd attach --wsl --busid <总线ID>。例如:usbipd attach --wsl --busid 1-2 - 回到WSL2的Ubuntu终端,现在你应该能看到
/dev/ttyACM0设备了。你需要将当前用户添加到dialout组以获得串口访问权限:sudo usermod -a -G dialout $USER。执行此命令后,必须完全退出WSL2终端再重新进入,用户组变更才会生效。
3.2 使用esptool.py进行烧录
MicroPython源码目录里自带了一个强大的烧录工具——esptool.py。我们回到编译固件的位置,执行烧录命令。在烧录前,板子需要进入“下载模式”。对于XIAO ESP32-C5,这通常通过快速双击板载的“RST”按钮(或标有“BOOT”的按钮)来实现。你会看到板载的RGB LED进入慢闪状态,表示已准备好。
假设我们的串口设备在Linux下是/dev/ttyACM0,在Windows下是COM3,烧录命令如下:
# Linux/WSL2 示例 cd ~/micropython/ports/esp32 esptool.py --chip esp32c5 --port /dev/ttyACM0 erase_flash esptool.py --chip esp32c5 --port /dev/ttyACM0 --baud 460800 write_flash -z 0x0 build-GENERIC_C5/firmware.bin# Windows PowerShell 示例 (需在ESP-IDF环境或已安装esptool的环境下运行) esptool.py --chip esp32c5 --port COM3 erase_flash esptool.py --chip esp32c5 --port COM3 --baud 460800 write_flash -z 0x0 firmware.bin命令解释:
--chip esp32c5: 指定芯片型号,这很重要,不同芯片的通信协议有差异。--port: 指定你的串口设备。erase_flash:强烈建议先擦除整个Flash,特别是从Arduino环境或其他固件切换过来时,避免残留数据导致异常。--baud 460800: 提高烧录波特率可以显著加快速度。如果连接不稳定,可以尝试降低到921600或115200。write_flash -z 0x0: 从Flash的0x0偏移地址开始写入固件。
烧录过程中,终端会有进度条显示。成功后,按一下板子的“RST”按钮重启。此时,MicroPython固件就开始运行了。
3.3 连接REPL:你的第一个交互窗口
固件运行后,我们需要一个终端工具连接到板子的REPL。推荐使用picocom(Linux)或PuTTY、Arduino IDE的串口监视器(Windows)。以picocom为例:
picocom -b 115200 /dev/ttyACM0连接成功后,按一下回车键,你应该会看到MicroPython的提示符>>>。恭喜,你已经成功进入了MicroPython的世界!你可以尝试输入一些简单的命令,比如print(“Hello, XIAO C5!”)或者import machine来测试。如果看到输出,说明一切正常。
实操心得:烧录后第一次连接REPL,如果没有任何反应,或者输出乱码,请按以下顺序排查:1) 确认串口号是否正确;2) 确认波特率是否为115200;3) 确认板子是否已重启(按RST键);4) 检查USB线是否只供电而无数据功能(换条线试试);5) 在WSL2下,确认是否已正确执行
usbipd attach且未超时断开。最稳妥的方法是,在Windows下用PuTTY等工具先测试连通性,排除WSL2配置的问题。
4. 点亮双频Wi-Fi:连接5GHz网络实战
让ESP32-C5连接Wi-Fi,是检验其核心特性的第一步。MicroPython提供了network模块来管理网络连接,使用起来非常直观。但连接5GHz网络时,有一个小细节需要注意。
4.1 基础连接代码与网络扫描
我们先写一个简单的脚本,并将其保存到板子的文件系统中。在REPL中,我们可以直接输入多行代码,但更常用的方式是使用文件工具。我们可以用ampy(Adafruit MicroPython Tool)这个Python库来管理文件。首先在电脑上安装:pip install adafruit-ampy。
然后,创建一个名为boot.py或main.py的文件(boot.py会在每次启动时自动运行)。我们创建一个wifi_connect.py用于测试:
# wifi_connect.py import network import time # 创建WLAN接口对象,STA模式表示作为客户端连接路由器 wlan = network.WLAN(network.STA_IF) wlan.active(True) # 激活接口 # 扫描附近的Wi-Fi网络 print("Scanning for networks...") scan_results = wlan.scan() for network_info in scan_results: ssid = network_info[0].decode('utf-8') # SSID是字节串,需要解码 bssid = network_info[1].hex() # MAC地址 channel = network_info[2] rssi = network_info[3] authmode = network_info[4] hidden = network_info[5] # 特别标注5GHz网络(通常信道大于36) band = "5GHz" if channel > 36 else "2.4GHz" print(f"SSID: {ssid:20} BSSID: {bssid} Channel: {channel:3} ({band}) RSSI: {rssi:4} dBm")使用ampy将这个脚本发送到板子并运行:
ampy --port /dev/ttyACM0 put wifi_connect.py ampy --port /dev/ttyACM0 run wifi_connect.py在输出中,你应该能看到你周围的Wi-Fi网络列表,并且能根据信道区分出2.4GHz和5GHz网络。这是验证C5射频功能正常的好方法。
4.2 连接5GHz网络的核心参数配置
接下来是连接。连接5GHz网络与2.4GHz在代码上几乎一样,但确保你的路由器5GHz网络没有启用“隐藏SSID”,并且最好使用WPA2-PSK(AES)加密方式,这是兼容性最广的。
# 继续在wifi_connect.py中追加,或新建一个连接函数 def connect_to_wifi(ssid, password): if not wlan.isconnected(): print(f‘Connecting to {ssid}...’) wlan.connect(ssid, password) # 等待连接,最多10秒 max_wait = 10 while max_wait > 0: if wlan.isconnected(): break max_wait -= 1 print(‘Waiting for connection...’) time.sleep(1) if wlan.isconnected(): print(‘Network connected!’) status = wlan.ifconfig() print(‘IP address:’, status[0]) print(‘Subnet mask:’, status[1]) print(‘Gateway:’, status[2]) print(‘DNS server:’, status[3]) return True else: print(‘Connection failed.’) return False # 替换为你的5GHz网络信息 connect_to_wifi(‘Your_5GHz_SSID‘, ’Your_Password‘)将上述代码合并到文件中,再次运行。如果一切顺利,你会看到获取到的IP地址信息。这里有个关键点:wlan.connect()是一个非阻塞调用,它发起连接后就返回了,所以我们需要一个循环来等待连接成功。等待时间不宜过短,因为5GHz网络的协商可能比2.4GHz稍慢一点。
4.3 处理连接失败与稳定性优化
连接失败怎么办?首先,检查密码是否正确。其次,在REPL中检查是否有更详细的错误信息,可以尝试wlan.status()来获取状态码。常见的状态码有:
1000: STAT_IDLE, 未连接。1001: STAT_CONNECTING, 正在连接。1010: STAT_GOT_IP, 已连接并获取到IP(成功)。- 其他如
202,203等通常表示密码错误或网络未找到。
为了提高连接稳定性,特别是在信号边缘区域,可以加入重连逻辑和信号强度检查:
import network import time import machine def connect_with_retry(ssid, password, retries=5): wlan = network.WLAN(network.STA_IF) wlan.active(True) for attempt in range(retries): if not wlan.isconnected(): print(f‘Attempt {attempt+1}/{retries} to connect...’) wlan.connect(ssid, password) for _ in range(15): # 等待15秒 if wlan.isconnected(): break time.sleep(1) if wlan.isconnected(): print(f‘Connected on attempt {attempt+1}’) print(‘IP:’, wlan.ifconfig()[0]) # 连接成功后,可以进入深度睡眠或执行主任务 return True else: print(‘Failed. Will retry...’) time.sleep(3) # 失败后等待3秒再试 print(‘Max retries reached. Connection failed.’) # 可以选择重启或进入深度睡眠 # machine.deepsleep(10000) # 睡眠10秒 return False # 在boot.py中调用,实现上电自动连接 connect_with_retry(‘Your_5GHz_SSID‘, ’Your_Password‘)注意事项:在实际部署中,将SSID和密码硬编码在代码中是不安全的。一种常见的做法是,在首次启动时,让设备进入“配网模式”(如开启一个AP热点),通过网页或手机App配置网络信息,然后将这些信息保存到板载的Flash文件系统(如
network.json)中。后续启动时,从文件读取配置进行连接。这涉及到更复杂的Web服务器或蓝牙配网逻辑,是产品化项目中必备的一环。
5. 深度探索:MicroPython下的外设驱动与低功耗实践
连接网络只是开始,XIAO ESP32-C5的GPIO、ADC、I2C、SPI等外设才是与物理世界交互的桥梁。同时,作为物联网设备,功耗管理至关重要。我们来看看在MicroPython下如何操作。
5.1 GPIO控制与中断:从点亮LED到响应按键
控制板载的LED是最简单的开始。XIAO ESP32-C5的用户LED通常连接在一个固定的GPIO上(需要查看原理图,假设是GPIO2),而RGB LED则通常通过一个GPIO控制WS2812B灯珠。
import machine import neopixel import time # 控制单色用户LED (假设接在GPIO2) led_pin = machine.Pin(2, machine.Pin.OUT) led_pin.value(1) # 点亮, 0为熄灭 # 控制板载RGB LED (假设数据线接在GPIO8, 只有1颗灯珠) np = neopixel.NeoPixel(machine.Pin(8), 1) np[0] = (255, 0, 0) # 设置为红色 (R, G, B) np.write() # 写入数据才能生效 time.sleep(1) np[0] = (0, 255, 0) # 绿色 np.write()GPIO中断对于检测按键、传感器信号边沿非常有用。下面是一个按键消抖的中断示例:
import machine import time button_pin = machine.Pin(3, machine.Pin.IN, machine.Pin.PULL_UP) # 假设按键接GPIO3, 内部上拉 debounce_time = 0 last_press_time = 0 def button_handler(pin): global last_press_time current_time = time.ticks_ms() # 消抖处理:忽略200毫秒内的连续触发 if time.ticks_diff(current_time, last_press_time) > 200: last_press_time = current_time print(‘Button pressed! Pin state:’, pin.value()) # 按下通常是低电平0 # 配置中断,下降沿触发(按键按下从高电平到低电平) button_pin.irq(trigger=machine.Pin.IRQ_FALLING, handler=button_handler) print(‘Waiting for button press...’) while True: time.sleep(1) # 主循环可以执行其他任务5.2 I2C与SPI通信:连接传感器与屏幕
XIAO的排针引出了I2C和SPI接口,使得连接各种传感器模块(温湿度、气压、光强)和显示模块(OLED)变得非常容易。
I2C扫描与读取传感器(以BMP280气压传感器为例):
import machine import time from machine import I2C, Pin import bmp280 # 假设你已经将bmp280.py库上传到板子 # 初始化I2C, 引脚根据XIAO的引脚定义(通常SDA=GPIO4, SCL=GPIO5) i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000) # I2C总线0, 速率400kHz # 扫描I2C总线上的设备 devices = i2c.scan() if devices: for d in devices: print(‘Found I2C device at address: 0x{:02X}’.format(d)) else: print(‘No I2C devices found’) # 初始化BMP280传感器 sensor = bmp280.BMP280(i2c) while True: temp = sensor.temperature pressure = sensor.pressure print(‘Temperature: {:.2f} C’.format(temp)) print(‘Pressure: {:.2f} hPa’.format(pressure/100)) # 转换为百帕 time.sleep(2)SPI驱动OLED屏幕(以SSD1306为例):
import machine import time from machine import Pin, SPI import ssd1306 # 需要ssd1306.py库 # 初始化SPI, XIAO ESP32-C5的SPI引脚需要查手册确认,以下为示例 spi = SPI(1, baudrate=10000000, polarity=0, phase=0, sck=Pin(10), mosi=Pin(11), miso=Pin(12)) # HSPI dc_pin = Pin(9, Pin.OUT) # 数据/命令选择引脚 res_pin = Pin(8, Pin.OUT) # 复位引脚 cs_pin = Pin(7, Pin.OUT) # 片选引脚(如果模块有) # 初始化OLED (128x64) oled = ssd1306.SSD1306_SPI(128, 64, spi, dc_pin, res_pin, cs_pin) # 清屏并显示文字 oled.fill(0) # 清屏(0为黑色,1为亮) oled.text(‘Hello XIAO C5!’, 0, 0, 1) oled.text(‘Wi-Fi 6 Ready’, 0, 16, 1) oled.show()经验技巧:MicroPython的I2C和SPI驱动有时会遇到时序问题。如果传感器读不出数据或屏幕不亮,首先检查:1) 引脚定义是否正确;2) 电源是否接好(3.3V);3) 上拉电阻是否需要(I2C总线通常需要4.7kΩ上拉电阻,但很多模块已集成);4) 尝试降低通信频率(如I2C从400kHz降到100kHz)。对于没有现成MicroPython库的传感器,你需要根据其数据手册,使用
i2c.readfrom()和i2c.writeto()函数来手动实现读写协议,这是一个很好的学习过程。
5.3 低功耗模式初探:让设备跑得更久
物联网设备很多是电池供电,低功耗设计是必修课。ESP32-C5支持多种低功耗模式,在MicroPython中,最常用的是lightsleep(浅睡眠)和deepsleep(深度睡眠)。
深度睡眠 (Deep Sleep):在此模式下,CPU、大部分RAM和所有外设都会断电,仅由RTC(实时时钟)模块维持极低功耗的运行。设备只能通过特定的唤醒源(如定时器、外部引脚)唤醒,唤醒后程序从头开始执行(相当于复位)。这是最省电的模式。
import machine import time # 配置唤醒源:使用RTC定时器,单位微秒 (10秒后唤醒) rtc = machine.RTC() sleep_time_ms = 10 * 1000 # 10秒 rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP) rtc.alarm(rtc.ALARM0, sleep_time_ms) print(‘Going into deep sleep for 10 seconds...’) time.sleep(0.1) # 给串口一点时间输出信息 machine.deepsleep() # 进入深度睡眠 # 此行之后的代码在唤醒前不会执行浅睡眠 (Light Sleep):CPU暂停,但RAM和部分外设保持供电,网络连接可能断开(取决于配置)。唤醒速度比深度睡眠快,功耗介于运行和深度睡眠之间。在MicroPython中,可以通过machine.lightsleep()函数进入,但唤醒源配置相对复杂,通常需要结合网络事件或引脚中断。
一个实用的低功耗场景是:传感器每5分钟采集一次数据并通过Wi-Fi上传。那么工作流程可以是:上电 -> 连接Wi-Fi -> 读取传感器 -> 发送数据 -> 进入深度睡眠5分钟 -> 被定时器唤醒 -> 重复。这样,设备99%的时间都在深度睡眠中,功耗可以低至10微安级别,两节AA电池可以工作数月甚至数年。
避坑指南:深度睡眠时,GPIO的状态会丢失。如果你需要某个GPIO在睡眠期间保持高电平或低电平(例如控制一个MOSFET开关),你需要使用具有“锁存”或“保持”功能的GPIO,或者外接一个锁存电路。此外,深度睡眠后唤醒,所有变量都会丢失。如果你需要保存一些状态(比如传感器数据的序列号),必须将其存入RTC内存(
rtc.memory())或Flash文件系统中。另外,注意machine.deepsleep()不会返回,设备直接进入睡眠。所以任何想在睡眠前执行的清理工作(如断开网络、关闭外设电源)都必须在这条语句之前完成。
6. 项目实战:构建一个5GHz Wi-Fi环境监测器
理论说得再多,不如动手做一个项目。我们来整合前面学到的知识,构建一个简单的环境监测器,它通过5GHz Wi-Fi将温湿度和气压数据定时发送到网络服务器(这里以HTTP POST到一个测试接口为例)。
6.1 硬件连接与项目规划
所需材料:
- Seeed Studio XIAO ESP32-C5 开发板
- BME280传感器模块(集成温湿度气压,I2C接口)
- 面包板和杜邦线若干
连接方式:
- BME280的VCC -> XIAO的3.3V
- BME280的GND -> XIAO的GND
- BME280的SCL -> XIAO的GPIO5 (I2C SCL)
- BME280的SDA -> XIAO的GPIO4 (I2C SDA)
项目逻辑:
- 设备上电,从文件系统读取Wi-Fi配置。
- 连接5GHz Wi-Fi网络。
- 初始化BME280传感器。
- 进入主循环:读取传感器数据 -> 封装为JSON格式 -> 通过HTTP POST发送到服务器 -> 打印结果到REPL -> 进入深度睡眠10分钟 -> 被定时器唤醒,重复步骤4。
6.2 代码实现:整合网络、传感器与低功耗
首先,我们需要将BME280的MicroPython驱动库(bme280.py)上传到板子。然后创建主程序文件main.py。
# main.py import network import machine import time import json import urequests as requests from machine import I2C, Pin, RTC import bme280 # 确保bme280.py已上传 import uos # ===== 1. 读取Wi-Fi配置(简化版,实际应用建议用配网) ===== def load_config(): # 尝试从config.json文件读取配置 try: with open(‘/config.json’, ‘r’) as f: config = json.loads(f.read()) return config.get(‘ssid’, ‘’), config.get(‘password’, ‘’) except: # 如果文件不存在,返回硬编码的配置(仅用于测试) print(‘Config file not found, using hardcoded config.’) return ‘Your_5GHz_SSID‘, ’Your_Password‘ # ===== 2. Wi-Fi连接函数(带重试) ===== def connect_wifi(ssid, password): wlan = network.WLAN(network.STA_IF) wlan.active(True) if not wlan.isconnected(): print(‘Connecting to Wi-Fi...’) wlan.connect(ssid, password) for _ in range(20): # 最多等待20秒 if wlan.isconnected(): break time.sleep(1) if wlan.isconnected(): print(‘Wi-Fi connected! IP:’, wlan.ifconfig()[0]) return True else: print(‘Wi-Fi connection failed!’) return False # ===== 3. 传感器数据读取 ===== def read_sensor_data(): # 初始化I2C和BME280 i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=100000) sensor = bme280.BME280(i2c=i2c) # 读取数据,BME280库通常返回字符串 temp, press, hum = sensor.values # 转换为浮点数,并简单处理单位 temperature = float(temp[:-1]) # 去掉末尾的’C‘ pressure = float(press[:-3]) # 去掉末尾的’hPa‘, 假设单位是百帕 humidity = float(hum[:-1]) # 去掉末尾的’%‘ return {‘temperature’: temperature, ‘pressure’: pressure, ‘humidity’: humidity} # ===== 4. 数据上传函数 ===== def upload_data(data_dict, server_url): try: # 将字典转换为JSON字符串 json_data = json.dumps(data_dict) headers = {‘Content-Type’: ‘application/json’} # 发送HTTP POST请求 response = requests.post(server_url, data=json_data, headers=headers) print(‘Upload Response:’, response.status_code, response.text) response.close() # 重要:关闭响应,释放资源 return response.status_code == 200 except Exception as e: print(‘Upload failed:’, e) return False # ===== 5. 主程序 ===== def main(): print(‘=== XIAO ESP32-C5 Environmental Monitor ===’) # 加载配置并连接Wi-Fi ssid, password = load_config() if not connect_wifi(ssid, password): # 连接失败,可能进入深度睡眠一段时间再试 print(‘Wi-Fi failed. Sleeping for 1 minute.’) rtc = machine.RTC() rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP) rtc.alarm(rtc.ALARM0, 60 * 1000) # 1分钟 machine.deepsleep() return # 深度睡眠后程序重启,会再次执行 # 读取传感器数据 print(‘Reading sensor data...’) sensor_data = read_sensor_data() print(‘Data:’, sensor_data) # 上传数据(替换为你的服务器URL) server_url = ‘http://your-server.com/api/sensor-data‘ upload_success = upload_data(sensor_data, server_url) if upload_success: print(‘Data uploaded successfully.’) else: print(‘Data upload failed.’) # 任务完成,进入深度睡眠10分钟 print(‘Going into deep sleep for 10 minutes...’) sleep_duration_minutes = 10 rtc = machine.RTC() rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP) rtc.alarm(rtc.ALARM0, sleep_duration_minutes * 60 * 1000) # 转换为毫秒 # 可选:关闭Wi-Fi以节省最后一点功耗(虽然深度睡眠会断掉) network.WLAN(network.STA_IF).active(False) time.sleep(0.1) # 等待一下 machine.deepsleep() # ===== 程序入口 ===== if __name__ == ‘__main__’: main()6.3 部署、测试与优化
将上述代码保存为main.py,连同bme280.py库文件,使用ampy上传到板子:
ampy --port /dev/ttyACM0 put bme280.py ampy --port /dev/ttyACM0 put main.py上传完成后,按一下板子的RST键重启。你会看到程序开始运行:尝试连接Wi-Fi,读取传感器数据,并尝试上传。由于我们没有真实的服务器URL,上传会失败,但你可以观察REPL中的打印信息,确认传感器读取和网络连接部分是否正常。
优化方向:
- 增加配网功能:如前所述,硬编码Wi-Fi密码不安全也不灵活。可以实现一个“SmartConfig”或“蓝牙配网”功能,让设备在首次启动时进入配网模式。
- 数据缓存与重传:在网络不佳时,上传可能失败。可以将数据暂存到Flash文件系统中,等网络恢复后重传。
- 功耗精细管理:在进入深度睡眠前,确保所有外设(如I2C传感器)都处于最低功耗状态。有些传感器有睡眠模式命令。
- 使用MQTT替代HTTP:对于频繁上报的物联网数据,MQTT协议比HTTP更轻量、更高效。MicroPython有
umqtt.simple库可以使用。 - 电源管理:如果使用电池供电,需要监测电池电压。XIAO ESP32-C5的某个ADC引脚可以通过分压电阻连接电池,在代码中定期检测电压,在电压过低时上报报警信息。
这个项目虽然简单,但涵盖了从硬件连接到网络通信,再到低功耗管理的物联网核心环节。通过修改传感器类型、上报频率和服务器逻辑,你可以将其改造成土壤湿度监测器、空气质量检测站,甚至是远程控制开关。XIAO ESP32-C5的双频Wi-Fi能力,尤其适合部署在2.4GHz频段拥挤(如智能家居设备众多)但5GHz信号良好的环境中,能提供更稳定、延迟更低的数据连接。