ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

arduino-esp32 Deep Sleep 完全指南:ExternalWakeUp 外部唤醒与 TimerWakeUp 定时器唤醒实战

arduino-esp32 Deep Sleep 完全指南:ExternalWakeUp 外部唤醒与 TimerWakeUp 定时器唤醒实战 arduino-esp32 Deep Sleep 完全指南ExternalWakeUp 外部唤醒与 TimerWakeUp 定时器唤醒实战【免费下载链接】arduino-esp32Arduino core for the ESP32 family of SoCs项目地址: https://gitcode.com/GitHub_Trending/ar/arduino-esp32导读本文基于 arduino-esp32 官方文档 docs/en/api/deepsleep.rst 的 Deep Sleep 章节系统讲解 ESP32 系列芯片在 Arduino 环境下的深度睡眠Deep Sleep编程。内容覆盖两种最基础的唤醒方式——外部 GPIO 唤醒External Wake Up与定时器唤醒Timer Wake Up并延伸至触摸唤醒、ULP 协处理器唤醒、唤醒原因Wakeup Reason解析与 RTC 内存数据持久化等进阶主题。读完本文你将能够编写低功耗 IoT 固件让设备按需休眠、按外部事件或定时周期唤醒并在多次唤醒之间保留关键数据。文中所有示例均来自本仓库libraries/ESP32/examples/DeepSleep/目录下可编译、可运行的官方示例。一、Deep Sleep 模式概述为什么要省电对于电池供电的 IoT 应用功耗是首要设计约束。ESP32 的 Deep Sleep 模式正是为此设计进入该模式后CPU、大部分 RAM 以及所有由 APB_CLK 提供时钟的数字外设都会被断电芯片中仅保留以下电源域power domain继续工作RTC 控制器RTC controllerRTC 外设RTC peripheralsRTC 内存RTC memories正如官方示例 TimerWakeUp.ino 头部注释所描述的这套选择性断电机制让芯片在休眠期间维持极低功耗同时仍能通过 RTC 域内的计时器、GPIO、触摸传感器或 ULP 协处理器侦测唤醒事件。进入 Deep Sleep 的 API 调用链非常简洁Arduino 层封装了ESP.deepSleep(time_us)定义于 cores/esp32/Esp.h其实现直接调用 ESP-IDF 的esp_deep_sleep()见 cores/esp32/Esp.cpp。而所有示例代码中使用的是更底层的组合式调用esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); // 先配置唤醒源 esp_deep_sleep_start(); // 再进入深度睡眠需要注意setup()末尾调用esp_deep_sleep_start()之后程序流程即被冻结loop()不会执行——这也是所有 Deep Sleep 示例中loop()为空或永不触达的原因。二、定时器唤醒Timer Wake Up周期任务的最简实现定时器唤醒适合需要周期性采集数据、周期上报状态的场景是 Deep Sleep 中最常用的唤醒源。完整代码见 TimerWakeUp.ino核心步骤如下。2.1 定义休眠时长#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ #define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in seconds) */esp_sleep_enable_timer_wakeup()的参数单位是微秒µs因此先用uS_TO_S_FACTOR把秒换算成微秒避免魔法数字。上例表示每 5 秒唤醒一次。2.2 在 setup() 中配置唤醒源并进入休眠void setup() { Serial.begin(115200); delay(1000); // 等待串口监视器打开 bootCount; Serial.println(Boot number: String(bootCount)); print_wakeup_reason(); esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); Serial.println(Setup ESP32 to sleep for every String(TIME_TO_SLEEP) Seconds); // 可选关闭 RTC 外设电源域以进一步省电 //esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF); Serial.println(Going to sleep now); Serial.flush(); esp_deep_sleep_start(); Serial.println(This will never be printed); // 永远不会执行到 } void loop() { // 不会被执行 }2.3 电源域精细控制可选进阶示例中注释掉了一行关键配置//esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);默认情况下ESP32 会自动关闭唤醒源不需要的电源域但作为省电高手你可以用esp_deep_sleep_pd_config(domain, option)手动指定某电源域在休眠期间的开/关状态。例如关闭ESP_PD_DOMAIN_RTC_PERIPH可进一步降低休眠电流代价是 RTC 外设如 RTC GPIO、触摸相关唤醒能力受限。选择电源域策略时需要与你的唤醒源类型匹配。2.4 唤醒原因Wakeup Reason解析无论是定时唤醒还是外部唤醒醒来后第一件事往往是判断为什么醒。示例中的print_wakeup_reason()通过esp_sleep_get_wakeup_cause()返回的枚举值区分唤醒来源switch (wakeup_reason) { case ESP_SLEEP_WAKEUP_EXT0: Serial.println(Wakeup caused by external signal using RTC_IO); break; case ESP_SLEEP_WAKEUP_EXT1: Serial.println(Wakeup caused by external signal using RTC_CNTL); break; case ESP_SLEEP_WAKEUP_TIMER: Serial.println(Wakeup caused by timer); break; case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println(Wakeup caused by touchpad); break; case ESP_SLEEP_WAKEUP_ULP: Serial.println(Wakeup caused by ULP program); break; default: Serial.printf(Wakeup was not caused by deep sleep: %d\n, wakeup_reason); break; }其中ESP_SLEEP_WAKEUP_EXT0表示由 RTC_IO 驱动的外部信号唤醒ESP_SLEEP_WAKEUP_EXT1表示由 RTC 控制器RTC_CNTL驱动的外部信号唤醒其余依次对应定时器、触摸板与 ULP 程序唤醒。设备首次上电非深睡唤醒时该函数会落入default分支。三、外部唤醒External Wake UpEXT0 与 EXT1 两种机制外部唤醒适合按钮、门磁、运动检测等事件驱动场景。完整代码见 ExternalWakeUp.ino其硬件连接为按键一端接 GPIO 33另一端经 10KΩ 下拉电阻接地。3.1 重要前提只能用 RTC IO 引脚示例注释明确给出了硬件约束Only RTC IO can be used as a source for external wake source. They are pins: 0,2,4,12-15,25-27,32-39.即 ESP32 上只有 RTC 域引脚0、2、4、12–15、25–27、32–39可作为外部唤醒源。设计电路时务必避开非 RTC 引脚。3.2 EXT0单引脚、电平触发EXT0 使用RTC_IO实现唤醒需要 RTC 外设RTC_PERIPH电源域保持开启#define WAKEUP_GPIO GPIO_NUM_33 // 必须是 RTC IO esp_sleep_enable_ext0_wakeup(WAKEUP_GPIO, 1); // 1 High 唤醒, 0 Low 唤醒 // 通过 RTCIO 配置内部上/下拉将唤醒引脚在休眠期间钳位到非激活电平 rtc_gpio_pullup_dis(WAKEUP_GPIO); rtc_gpio_pulldown_en(WAKEUP_GPIO);esp_sleep_enable_ext0_wakeup(gpio_num, level)的第二个参数指定唤醒电平1表示引脚出现高电平即唤醒0表示低电平唤醒。示例中按下按键使 GPIO33 拉高从而唤醒。由于 EXT0 与 RTC IO 的上下拉同属RTC_PERIPH电源域示例注释特别说明EXT0 无需像 EXT1 那样显式保持该电源域。3.3 EXT1多引脚、掩码触发EXT1 使用RTC 控制器RTC_CNTL实现唤醒不依赖 RTC 外设供电因此功耗更低且可同时监测多个引脚#define BUTTON_PIN_BITMASK(GPIO) (1ULL GPIO) // 将 GPIO 编号转为位掩码 esp_sleep_enable_ext1_wakeup_io(BUTTON_PIN_BITMASK(WAKEUP_GPIO), ESP_EXT1_WAKEUP_ANY_HIGH);BUTTON_PIN_BITMASK(GPIO)展开为1ULL GPIO即把引脚号映射到位掩码例如 GPIO 33 对应1ULL 33。唤醒模式参数ESP_EXT1_WAKEUP_ANY_HIGH表示任一被掩码的引脚为高电平即唤醒对应地还有ESP_EXT1_WAKEUP_ALL_LOW全部为低才唤醒。示例同时给出了 EXT1 模式下的上下拉建议若外部没有上/下拉电阻可在深睡期间用 RTC IO 的内部上/下拉把唤醒引脚钳位到非激活电平。但要注意——RTC IO 依赖 RTC_PERIPH 电源域保持该域开启会增加功耗若关闭RTC_PERIPH域、或某些芯片本身缺少该电源域则需要使用 HOLD 特性在睡眠期间维持引脚上/下拉状态。3.4 在两种模式间切换示例用编译期宏快速切换两种外部唤醒机制#define USE_EXT0_WAKEUP 1 // 1 EXT0 wakeup, 0 EXT1 wakeup #if USE_EXT0_WAKEUP esp_sleep_enable_ext0_wakeup(WAKEUP_GPIO, 1); rtc_gpio_pullup_dis(WAKEUP_GPIO); rtc_gpio_pulldown_en(WAKEUP_GPIO); #else // EXT1 WAKEUP esp_sleep_enable_ext1_wakeup_io(BUTTON_PIN_BITMASK(WAKEUP_GPIO), ESP_EXT1_WAKEUP_ANY_HIGH); rtc_gpio_pulldown_en(WAKEUP_GPIO); // GPIO33 被下拉到 GND因此高电平唤醒 rtc_gpio_pullup_dis(WAKEUP_GPIO); // 禁用上拉以允许高电平唤醒 #endif实践中的选型建议单引脚唤醒优先用 EXT0配置直观多引脚监测或追求更低休眠功耗时用 EXT1无需保持 RTC_PERIPH 域。四、用 RTC_DATA_ATTR 在休眠期间持久化数据Deep Sleep 会清空常规 RAM因此跨重启保留计数器、状态标志等数据必须借助RTC 内存。所有 Deep Sleep 示例都使用了同一行声明RTC_DATA_ATTR int bootCount 0;RTC_DATA_ATTR由 ESP-IDF 提供esp_attr.h它把变量放置到 RTC 慢速内存RTC_SLOW_MEM中在 Deep Sleep 期间不被断电重启后值依然保留。典型用法void setup() { bootCount; // 每次唤醒自增 Serial.println(Boot number: String(bootCount)); ... }配合esp_sleep_get_wakeup_cause()你可以在首次上电bootCount 1时执行初始化在后续唤醒时直接恢复现场。这是实现断电不丢状态的最简方案。五、进阶触摸唤醒与 ULP 协处理器唤醒仓库的libraries/ESP32/examples/DeepSleep/目录还提供了另外两种官方示例用于更复杂的低功耗场景。5.1 触摸唤醒Touch Wake UpTouchWakeUp.ino 演示以电容触摸作为唤醒源。示例代码使用esp_sleep_get_touchpad_wakeup_status()反查具体触发触摸的引脚并强调了一个跨芯片差异ESP32支持多个触摸板同时作为唤醒源示例启用 Touch Pad 3 和 7对应 GPIO 15 与 GPIO 27ESP32-S2 / ESP32-S3仅支持 1 个触摸板作为唤醒源不同芯片的触摸阈值语义也不同ESP32 阈值40越大越灵敏S2/S3 阈值5000越小越灵敏其他芯片默认500。#if CONFIG_IDF_TARGET_ESP32 touchSleepWakeUpEnable(T3, THRESHOLD); touchSleepWakeUpEnable(T7, THRESHOLD); #else //ESP32-S2 ESP32-S3 ESP32-P4 touchSleepWakeUpEnable(T3, THRESHOLD); #endif5.2 ULP 协处理器唤醒SmoothBlink_ULP_CodeSmoothBlink_ULP_Code.ino 展示了 Deep Sleep 的最高级玩法主 CPU 休眠期间由ULPUltra Low Power协处理器独立运行汇编程序在 GPIO 2 上输出约 10KHz 的渐变 PWM 呼吸灯并跨休眠周期保存占空比状态。其实现要点包括用RTC_SLOW_MEM[]数组索引与主程序共享变量如fadeCycleDelay通过uint32_t *fadeCycleDelay RTC_SLOW_MEM[RTC_fadeDelay];传递参数以ulp_insn_t ulp_prog[]数组定义 ULP 汇编指令序列I_MOVI、I_ST、I_LD、M_BL、I_WR_REG等再用ulp_process_macros_and_load()加载、ulp_run()启动通过esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON)显式保持 RTC 外设电源域供 ULP 操作 GPIO配合esp_sleep_enable_timer_wakeup()让主 CPU 每 5 秒醒来一次调整亮度参数其余时间交给 ULP 全权处理。这是主 CPU 休眠、协处理器值守的典型架构适合需要持续输出信号如呼吸灯、传感器激励同时又要求极低功耗的应用。六、实战要点速查场景唤醒源 API关键参数/约束周期性任务esp_sleep_enable_timer_wakeup(time_us)单位微秒TIME_TO_SLEEP * 1000000ULL单引脚外部事件esp_sleep_enable_ext0_wakeup(gpio, level)仅限 RTC IO 引脚0,2,4,12–15,25–27,32–39level1高唤醒/0低唤醒多引脚外部事件esp_sleep_enable_ext1_wakeup_io(mask, mode)掩码1ULL GPIOESP_EXT1_WAKEUP_ANY_HIGH/ESP_EXT1_WAKEUP_ALL_LOW触摸唤醒touchSleepWakeUpEnable(pad, threshold)ESP32 可多 padS2/S3 仅 1 个 padULP 值守ulp_run(offset) 定时器唤醒需保持ESP_PD_DOMAIN_RTC_PERIPH开启跨休眠数据RTC_DATA_ATTR变量存放于 RTC_SLOW_MEMDeep Sleep 不丢失电源域微调esp_deep_sleep_pd_config(domain, option)例如ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF所有示例的通用骨架可归纳为三步① 声明RTC_DATA_ATTR持久变量 → ② 在setup()中解析唤醒原因并配置唤醒源 → ③ 调用esp_deep_sleep_start()进入休眠loop()不会执行。需要特别留意两点esp_deep_sleep_start()前的Serial.flush()确保休眠前的串口输出完整发送见 TimerWakeUp 示例否则可能丢失最后的日志无唤醒源时的行为如示例注释所述如果未配置任何唤醒源就调用esp_deep_sleep_start()芯片将永久休眠只能通过硬件复位EN 引脚唤醒。七、进一步阅读Deep Sleep 章节原始文档docs/en/api/deepsleep.rst该章节标记为 WIP正文以示例为核心四个可编译运行的官方示例均位于 libraries/ESP32/examples/DeepSleep/ExternalWakeUp、TimerWakeUp、TouchWakeUp、SmoothBlink_ULP_Code唤醒原因解析的配套示例可参考 libraries/ESP32/examples/ResetReason/ResetReason.ino 同样使用esp_sleep_get_wakeup_cause()体系Arduino 层封装入口ESP.deepSleep(time_us)声明于 cores/esp32/Esp.h实现在 cores/esp32/Esp.cpp低功耗触发的底层实现可继续阅读 ESP-IDF 的esp_sleep系列驱动本仓库cores/esp32/与variants/中对应芯片的头文件定义了CONFIG_IDF_TARGET_*芯片差异宏掌握上述示例与原理后即可根据实际硬件选择定时、外部、触摸或 ULP 唤醒组合构建出符合产品功耗指标的 Deep Sleep 应用。【免费下载链接】arduino-esp32Arduino core for the ESP32 family of SoCs项目地址: https://gitcode.com/GitHub_Trending/ar/arduino-esp32创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表