欢迎光临
我们一直在努力

《WiFi 嵌入式物联网开发全套实战》| 第 20 章 WiFi 低功耗休眠、定时唤醒、保活机制(电池设备必备)

专栏:《WiFi 嵌入式物联网开发全套实战》 专栏定位:嵌入式 Linux/ESP32 WiFi 从原理→驱动→配网→协议→稳定性→抓包调试→量产优化全套工业实战 适配:物联网设备、智能家居、工控网关、无线透传设备、4G+WiFi 双模设备 💖 点赞 + 收藏 + 关注,嵌入式 WiFi 量产实战全套教程持续更新!

本章前言

前面章节我们开发的 ESP32 WiFi 工程,全部为常开模式,WiFi 射频持续工作,功耗几百毫安,只适合插电设备。 对于电池供电物联网产品:电池传感器、无线门锁、电池摄像头,产品要求电池工作数月甚至数年,必须开启 WiFi 低功耗模式。

ESP32 WiFi 提供 Modem‑sleep、Light‑sleep、Deep‑sleep 三级休眠方案。大量开发者踩坑:休眠之后 WiFi 断开、唤醒无法重连 AP、休眠丢包、MQTT 掉线、唤醒网络延时大、电流降不下来、休眠功耗不稳定、定时唤醒抖动。

休眠不是简单调用 sleep 接口,需要理解 WiFi‑PS(Power Save)802.11 省电协议,AP 与 STA 之间的休眠交互机制。本章对比三级休眠模式,讲解 WiFi‑PS 信标监听、DTIM、Listen Interval 核心概念;给出可直接编译完整工程,包含定时唤醒、休眠进入退出、唤醒 WiFi 恢复、MQTT 保活;梳理量产电池设备高频坑点,给出功耗测试方法与调优方案。

前置阅读:第 14 章 STA 掉线恢复、第 19 章 MQTT 物联网上云完整工程。

20.1 ESP32 三类休眠模式对比

休眠模式CPUWiFi / 蓝牙RAM唤醒源典型休眠电流适用场景
Modem‑sleep(调制解调器休眠) 运行 WiFi 射频间歇休眠 全部保持 定时器、IO ~15‑40mA CPU 业务持续运行,WiFi 间歇省电,不适合电池产品
Light‑sleep(轻度休眠) 暂停 WiFi 可开启 WiFi‑PS 间歇收 Beacon RAM 保持 定时器、IO、RTC ~0.8‑3mA 电池 WiFi 设备主流方案,唤醒速度快,WiFi 可维持连接
Deep‑sleep(深度休眠) 断电 WiFi 完全关闭 仅 RTC 内存保留 RTC 定时器、IO ~10‑80μA 极低功耗,但 WiFi 完全断开,每次唤醒需要重新配网重连路由

工程选型结论

  • 需要维持 WiFi 连接,休眠不重连路由器:选 Light‑sleep + WiFi‑PS 省电模式;
  • 不需要常驻 WiFi,定时采集上报,允许唤醒重新联网:优先 Deep‑sleep,功耗最低;
  • Modem‑sleep 省电幅度有限,电池产品一般不采用。
  • 20.2 802.11 WiFi‑PS 省电核心原理

    STA 进入省电模式后,会向 AP 发送 PS‑bit 置 1 的帧,告知 AP:我进入休眠,不要向我直接发送单播数据。 AP 会把发给该 STA 的单播报文进行缓存,等到 AP 发送 DTIM Beacon 信标帧的时候,把缓存报文携带下发。 STA 休眠状态下不会一直接收无线信号,只在 DTIM 时刻短暂唤醒,监听 Beacon,取回 AP 缓存数据包,之后继续休眠。

    关键参数 DTIM / Listen Interval

  • DTIM:AP 参数,DTIM 间隔,绝大多数家用路由器 DTIM=1。代表每 1 个 Beacon 周期做一次组播 / 单播缓存下发。
  • Listen Interval:STA 参数,STA 告诉 AP,我每隔多少个 Beacon 周期醒来一次接收缓存数据。
    • Listen Interval 越大,休眠时间越长,平均功耗越低;但是 AP 缓存报文时间变长,数据延迟变大;AP 缓存资源有限,过大 Listen Interval 会导致 AP 丢弃缓存报文,出现丢包。
  • 量产坑:Listen Interval 不能盲目设置很大,很多路由器 AP 缓存队列很小,超过阈值直接丢弃缓存数据包,设备休眠期间消息丢失。

    WiFi‑PS 两种工作模式

    • MAX_PS:最大省电,绝大部分时间射频关闭,只在 DTIM 时刻唤醒,功耗最低,报文延迟高;
    • MIN_PS:快速省电,有数据交互之后短暂保持射频打开,空闲一段时间进入休眠,延迟低,平均功耗更高。

    20.3 Light‑sleep + WiFi‑PS 实战(休眠保持 WiFi 连接)

    重要约束:Light‑sleep 模式下,FreeRTOS 任务停止运行,只有 RTC、外设可以工作;WiFi 硬件由底层驱动自动完成间歇唤醒接收 Beacon,应用层任务休眠期间停止执行。

    ESP‑IDF 开启 WiFi 省电 API:

    esp_wifi_set_ps(WIFI_PS_MIN_MODEM); // MIN_PS
    esp_wifi_set_ps(WIFI_PS_MAX_MODEM); // MAX_PS 最大省电,电池设备首选

    设置 Listen Interval:

    wifi_ps_config_t ps_cfg = {
    .listen_interval = 3, // 单位:Beacon周期,默认Beacon 100ms → 300ms唤醒一次
    };
    esp_wifi_set_ps_config(&ps_cfg);

    完整工程:Light‑sleep 定时唤醒,维持 WiFi、MQTT 连接

    功能:平时进入 Light‑sleep 低功耗;每隔 10s 唤醒一次,上报 MQTT 状态,上报完成继续休眠;WiFi 不断开,不需要每次重连路由。 基于 ESP‑IDF5.x,继承第 14、19 章 WiFi、MQTT 基础代码。

    #include <stdio.h>
    #include <string.h>

    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    #include "freertos/event_groups.h"

    #include "esp_wifi.h"
    #include "esp_event.h"
    #include "esp_log.h"
    #include "nvs_flash.h"
    #include "esp_netif.h"
    #include "esp_sleep.h"
    #include "mqtt_client.h"

    #define WIFI_CONNECTED_BIT BIT0
    static EventGroupHandle_t wifi_event_group;
    static esp_mqtt_client_handle_t mqtt_client = NULL;
    static const char *TAG = "LOW_PS_WIFI";

    #define WIFI_SSID "YourSSID"
    #define WIFI_PASSWORD "YourPassword"
    #define MQTT_BROKER_URI "mqtt://192.168.1.100:1883"
    #define MQTT_TOPIC_PUB "device/battery/status"
    #define LIGHT_SLEEP_PERIOD_S 10 /* Light‑sleep休眠周期,单位秒 */

    static void wifi_event_handler(void* arg, esp_event_base_t base, int32_t id, void* data)
    {
    if(base == WIFI_EVENT && id == WIFI_EVENT_STA_DISCONNECTED)
    {
    ESP_LOGW(TAG,"WiFi断开");
    xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_BIT);
    esp_wifi_connect();
    }
    else if(base == IP_EVENT && id == IP_EVENT_STA_GOT_IP)
    {
    ESP_LOGI(TAG,"WiFi获取IP成功");
    xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
    }
    }

    static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
    {
    esp_mqtt_event_handle_t event = event_data;
    switch ((esp_mqtt_event_id_t)event_id)
    {
    case MQTT_EVENT_CONNECTED:
    ESP_LOGI(TAG,"MQTT已连接");
    break;
    case MQTT_EVENT_DISCONNECTED:
    ESP_LOGW(TAG,"MQTT断开");
    break;
    default:
    break;
    }
    }

    static void lowpower_task(void *arg)
    {
    xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);

    /* 开启WiFi MAX_PS最大省电模式 */
    wifi_ps_config_t ps_conf = {
    .listen_interval = 3,
    };
    esp_wifi_set_ps_config(&ps_conf);
    esp_wifi_set_ps(WIFI_PS_MAX_MODEM);
    ESP_LOGI(TAG,"WiFi MAX_PS省电模式开启,进入Light‑sleep循环");

    while(1)
    {
    /* MQTT上报业务数据 */
    if(mqtt_client && esp_mqtt_client_get_state(mqtt_client) == MQTT_CLIENT_STATE_CONNECTED)
    {
    const char *payload = "{\\"battery\\":85}";
    esp_mqtt_client_publish(mqtt_client, MQTT_TOPIC_PUB, payload, strlen(payload),1,0);
    ESP_LOGI(TAG,"唤醒上报电池数据完成");
    }

    /* 配置Light‑sleep休眠时长 */
    esp_sleep_enable_timer_wakeup(LIGHT_SLEEP_PERIOD_S * 1000000ULL);
    ESP_LOGI(TAG,"准备进入Light‑sleep");

    /* 进入轻度休眠,此处CPU挂起,任务暂停;RTC定时器到期自动唤醒,代码从此处继续往下跑 */
    esp_light_sleep_start();

    ESP_LOGI(TAG,"Light‑sleep唤醒完成");
    vTaskDelay(pdMS_TO_TICKS(200));
    }
    }

    static void wifi_sta_init(void)
    {
    wifi_event_group = xEventGroupCreate();
    esp_netif_init();
    esp_event_loop_create_default();
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t wcfg = WIFI_INIT_CONFIG_DEFAULT();
    esp_wifi_init(&wcfg);

    esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL, NULL);
    esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL, NULL);

    wifi_config_t sta_cfg = {
    .sta = {
    .ssid = WIFI_SSID,
    .password = WIFI_PASSWORD,
    }
    };
    esp_wifi_set_mode(WIFI_MODE_STA);
    esp_wifi_set_config(WIFI_IF_STA, &sta_cfg);
    esp_wifi_start();
    esp_wifi_connect();
    }

    static void mqtt_init(void)
    {
    esp_mqtt_client_config_t mqtt_cfg = {
    .broker.address.uri = MQTT_BROKER_URI,
    };
    mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
    esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
    esp_mqtt_client_start(mqtt_client);
    }

    void app_main(void)
    {
    nvs_flash_init();
    wifi_sta_init();
    mqtt_init();

    xTaskCreate(lowpower_task, "lowpower", 4096, NULL, 4, NULL);
    }

    Light‑sleep 代码关键点解读

  • esp_light_sleep_start()调用之后 CPU 暂停,任务停止运行;RTC 定时器到期硬件唤醒,程序从该函数返回继续执行;
  • WiFi‑PS 由 WiFi 硬件驱动自主管理,休眠期间 WiFi 射频间歇工作维持 AP 连接,不需要应用层干预;
  • Listen Interval 参数需要和路由器 DTIM 匹配;DTIM=1 路由器,listen_interval 建议 2‑5;
  • 唤醒之后预留短暂延时,等待 WiFi 射频稳定,再发送 MQTT/TCP 报文,避免唤醒瞬间报文发送失败。
  • 20.4 Deep‑sleep 深度休眠实战(WiFi 完全关闭,功耗最低)

    Deep‑sleep 下 WiFi、蓝牙全部断电,WiFi 连接完全丢失。每次唤醒之后,完整重新初始化 WiFi、连接 AP、连接 MQTT,上报数据,上报完成再次进入深度休眠。 适合低频次上报产品,例如每隔 30s、几分钟上报一次传感器。

    void deep_sleep_example(void)
    {
    /* 业务:采集传感器,上报数据 */

    /* 设置RTC定时唤醒,20s之后唤醒 */
    esp_sleep_enable_timer_wakeup(20 * 1000000ULL);
    ESP_LOGI(TAG,"进入Deep‑sleep,WiFi全部断电");
    esp_deep_sleep_start();
    /* Deep‑sleep唤醒之后程序整体复位,app_main重新运行,不会执行本函数后面代码 */
    }

    重要特性:Deep‑sleep 唤醒等同于芯片软复位,代码从头执行 app_main,全局变量全部丢失,只有 RTC slow memory 可以保存少量数据。

    20.5 电池设备量产高频故障现象与根因

    故障 1:开启 MAX_PS 省电,休眠之后 MQTT 收不到云端下发指令

    • 现象:设备可以上报上行消息;云端下发指令设备收不到。
    • 根因:Listen Interval 设置过大,AP 缓存满丢弃报文;DTIM 配置不匹配。
    • 解决:调小 listen_interval;尽量使用 DTIM=1 路由器;电池设备不适合高频下行控制,业务尽量改成设备主动上报。

    故障 2:Light‑sleep 休眠电流降不下来,电流几十 mA

    • 根因:有其他任务持续运行、外设时钟没有关闭、没有真正进入 light‑sleep;WiFi 没有开启 PS 模式,射频一直常开。
    • 解决:确认所有任务在休眠时刻阻塞;开启WIFI_PS_MAX_MODEM;测量休眠真实电流。

    故障 3:Light‑sleep 长时间运行,WiFi 随机断开

    • 根因:Listen Interval 过大,AP 超时把 PS 模式 STA 踢下线;路由器 AP 对 PS 客户端兼容性差。
    • 解决:适当减小 listen_interval;产品兼容性测试多品牌路由器。

    故障 4:Deep‑sleep 唤醒联网慢,上报时延大

    • 根因:每次唤醒完整扫描、认证、关联、MQTT 握手全部流程。
    • 解决:优化 WiFi 快速重连参数;NVS 保存 WiFi 配置,减少扫描时间。

    故障 5:休眠唤醒之后第一条 TCP/MQTT 报文发送失败

    • 根因:刚唤醒 WiFi 射频还未稳定,立刻发包。
    • 解决:唤醒之后增加短暂延时,等待 WiFi 链路就绪再执行业务发送。

    20.6 功耗测量实操方法

  • 使用直流电源带电流显示,或者高精度电流表测量整机平均电流;
  • 区分峰值电流(WiFi 收发瞬间)、休眠平均电流;电池产品看平均电流,不是峰值;
  • 计算电池续航:电池容量(mAh) / 平均工作电流(mA),同时考虑休眠与唤醒占空比。
  • 举例:1000mAh 电池,平均电流 1mA,理论续航 1000 小时。

    20.7 menuconfig 低功耗关键配置

  • Component config → ESP‑SLEEP:使能 light sleep 支持;
  • Component config → Wi‑Fi → WiFi Power Save:开启省电相关支持;
  • LWIP:调大 socket 接收缓冲区,应对休眠唤醒报文突发;
  • 不需要的外设 UART、SPI、I2S 休眠之前关闭,降低额外漏电。
  • 20.8 本章小结

    电池供电 WiFi 产品,休眠方案选型是产品成败关键点。

    • Light‑sleep + WiFi‑PS MAX_MODEM:休眠保持 WiFi 连接,可接收下行消息;代价功耗比 Deep‑sleep 高,受 AP DTIM、缓存机制限制,存在丢包风险。
    • Deep‑sleep:功耗极低,但是每次唤醒必须完整重连 WiFi,不适合需要实时接收云端指令的设备。

    802.11 WiFi‑PS 省电模式依赖路由器 AP 的缓存实现,不同品牌路由器兼容性存在差异,量产必须做多路由器兼容性测试。休眠调试不能只看日志,必须实测整机电流,验证休眠功耗是否达到设计指标。

    💖 点赞 + 收藏 + 关注,嵌入式 WiFi 量产实战全套教程持续更新!

     

    赞(0)
    未经允许不得转载:171主机测评 » 《WiFi 嵌入式物联网开发全套实战》| 第 20 章 WiFi 低功耗休眠、定时唤醒、保活机制(电池设备必备)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址