ESP32 实战教程:做一个定时唤醒的低功耗 BLE 传感器
本文由 AI 协助整理。低功耗数值必须以整机实测为准,开发板上的 USB 转串口、稳压器、LED 和传感器都会增加耗电。深度睡眠唤醒后通常从启动流程重新开始,不能假设程序会从睡眠前下一行继续。

低功耗的核心不是“少 delay 一会儿”
一个电池传感器如果一直运行 WiFi、持续刷新屏幕和每秒打印串口,换再大的电池也会很快失去耐心。低功耗设计通常是另一种工作节奏:大部分时间睡眠,定时醒来读取传感器,短暂广播数据,然后再次进入深度睡眠。
本教程做一个 BLE 广播节点:每隔 60 秒唤醒,读取温湿度,广播一小段环境数据,保存启动计数,再睡眠。手机或网关不需要一直连接,只要在广播窗口扫描即可。
如果业务必须让手机随时连接,就不能把 BLE 连接和深度睡眠同时当成长期状态。低功耗蓝牙的“低功耗”不代表设备可以在睡眠时维持一个完整连接,设计时要先确定是广播型节点还是连接型设备。
先测整机,而不是只看芯片参数
测试对象应包括:ESP32 模组、开发板稳压器、USB 芯片、传感器、指示灯和电源模块。开发板插着 USB 测出来的电流,不能直接等同于最终电池产品。
记录至少三种状态:
- 唤醒采样时电流。
- BLE 广播时电流。
- 深度睡眠时电流。
如果每 60 秒醒来 2 秒,平均电流可以用分段能量估算;但电池寿命还会受到电池内阻、温度、稳压器静态电流和低电压保护影响。不要拿万用表普通电流档串上去就宣布得到了“精确待机功耗”,测量设备自身也可能改变系统。
硬件和广播数据
需要一块支持 BLE 的 ESP32、温湿度传感器和电池供电。广播数据可以放在 Manufacturer Data 或 Service Data 中。为了让手机工具容易查看,先采用文本或短字节结构;长期运行再优化为定长二进制。
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEAdvertising.h>
#include "esp_sleep.h"
RTC_DATA_ATTR uint32_t bootCount = 0;
constexpr uint64_t SLEEP_SECONDS = 60;
RTC_DATA_ATTR 让变量在深度睡眠唤醒后保留一部分状态,但它不是永久存储。长时间运行的累计计数若不能丢失,应考虑 NVS,并控制写入频率。
读取唤醒原因
void printWakeReason() {
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
switch (cause) {
case ESP_SLEEP_WAKEUP_TIMER:
Serial.println("Wake by timer");
break;
case ESP_SLEEP_WAKEUP_EXT0:
case ESP_SLEEP_WAKEUP_EXT1:
Serial.println("Wake by external GPIO");
break;
default:
Serial.println("Power-on or reset");
break;
}
}
每次唤醒都重新执行 setup()。把唤醒原因打印出来,有助于区分“正常定时醒来”和“电源抖动导致重启”。如果设备每隔一分钟都显示 power-on,先查供电和复位,而不是继续优化睡眠代码。
传感器初始化与采样
struct Sample {
float temperature;
float humidity;
bool valid;
};
Sample readSensor() {
Sample sample{};
// 替换为真实传感器读取。
sample.temperature = 24.6f;
sample.humidity = 52.8f;
sample.valid = isfinite(sample.temperature) &&
isfinite(sample.humidity) &&
sample.humidity >= 0.0f &&
sample.humidity <= 100.0f;
return sample;
}
传感器在深度睡眠期间是否需要断电,取决于模块。可以用 MOSFET 或负载开关控制传感器电源,但要考虑启动时间、稳定时间和 GPIO 上电状态。若只是为了省几百微安,却加入一个自身消耗同样电流的电源开关,账本会显得很幽默。
创建一次性 BLE 广播
void broadcastSample(const Sample& sample) {
BLEDevice::init("ESP32-LowPower");
BLEAdvertising* advertising = BLEDevice::getAdvertising();
BLEAdvertisementData data;
char text[80];
snprintf(text, sizeof(text),
"v=1;boot=%lu;t=%.1f;h=%.1f;ok=%d",
static_cast<unsigned long>(bootCount),
sample.temperature, sample.humidity,
sample.valid ? 1 : 0);
data.setManufacturerData(std::string(text));
advertising->setAdvertisementData(data);
advertising->start();
delay(1500); // 给扫描器留出发现窗口
advertising->stop();
BLEDevice::deinit(true);
}
广播窗口不宜无限延长。手机扫描通常不是持续监听,过短可能错过,过长又浪费电。实际项目可以根据扫描器周期、网关部署和环境干扰调整,并给数据增加设备短 ID、协议版本和序号。
不同 BLE 库版本对 setManufacturerData、广告对象生命周期和 deinit 的行为可能略有差异。编译时以当前 Arduino-ESP32 BLE 示例为准;如果设备长时间运行后内存异常,优先检查 BLE 对象是否每次唤醒都正确释放。
进入深度睡眠
void sleepNow() {
Serial.flush();
esp_sleep_enable_timer_wakeup(SLEEP_SECONDS * 1000000ULL);
Serial.printf("Sleep for %llu seconds\n",
static_cast<unsigned long long>(SLEEP_SECONDS));
esp_deep_sleep_start();
}
void setup() {
Serial.begin(115200);
delay(100);
++bootCount;
printWakeReason();
Sample sample = readSensor();
if (sample.valid) {
broadcastSample(sample);
}
sleepNow();
}
void loop() {}
进入深度睡眠后,loop() 不会像普通程序一样继续运行。唤醒后芯片重新启动,RTC_DATA_ATTR 变量是少量可保留状态,不是整个应用上下文。
增加外部 GPIO 唤醒
经典 ESP32 只有 RTC GPIO 才能用于某些深度睡眠唤醒模式,具体可用脚位随芯片不同。以 GPIO33 按键为例:
#include "driver/rtc_io.h"
constexpr gpio_num_t WAKE_PIN = GPIO_NUM_33;
void enableButtonWake() {
esp_sleep_enable_ext0_wakeup(WAKE_PIN, 1);
rtc_gpio_pulldown_en(WAKE_PIN);
rtc_gpio_pullup_dis(WAKE_PIN);
}
实际按键电路要避免悬空和抖动。按键唤醒后不要立刻再次进入睡眠,可以在启动阶段判断唤醒原因并进入配网、强制广播或校准模式。
广播数据中的时间和电池电压
低功耗节点很适合把电池电压放进广播,让网关提前发现电量下降:
id=env01;ver=1;seq=42;t=24.6;h=52.8;batt_mv=3970;ok=1
电池电压采样要考虑分压电阻、ADC 参考误差和采样时机。不要把 ADC 的一个原始值直接当成精确电量百分比。锂电池电压曲线也不是线性的,电量估算应结合电池类型、负载和校准数据。
低功耗调试方法
先让设备每 10 秒睡眠,确认唤醒原因、广播内容和计数都正确;再改成一分钟或更长。串口日志会唤醒或影响功耗测量,测待机时要减少串口输出并确认 USB 芯片仍是否供电。
每一轮记录:
- 唤醒时间。
- 传感器读取是否成功。
- 广播持续时长。
- 进入睡眠前电压。
- 睡眠电流和唤醒峰值。
如果平均功耗没有下降,优先检查是不是开发板上的电源 LED、USB-UART、传感器模块和稳压器仍在吃电。软件已经睡了,硬件邻居可能还在开派对。
常见问题
| 现象 | 优先检查 |
|---|---|
| 唤醒后计数归零 | 是否使用 RTC_DATA_ATTR,是否发生彻底掉电 |
| 广播搜不到 | 广播窗口、手机扫描间隔、BLE 对象释放 |
| 深睡眠电流很高 | 开发板外围、传感器、电源模块和 GPIO 状态 |
| 外部按键无法唤醒 | GPIO 是否为 RTC IO、上下拉和电平条件 |
| 传感器读数异常 | 上电稳定时间、供电控制和采样时机 |
| 时间间隔不准 | 睡眠计时误差、唤醒耗时和电源状态 |
总结
低功耗 BLE 传感器的工作方式是“醒来做事,完成就睡”。传感器采样、短暂广播、状态保存和唤醒配置都要围绕这个周期设计。
先测整机,确认广播窗口和数据格式,再优化传感器断电、NVS 写入与电量估算。深度睡眠不是把 delay() 换成一个函数,而是重新设计设备的生命周期。
参考资料
打赏
如果这篇学习记录对你有帮助,欢迎扫码支持后续整理。

打赏支持:王庆岩
浙公网安备 33010602011771号