IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> ESP32 (Sleep Modes)-睡眠模式学习(8) -> 正文阅读

[嵌入式]ESP32 (Sleep Modes)-睡眠模式学习(8)

提示:本博客作为学习笔记,有错误的地方希望指正

一、ESP32 Sleep Modes概述

参考资料:ESP IDF编程手册V4.4
??ESP32 具有 Light-sleep 和 Deep-sleep 两种睡眠节能模式。此外还有一种Modem-sleep模式,这种模式在ESP32 WI-FI可以与路由器保持连接。

1、Sleep模式

1.1.1、 Light-sleep 模式

??在 Light-sleep 模式下,数字外设、CPU、以及大部分 RAM 都使用时钟门控,同时电源电压降低。退出该模式后,数字外设、CPU 和 RAM 恢复运行,内部状态保持不变。
??函数 esp_light_sleep_start() 可用于在配置唤醒源后进入 Light-sleep 模式,也可用于在未配置唤醒源的情况下进入 Light-sleep 模式。在后一种情况中,芯片将一直处于睡眠模式,直到从外部被复位。

1.1.2、 Deep-sleep 模式

??在 Deep-sleep 模式下,CPU、大部分 RAM、以及所有由时钟 APB_CLK 驱动的数字外设都会被断电。芯片上继续处于供电状态的部分仅包括:

  • RTC 控制器
  • RTC 外设
  • ULP 协处理器
  • RTC 高速内存
  • RTC 低速内存

??函数 esp_deep_sleep_start() 可用于在配置唤醒源后进入 Deep-sleep 模式,也可用于在未配置唤醒源的情况下进入 Deep-sleep 模式 模式。在后一种情况中,芯片将一直处于睡眠模式,直到从外部被复位。

系统资源Light-sleepDeep-sleep
Wi-Fi 和 Bluetooth 功能关闭关闭
GPIO状态保保持保持
系统时钟关闭关闭
RTC 时钟开启开启
CPU 状态暂停关闭

??Light-sleep 和 Deep-sleep 模式有多种唤醒源。这些唤醒源也可以组合在一起,此时任何一个唤醒源都可以触发唤醒。通过 API esp_sleep_enable_X_wakeup 可启用唤醒源,通过 API esp_sleep_disable_wakeup_source() 可禁用唤醒源,在系统进入 Light-sleep 或 Deep-sleep 模式前,可以在任意时刻配置唤醒源。
??此外,应用程序可以使用 API esp_sleep_pd_config() 强制 RTC 外设和 RTC 内存进入特定断电模式。
??配置唤醒源后,应用程序就可以使用 API esp_light_sleep_start() 或 esp_deep_sleep_start() 进入睡眠模式。此时,系统将按照被请求的唤醒源配置硬件,同时 RTC 控制器会给 CPU 和数字外设断电。
??如需保持 Wi-Fi 连接,请启用 Wi-Fi Modem-sleep 模式和自动 Light-sleep 模式(请参阅 电源管理 API)。在这两种模式下,Wi-Fi 驱动程序发出请求时,系统将自动从睡眠中被唤醒,从而保持与 AP 的连接。

1.2、睡眠模式下的 Wi-Fi 和 Bluetooth 功能

??在 Light-sleep 和 Deep-sleep 模式下,无线外设会被断电。因此,在进入这两种睡眠模式前,应用程序必须调用恰当的函数(esp_bluedroid_disable()、esp_bt_controller_disable() 或 esp_wifi_stop())来禁用 Wi-Fi 和 Bluetooth。在 Light-sleep 或 Deep-sleep 模式下,即使不调用这些函数也无法连接 Wi-Fi 和 Bluetooth。

1.3、唤醒源

??其中唤醒源有以下几种情况

ESP_SLEEP_WAKEUP_UNDEFINED,         //!< 在深度睡眠的情况下,复位不是由退出深度睡眠引起的 In case of deep sleep, reset was not caused by exit from deep sleep                                      
ESP_SLEEP_WAKEUP_ALL ,              //!< 没有一个唤醒源,esp_sleep_disable_wakeup_source 禁用睡眠模式唤醒源 Not a wakeup cause, used to disable all wakeup sources with esp_sleep_disable_wakeup_source                                                      
ESP_SLEEP_WAKEUP_EXT0 ,             //!< 由外部信号RTC_IO引起的唤醒 Wakeup caused by external signal using RTC_IO              
ESP_SLEEP_WAKEUP_EXT1 ,             //!< 使用RTC_CNTL由外部信号引起的唤醒  Wakeup caused by external signal using RTC_CNTL                      
ESP_SLEEP_WAKEUP_TIMER ,            //!< 定时器引起的唤醒 Wakeup caused by timer       
ESP_SLEEP_WAKEUP_TOUCHPAD,          //!< touchpad引起的唤醒 Wakeup caused by touchpad       
ESP_SLEEP_WAKEUP_ULP ,              //!< ULP程序导致的唤醒 Wakeup caused by ULP program       
ESP_SLEEP_WAKEUP_GPIO ,             //!< GPIO导致的唤醒(仅为轻度睡眠) Wakeup caused by GPIO (light sleep only)                  
ESP_SLEEP_WAKEUP_UART ,             //!< UART引起的觉醒(仅轻度睡眠) Wakeup caused by UART (light sleep only)              
ESP_SLEEP_WAKEUP_WIFI ,             //!< WIFI引起的唤醒(仅限轻度睡眠) Wakeup caused by WIFI (light sleep only)                  
ESP_SLEEP_WAKEUP_COCPU ,            //!< 由COCPU引起的唤醒int Wakeup caused by COCPU int           
ESP_SLEEP_WAKEUP_COCPU_TRAP_TRIG,   //!< 由COCPU崩溃引起的唤醒 Wakeup caused by COCPU crash           
ESP_SLEEP_WAKEUP_BT ,               //!< BT引起的醒来(仅轻度睡眠) Wakeup caused by BT (light sleep only)      

1.3.1、定时器唤醒

??RTC 控制器中内嵌定时器,可用于在预定义的时间到达后唤醒芯片。时间精度为微秒,但其实际分辨率依赖于为 RTC SLOW_CLK 所选择的时钟源。

关于 RTC 时钟选项的更多细节,请参考 ESP32 技术参考手册 > ULP 协处理器 [PDF]

??在这种唤醒模式下,无需为睡眠模式中的 RTC 外设或内存供电。
??调用 esp_sleep_enable_timer_wakeup() 函数可启用使用定时器唤醒睡眠模式。

1.3.2、触摸传感器唤醒

??RTC IO 模块中包含这样一个逻辑——当发生触摸传感器中断时,触发唤醒。要启用此唤醒源,用户需要在芯片进入睡眠模式前配置触摸传感器中断功能。
??ESP32 修订版 0 和 1 仅在 RTC 外设没有被强制供电时支持该唤醒源(即 ESP_PD_DOMAIN_RTC_PERIPH 应被设置为 ESP_PD_OPTION_AUTO)。
??可调用 esp_sleep_enable_touchpad_wakeup() 函数来启用该唤醒源。

1.3.3、外部唤醒 (ext0)唤醒

??RTC IO 模块中包含这样一个逻辑——当某个 RTC GPIO 被设置为预定义的逻辑值时,触发唤醒。RTC IO 是 RTC 外设电源域的一部分,因此如果该唤醒源被请求,RTC 外设将在 Deep-sleep 模式期间保持供电。
??在此模式下,RTC IO 模块被使能,因此也可以使用内部上拉或下拉电阻。配置时,应用程序需要在调用函数 esp_deep_sleep_start() 前先调用函数 rtc_gpio_pullup_en() 和 rtc_gpio_pulldown_en()。
??在 ESP32 修订版 0 和 1 中,此唤醒源与 ULP 和触摸传感器唤醒源都不兼容。
??可调用 esp_sleep_enable_ext0_wakeup() 函数来启用此唤醒源。

??警告
从睡眠模式中唤醒后,用于唤醒的 IO pad 将被配置为 RTC IO。因此,在将该 pad 用作数字 GPIO 之前,请调用 rtc_gpio_deinit() 函数对其进行重新配置。

1.3.4、外部唤醒 (ext1)

??RTC 控制器中包含使用多个 RTC GPIO 触发唤醒的逻辑。您可以从以下两个逻辑函数中选择其一,用于触发唤醒:

  • 当所有所选管脚为低电平时唤醒 (ESP_EXT1_WAKEUP_ALL_LOW
  • 当任意一个所选管脚为高电平时唤醒(ESP_EXT1_WAKEUP_ANY_HIGH)

??此唤醒源由 RTC 控制器实现。这种模式下的 RTC 外设和 RTC 内存可以被断电。但如果 RTC 外设被断电,内部上拉和下拉电阻将被禁用。想要使用内部上拉和下拉电阻,需要 RTC 外设电源域在睡眠期间保持开启,并在进入睡眠前使用函数 rtc_gpio_ 配置上拉或下拉电阻。

esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);    //设置RTC电源域休眠模式的下电模式
gpio_pullup_dis(gpio_num);      //禁用GPIO上拉菜单。
gpio_pulldown_en(gpio_num);     //使能GPIO下拉功能。
??警告
从睡眠模式中唤醒后,用于唤醒的 IO pad 将被配置为 RTC IO。因此在将该 pad 用作数字 GPIO 前,请调用 rtc_gpio_deinit() 函数对其进行重新配置。

??可调用 esp_sleep_enable_ext1_wakeup() 函数来启用此唤醒源。

1.3.5、ULP 协处理器唤醒

??当芯片处于睡眠模式时,ULP 协处理器仍然运行,可用于轮询传感器、监视 ADC 或触摸传感器的值,并在检测到特殊事件时唤醒芯片。ULP 协处理器是 RTC 外设电源域的一部分,运行存储在 RTC 低速内存中的程序。如果这一唤醒源被请求,RTC 低速内存将会在睡眠期间保持供电状态。RTC 外设会在 ULP 协处理器开始运行程序前自动上电;一旦程序停止运行,RTC 外设会再次自动断电。
??ESP32 修订版 0 和 1 仅在 RTC 外设没有被强制供电时支持该唤醒(即 ESP_PD_DOMAIN_RTC_PERIPH 应被设置为 ESP_PD_OPTION_AUTO)。
??可调用 esp_sleep_enable_ulp_wakeup() 函数来启用此唤醒源。

1.3.6、GPIO 唤醒(仅适用于 Light-sleep 模式)

??除了上述 EXT0 和 EXT1 唤醒源之外,还有一种从外部唤醒 Light-sleep 模式的方法——使用函数 gpio_wakeup_enable()。启用该唤醒源后,可将每个管脚单独配置为在高电平或低电平时唤醒。EXT0 和 EXT1 唤醒源只能用于 RTC IO,但此唤醒源既可以用于 RTC IO,可也用于数字 IO。
??可调用 esp_sleep_enable_gpio_wakeup() 函数来启用此唤醒源。

??警告
??在进入 Light-sleep 模式前,请查看您将要驱动的 GPIO 管脚的电源域。如果有管脚属于 VDD_SDIO 电源域,必须将此电源域配置为在睡眠期间保持供电。

??例如,在 ESP32-WROOM-32 开发板上,GPIO16 和 GPIO17 连接到 VDD_SDIO 电源域。如果这两个管脚被配置为在睡眠期间保持高电平,则您需将对应电源域配置为保持供电。您可以使用函数 esp_sleep_pd_config():

esp_sleep_pd_config(ESP_PD_DOMAIN_VDDSDIO, ESP_PD_OPTION_ON);   //设置RTC电源域休眠模式的下电模式

1.3.7、UART 唤醒(仅适用于 Light-sleep 模式)

??当 ESP32 从外部设备接收 UART 输入时,通常需要在输入数据可用时唤醒芯片。UART 外设支持在 RX 管脚上观测到一定数量的上升沿时,将芯片从 Light-sleep 模式中唤醒。调用 uart_set_wakeup_threshold() 函数可设置被观测上升沿的数量。请注意,触发唤醒的字符(及该字符前的所有字符)在唤醒后不会被 UART 接收,因此在发送数据之前,外部设备通常需要首先向 ESP32 额外发送一个字符以触发唤醒。
??可调用 esp_sleep_enable_uart_wakeup() 函数来启用此唤醒源。

1.4、RTC 外设和内存断电

??默认情况下,调用函数 esp_deep_sleep_start() 和 esp_light_sleep_start() 后,所有唤醒源不需要的 RTC 电源域都会被断电。可调用函数 esp_sleep_pd_config() 来修改这一设置。
??注意:在 ESP32 修订版 1 中,RTC 高速内存在 Deep-sleep 期间将总是保持使能,以保证复位后可运行 Deep-sleep stub。如果应用程序在 Deep-sleep 模式后无需复位,您也可以对其进行修改。
??如果程序中的某些值被放入 RTC 低速内存中(例如使用 RTC_DATA_ATTR 属性),RTC 低速内存将默认保持供电。如果有需要,也可以使用函数 esp_sleep_pd_config() 对其进行修改。

1.5、配置 IO

??一些 ESP32 IO 在默认情况下启用内部上拉或下拉电阻。如果这些管脚在 Deep-sleep 模式下中受外部电路驱动,电流流经这些上下拉电阻时,可能会增加电流消耗。
??想要隔离这些管脚以避免额外的电流消耗,请调用 rtc_gpio_isolate() 函数。
??例如,在 ESP32-WROVER 模组上,GPIO12 在外部上拉,但其在 ESP32 芯片中也有内部下拉。这意味着在 Deep-sleep 模式中,电流会流经这些外部和内部电阻,使电流消耗超出可能的最小值。
??在函数 esp_deep_sleep_start() 前增加以下代码即可避免额外电流消耗:

rtc_gpio_isolate(GPIO_NUM_12);

1.6、UART 输出处理

??在进入睡眠模式之前,调用函数 esp_deep_sleep_start() 会冲刷掉 UART FIFO 缓存。
??当使用函数 esp_light_sleep_start() 进入 Light-sleep 模式时,UART FIFO 将不会被冲刷。与之相反,UART 输出将被暂停,FIFO 中的剩余字符将在 Light-sleep 唤醒后被发送。

1.7、检查睡眠唤醒原因

??esp_sleep_get_wakeup_cause() 函数可用于检测是何种唤醒源在睡眠期间被触发。
??对于触摸传感器唤醒源,可以调用函数 esp_sleep_get_touchpad_wakeup_status() 来确认触发唤醒的触摸管脚。
??对于 ext1 唤醒源,可以调用函数 esp_sleep_get_ext1_wakeup_status() 来确认触发唤醒的触摸管脚。

1.8、禁用睡眠模式唤醒源

??调用 API esp_sleep_disable_wakeup_source() 可以禁用给定唤醒源的触发器,从而禁用该唤醒源。此外,如果将参数设置为 ESP_SLEEP_WAKEUP_ALL,该函数可用于禁用所有触发器。

二、硬件设计

??经过我测试下ESP32和ESP32S3的串口唤醒有些不一样,ESP32串口唤醒不需要配置接收引脚GPIO可以实现唤醒,但是ESP32S3不配置不能唤醒。具体的功耗手里目前没有工具没法测试。

三、Light-sleep 实现代码

??值得注意的是我在测试的时候发现了几个问题,官方给的Demo中GPIO唤醒的时候没有配置输入上下拉使能,当我手指在GPIO引脚上空的时候就会出现感应到GPIO唤醒,并且一段时间GPIO就会复位,其次是在于ESP32和ESP32的串口唤醒有些不一样,对于ESP32的串口唤醒的话我测试的时候不需要配追GPIO的参数,其次就是串口唤醒不支持GPIO矩阵作为串口的引脚,必须原配的,下图就是ESP32的串口唤醒截图。
在这里插入图片描述
??对于ESP32S3的话我测试过可以使用GPIO矩阵作为串口换新的,但是需要配置前面的GPIO参数,不然原配的引脚或者IO矩阵的引脚都不行,不能唤醒,弄了许久的,我以为前面配置了GPIO的参数就是GPIO唤醒掩盖了串口唤醒,但是我到唤醒源函数中看逻辑,逻辑是GPIO的唤醒等级逻辑高于串口,这样看来这样配置就是没有问题可以触发串口唤醒的。如果有小伙伴发现更好的方法欢迎留言一起讨论。
??在这个实验历程中有定时器唤醒和串口唤醒以及GPIO唤醒三种状态。整个测试文件的初始化流程为。
在这里插入图片描述

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "esp_timer.h"

#if CONFIG_IDF_TARGET_ESP32C3
#define BUTTON_GPIO_NUM_DEFAULT         9
#else
#define BUTTON_GPIO_NUM_DEFAULT         19
#endif

/* "Boot" button is active low */
#define BUTTON_WAKEUP_LEVEL_DEFAULT     0

#define Power_Control_Pin               10          //电源控制引脚
#define RX_BUF_SIZE                     1024        //接收字符多少
#define Wakeup_Uart_NumberPort          UART_NUM_0  //设置唤醒串口的编号
#define Wakeup_Uart_DataNumber          3           //串口唤醒数据的个数
#define UART_RX_GPIO_NUM                44          //串口唤醒接收引脚

const char * TAG = "Light Sleep";
void app_main(void)
{
    esp_err_t err = ESP_OK;
    const int button_gpio_num = BUTTON_GPIO_NUM_DEFAULT;    //配置默认唤醒GPIO    
    const int wakeup_level = BUTTON_WAKEUP_LEVEL_DEFAULT;   //设置唤醒电平

    gpio_config_t config = {
            .pin_bit_mask = BIT64(button_gpio_num),         //M5Stack 不能配置GPIO1 作为串口引脚,影响串口输出
            .mode = GPIO_MODE_INPUT,                        //输入模式
            .pull_up_en = 1,                                //使能上拉
    };
    ESP_ERROR_CHECK(gpio_config(&config));                  //配置GPIO
    gpio_wakeup_enable(button_gpio_num,wakeup_level == 0 ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL);//设置gpio唤醒
	//esp32s3 需要有串口接收引脚的配置
    const int uart_rx_gpio_num = UART_RX_GPIO_NUM;          //配置默认唤醒GPIO    
    gpio_wakeup_enable(uart_rx_gpio_num,wakeup_level == 0 ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL);//设置gpio唤醒 不能放置在初始化gpio之后,不然就配置成gpio唤醒了
    gpio_config_t gpio_uart_config = {
            .pin_bit_mask = BIT64(uart_rx_gpio_num),        //M5Stack 不能配置GPIO1 作为串口引脚,影响串口输出
            .mode = GPIO_MODE_INPUT,                        //输入模式
            .pull_up_en = 1,                                //使能上拉
    };
    ESP_ERROR_CHECK(gpio_config(&gpio_uart_config));        //配置GPIO
    //配置串口唤醒的一些参数 esp32 只需要以下串口配置就行了
    const uart_config_t uart_config = {
        .baud_rate = 115200,                                //设置串口波特率
        .data_bits = UART_DATA_8_BITS,                      //设置数据位
        .parity = UART_PARITY_DISABLE,                      //设置奇偶校验
        .stop_bits = UART_STOP_BITS_1,                      //设置停止位
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,              //不使能硬件流控制
        .source_clk = UART_SCLK_APB,                        //设置时钟源 sleep模式的时候启用-->REF_TICK时钟源
    };
    uart_driver_install(Wakeup_Uart_NumberPort, RX_BUF_SIZE * 2, 0, 0, NULL, 0);    //安装串口驱动
    uart_param_config(Wakeup_Uart_NumberPort, &uart_config);                        //配置串口
    uart_set_pin(Wakeup_Uart_NumberPort, 43, 44, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);//配置串口引脚
    char data[] = "168";
    uart_write_bytes(Wakeup_Uart_NumberPort, (const char *) data, 4);
    err = uart_set_wakeup_threshold(Wakeup_Uart_NumberPort,Wakeup_Uart_DataNumber); //设置串口唤醒流
    if(err != ESP_OK)
        ESP_LOGE(TAG,"Init Err");
    err = esp_sleep_enable_uart_wakeup(Wakeup_Uart_NumberPort);                     //使能串口唤醒
    if(err != ESP_OK)
        ESP_LOGE(TAG,"Init Err");
    esp_sleep_enable_gpio_wakeup();                                                 //使能GPIO唤醒

    while (true) {
        esp_sleep_enable_timer_wakeup(5000000);     //设置唤醒时间
        esp_sleep_enable_gpio_wakeup();             //使能GPIO唤醒
        printf("Entering light sleep\n");
        uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);//等待串口数据发送完毕
        int64_t t_before_us = esp_timer_get_time(); //获取睡眠前的时间
        esp_light_sleep_start();                    //开启睡眠 
        int64_t t_after_us = esp_timer_get_time();  //在唤醒时候获取唤醒时候的时间
        const char* wakeup_reason;
        switch (esp_sleep_get_wakeup_cause()) {     //获取唤醒源
            case ESP_SLEEP_WAKEUP_TIMER:
                wakeup_reason = "timer";
                break;
            case ESP_SLEEP_WAKEUP_GPIO:
                wakeup_reason = "pin";
                break;
            case ESP_SLEEP_WAKEUP_UART:
                wakeup_reason = "uart";
                break;
            default:
                wakeup_reason = "other";
                break;
        }
        printf("Returned from light sleep, reason: %s, t=%lld ms, slept for %lld ms\n",wakeup_reason, t_after_us / 1000, (t_after_us - t_before_us) / 1000);
    }

}

四、Light-sleep 实验演示结果

在这里插入图片描述

五、Deep-sleep 实现代码

??深度睡眠模式下cpu唤醒就会复位,但是功耗低,支持触摸唤醒、定时器唤醒,ulp唤醒,但是ulp是汇编写的。


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "driver/adc.h"
#include "driver/rtc_io.h"
#include "soc/rtc.h"

#if CONFIG_IDF_TARGET_ESP32
#include "esp32/ulp.h"
#endif

#if SOC_TOUCH_SENSOR_NUM > 0
#include "soc/sens_periph.h"
#include "driver/touch_pad.h"
#endif

#ifdef CONFIG_IDF_TARGET_ESP32C3
#define DEFAULT_WAKEUP_PIN      CONFIG_EXAMPLE_GPIO_WAKEUP_PIN
#ifdef CONFIG_EXAMPLE_GPIO_WAKEUP_HIGH_LEVEL
#define DEFAULT_WAKEUP_LEVEL    ESP_GPIO_WAKEUP_GPIO_HIGH
#else
#define DEFAULT_WAKEUP_LEVEL    ESP_GPIO_WAKEUP_GPIO_LOW
#endif
#endif

static RTC_DATA_ATTR struct timeval sleep_enter_time;

#define CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP

#ifdef CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP
#if CONFIG_IDF_TARGET_ESP32

/*
 * Offset (in 32-bit words) in RTC Slow memory where the data is placed
 * by the ULP coprocessor. It can be chosen to be any value greater or equal
 * to ULP program size, and less than the CONFIG_ESP32_ULP_COPROC_RESERVE_MEM/4 - 6,
 * where 6 is the number of words used by the ULP coprocessor.
 */
#define ULP_DATA_OFFSET     36

_Static_assert(ULP_DATA_OFFSET < CONFIG_ESP32_ULP_COPROC_RESERVE_MEM/4 - 6,
        "ULP_DATA_OFFSET is set too high, or CONFIG_ESP32_ULP_COPROC_RESERVE_MEM is not sufficient");

/**
 * @brief Start ULP temperature monitoring program
 *
 * This function loads a program into the RTC Slow memory and starts up the ULP.
 * The program monitors on-chip temperature sensor and wakes up the SoC when
 * the temperature goes lower or higher than certain thresholds.
 */
static void start_ulp_temperature_monitoring(void);

/**
 * @brief Utility function which reads data written by ULP program
 *
 * @param offset offset from ULP_DATA_OFFSET in RTC Slow memory, in words
 * @return lower 16-bit part of the word writable by the ULP
 */
static inline uint16_t ulp_data_read(size_t offset)
{
    return RTC_SLOW_MEM[ULP_DATA_OFFSET + offset] & 0xffff;
}

/**
 * @brief Utility function which writes data to be ready by ULP program
 *
 * @param offset offset from ULP_DATA_OFFSET in RTC Slow memory, in words
 * @param value lower 16-bit part of the word to be stored
 */
static inline void ulp_data_write(size_t offset, uint16_t value)
{
    RTC_SLOW_MEM[ULP_DATA_OFFSET + offset] = value;
}
#endif // CONFIG_IDF_TARGET_ESP32
#endif // CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP

#ifdef CONFIG_EXAMPLE_TOUCH_WAKEUP  //配置触摸唤醒
#if CONFIG_IDF_TARGET_ESP32
#define TOUCH_THRESH_NO_USE 0       
static void calibrate_touch_pad(touch_pad_t pad);
#endif
#endif

void app_main(void)
{
    struct timeval now;
    gettimeofday(&now, NULL);                   //获取现在的时间
    int sleep_time_ms = (now.tv_sec - sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - sleep_enter_time.tv_usec) / 1000;

    switch (esp_sleep_get_wakeup_cause()) {     //获取唤醒源
#ifdef CONFIG_EXAMPLE_EXT1_WAKEUP   
        case ESP_SLEEP_WAKEUP_EXT1: {           //外部EXT1唤醒源 多个 RTC GPIO 触发唤醒的逻辑
            uint64_t wakeup_pin_mask = esp_sleep_get_ext1_wakeup_status();//获取导致唤醒的gpio的位掩码(ext1)
            if (wakeup_pin_mask != 0) {
                int pin = __builtin_ffsll(wakeup_pin_mask) - 1;
                printf("Wake up from GPIO %d\n", pin);
            } else {
                printf("Wake up from GPIO\n");
            }
            break;
        }
#endif // CONFIG_EXAMPLE_EXT1_WAKEUP
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
        case ESP_SLEEP_WAKEUP_GPIO: {           //配追GPIO唤醒
            uint64_t wakeup_pin_mask = esp_sleep_get_gpio_wakeup_status();
            if (wakeup_pin_mask != 0) {
                int pin = __builtin_ffsll(wakeup_pin_mask) - 1;
                printf("Wake up from GPIO %d\n", pin);
            } else {
                printf("Wake up from GPIO\n");
            }
            break;
        }
#endif //SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
        case ESP_SLEEP_WAKEUP_TIMER: {          //配置定时器唤醒
            printf("Wake up from timer. Time spent in deep sleep: %dms\n", sleep_time_ms);
            break;
        }
#ifdef CONFIG_EXAMPLE_TOUCH_WAKEUP              
        case ESP_SLEEP_WAKEUP_TOUCHPAD: {       //配置touch唤醒
            printf("Wake up from touch on pad %d\n", esp_sleep_get_touchpad_wakeup_status());
            break;
        }
#endif // CONFIG_EXAMPLE_TOUCH_WAKEUP
#ifdef CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP    //配置ulp唤醒
#if CONFIG_IDF_TARGET_ESP32
        case ESP_SLEEP_WAKEUP_ULP: {            //ulp唤醒源
            printf("Wake up from ULP\n");
            int16_t diff_high = (int16_t)ulp_data_read(3);
            int16_t diff_low = (int16_t) ulp_data_read(4);
            if (diff_high < 0) {
                printf("High temperature alarm was triggered\n");
            } else if (diff_low < 0) {
                printf("Low temperature alarm was triggered\n");
            } else {
                assert(false && "temperature has stayed within limits, but got ULP wakeup\n");
            }
            break;
        }
#endif // CONFIG_IDF_TARGET_ESP32
#endif // CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP
        case ESP_SLEEP_WAKEUP_UNDEFINED:    //没有找到唤醒源
        default:
            printf("Not a deep sleep reset\n");
    }

#ifdef CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP
#if CONFIG_IDF_TARGET_ESP32
    if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_UNDEFINED) {
        printf("ULP did %d temperature measurements in %d ms\n", ulp_data_read(1), sleep_time_ms);
        printf("Initial T=%d, latest T=%d\n", ulp_data_read(0), ulp_data_read(2));
    }
#endif // CONFIG_IDF_TARGET_ESP32
#endif // CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP

    vTaskDelay(1000 / portTICK_PERIOD_MS);

    const int wakeup_time_sec = 20;
    printf("Enabling timer wakeup, %ds\n", wakeup_time_sec);
    esp_sleep_enable_timer_wakeup(wakeup_time_sec * 1000000);   //设置定时器唤醒时间

#ifdef CONFIG_EXAMPLE_EXT1_WAKEUP
    const int ext_wakeup_pin_1 = 2;
    const uint64_t ext_wakeup_pin_1_mask = 1ULL << ext_wakeup_pin_1;    //配置外部唤醒引脚
    const int ext_wakeup_pin_2 = 4;
    const uint64_t ext_wakeup_pin_2_mask = 1ULL << ext_wakeup_pin_2;    //配置外部唤醒引脚

    printf("Enabling EXT1 wakeup on pins GPIO%d, GPIO%d\n", ext_wakeup_pin_1, ext_wakeup_pin_2);
    esp_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask | ext_wakeup_pin_2_mask, ESP_EXT1_WAKEUP_ANY_HIGH);//使能外部1唤醒
#endif // CONFIG_EXAMPLE_EXT1_WAKEUP

#ifdef CONFIG_EXAMPLE_GPIO_WAKEUP                                       //esp32 c3唤醒引脚
    const gpio_config_t config = {
        .pin_bit_mask = BIT(DEFAULT_WAKEUP_PIN),
        .mode = GPIO_MODE_INPUT,
    };
    ESP_ERROR_CHECK(gpio_config(&config));                              //配追引脚
    ESP_ERROR_CHECK(esp_deep_sleep_enable_gpio_wakeup(BIT(DEFAULT_WAKEUP_PIN), DEFAULT_WAKEUP_LEVEL));  //使能引脚
    printf("Enabling GPIO wakeup on pins GPIO%d\n", DEFAULT_WAKEUP_PIN);
#endif

#ifdef CONFIG_EXAMPLE_TOUCH_WAKEUP
#if CONFIG_IDF_TARGET_ESP32
    // Initialize touch pad peripheral.初始化触摸板外围设备。
    // The default fsm mode is software trigger mode。默认fsm模式为软件触发模式。
    ESP_ERROR_CHECK(touch_pad_init());
    // If use touch pad wake up, should set touch sensor FSM mode at 'TOUCH_FSM_MODE_TIMER'.
    //如果使用触摸板唤醒,应将触摸传感器 FSM 模式设置为“TOUCH_FSM_MODE_TIMER”。
    touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
    // Set reference voltage for charging/discharging 设置充电/放电参考电压
    // In this case, the high reference valtage will be 2.4V - 1V = 1.4V  在这种情况下,高参考电压将为 2.4V - 1V = 1.4V
    // The low reference voltage will be 0.5 低参考电压为 0.5
    // The larger the range, the larger the pulse count value.范围越大,脉冲计数值越大。
    //TOUCH_HVOLT_ATTEN_1V 触摸传感器高参考电压衰减,
    touch_pad_set_voltage(TOUCH_HVOLT_2V4, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V);
    //init RTC IO and mode for touch pad. 为触摸板初始化 RTC IO 和模式。
    touch_pad_config(TOUCH_PAD_NUM8, TOUCH_THRESH_NO_USE);
    touch_pad_config(TOUCH_PAD_NUM9, TOUCH_THRESH_NO_USE);
    calibrate_touch_pad(TOUCH_PAD_NUM8);
    calibrate_touch_pad(TOUCH_PAD_NUM9);
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
    /* Initialize touch pad peripheral. */
    touch_pad_init();
    /* Only support one touch channel in sleep mode. */
    touch_pad_config(TOUCH_PAD_NUM9);
    /* Denoise setting at TouchSensor 0. */
    touch_pad_denoise_t denoise = {
        /* The bits to be cancelled are determined according to the noise level. */
        .grade = TOUCH_PAD_DENOISE_BIT4,
        .cap_level = TOUCH_PAD_DENOISE_CAP_L4,
    };
    touch_pad_denoise_set_config(&denoise);
    touch_pad_denoise_enable();
    printf("Denoise function init\n");
    /* Filter setting */
    touch_filter_config_t filter_info = {
        .mode = TOUCH_PAD_FILTER_IIR_16,
        .debounce_cnt = 1,      // 1 time count.
        .noise_thr = 0,         // 50%
        .jitter_step = 4,       // use for jitter mode.
        .smh_lvl = TOUCH_PAD_SMOOTH_IIR_2,
    };
    touch_pad_filter_set_config(&filter_info);
    touch_pad_filter_enable();
    printf("touch pad filter init %d\n", TOUCH_PAD_FILTER_IIR_8);
    /* Set sleep touch pad. */
    touch_pad_sleep_channel_enable(TOUCH_PAD_NUM9, true);
    touch_pad_sleep_channel_enable_proximity(TOUCH_PAD_NUM9, false);
    /* Reducing the operating frequency can effectively reduce power consumption. */
    touch_pad_sleep_channel_set_work_time(1000, TOUCH_PAD_MEASURE_CYCLE_DEFAULT);
    /* Enable touch sensor clock. Work mode is "timer trigger". */
    touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
    touch_pad_fsm_start();
    vTaskDelay(100 / portTICK_RATE_MS);

    /* set touchpad wakeup threshold */
    uint32_t touch_value, wake_threshold;
    touch_pad_sleep_channel_read_smooth(TOUCH_PAD_NUM9, &touch_value);
    wake_threshold = touch_value * 0.1; // wakeup when touch sensor crosses 10% of background level
    touch_pad_sleep_set_threshold(TOUCH_PAD_NUM9, wake_threshold);
    printf("Touch pad #%d average: %d, wakeup threshold set to %d\n",
        TOUCH_PAD_NUM9, touch_value, (uint32_t)(touch_value * 0.1));
#endif
    printf("Enabling touch pad wakeup\n");
    esp_sleep_enable_touchpad_wakeup();
    esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
#endif // CONFIG_EXAMPLE_TOUCH_WAKEUP

#ifdef CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP
#if CONFIG_IDF_TARGET_ESP32
    printf("Enabling ULP wakeup\n");
    esp_sleep_enable_ulp_wakeup();
#endif
#endif

#if CONFIG_IDF_TARGET_ESP32
    // Isolate GPIO12 pin from external circuits. This is needed for modules
    // which have an external pull-up resistor on GPIO12 (such as ESP32-WROVER)
    // to minimize current consumption.
    rtc_gpio_isolate(GPIO_NUM_12);
#endif

    printf("Entering deep sleep\n");
    gettimeofday(&sleep_enter_time, NULL);

#ifdef CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP
#if CONFIG_IDF_TARGET_ESP32
    start_ulp_temperature_monitoring();
#endif
#endif

    esp_deep_sleep_start();
}

#ifdef CONFIG_EXAMPLE_TOUCH_WAKEUP
#if CONFIG_IDF_TARGET_ESP32
static void calibrate_touch_pad(touch_pad_t pad)
{
    int avg = 0;
    const size_t calibration_count = 128;
    for (int i = 0; i < calibration_count; ++i) {
        uint16_t val;
        touch_pad_read(pad, &val);
        avg += val;
    }
    avg /= calibration_count;
    const int min_reading = 300;
    if (avg < min_reading) {
        printf("Touch pad #%d average reading is too low: %d (expecting at least %d). "
               "Not using for deep sleep wakeup.\n", pad, avg, min_reading);
        touch_pad_config(pad, 0);
    } else {
        int threshold = avg - 100;
        printf("Touch pad #%d average: %d, wakeup threshold set to %d.\n", pad, avg, threshold);
        touch_pad_config(pad, threshold);
    }
}
#endif
#endif // CONFIG_EXAMPLE_TOUCH_WAKEUP

#ifdef CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP
#if CONFIG_IDF_TARGET_ESP32
static void start_ulp_temperature_monitoring(void)
{
    /*
     * This ULP program monitors the on-chip temperature sensor and wakes the chip up when
     * the temperature goes outside of certain window.
     * When the program runs for the first time, it saves the temperature measurement,
     * it is considered initial temperature (T0).
     *
     * On each subsequent run, temperature measured and compared to T0.
     * If the measured value is higher than T0 + max_temp_diff or lower than T0 - max_temp_diff,
     * the chip is woken up from deep sleep.
     */

    /* Temperature difference threshold which causes wakeup
     * With settings here (TSENS_CLK_DIV=2, 8000 cycles),
     * TSENS measurement is done in units of 0.73 degrees Celsius.
     * Therefore, max_temp_diff below is equivalent to ~2.2 degrees Celsius.
     */
    const int16_t max_temp_diff = 3;

    // Number of measurements ULP should do per second
    const uint32_t measurements_per_sec = 5;

    // Allow TSENS to be controlled by the ULP
    SET_PERI_REG_BITS(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_CLK_DIV, 2, SENS_TSENS_CLK_DIV_S);
    SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 3, SENS_FORCE_XPD_SAR_S);
    CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP);
    CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_DUMP_OUT);
    CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP_FORCE);

    // Clear the part of RTC_SLOW_MEM reserved for the ULP. Makes debugging easier.
    memset(RTC_SLOW_MEM, 0, CONFIG_ESP32_ULP_COPROC_RESERVE_MEM);

    // The first word of memory (at data offset) is used to store the initial temperature (T0)
    // Zero it out here, then ULP will update it on the first run.
    ulp_data_write(0, 0);
    // The second word is used to store measurement count, zero it out as well.
    ulp_data_write(1, 0);

    const ulp_insn_t program[] = {
        // load data offset into R2
        I_MOVI(R2, ULP_DATA_OFFSET),
        // load/increment/store measurement counter using R1
        I_LD(R1, R2, 1),
        I_ADDI(R1, R1, 1),
        I_ST(R1, R2, 1),
        // enable temperature sensor
        I_WR_REG(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_S, SENS_FORCE_XPD_SAR_S + 1, 3),
        // do temperature measurement and store result in R3
        I_TSENS(R3, 8000),
        // disable temperature sensor
        I_WR_REG(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_S, SENS_FORCE_XPD_SAR_S + 1, 0),
        // Save current measurement at offset+2
        I_ST(R3, R2, 2),
        // load initial value into R0
        I_LD(R0, R2, 0),
        // if threshold value >=1 (i.e. initialized), goto 1
        M_BGE(1, 1),
            // otherwise, save the current value as initial (T0)
            I_MOVR(R0, R3),
            I_ST(R0, R2, 0),
        M_LABEL(1),
        // check if the temperature is greater or equal (T0 + max_temp_diff)
        // uses R1 as scratch register, difference is saved at offset + 3
        I_ADDI(R1, R0, max_temp_diff - 1),
        I_SUBR(R1, R1, R3),
        I_ST(R1, R2, 3),
        M_BXF(2),
        // check if the temperature is less or equal (T0 - max_temp_diff)
        // uses R1 as scratch register, difference is saved at offset + 4
        I_SUBI(R1, R0, max_temp_diff - 1),
        I_SUBR(R1, R3, R1),
        I_ST(R1, R2, 4),
        M_BXF(2),
            // temperature is within (T0 - max_temp_diff; T0 + max_temp_diff)
            // stop ULP until the program timer starts it again
            I_HALT(),
        M_LABEL(2),
            // temperature is out of bounds
            // disable ULP program timer
            I_WR_REG_BIT(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN_S, 0),
            // initiate wakeup of the SoC
            I_WAKE(),
            // stop the ULP program
            I_HALT()
    };

    // Load ULP program into RTC_SLOW_MEM, at offset 0
    size_t size = sizeof(program)/sizeof(ulp_insn_t);
    ESP_ERROR_CHECK( ulp_process_macros_and_load(0, program, &size) );
    assert(size < ULP_DATA_OFFSET && "ULP_DATA_OFFSET needs to be greater or equal to the program size");

    // Set ULP wakeup period
    const uint32_t sleep_cycles = rtc_clk_slow_freq_get_hz() / measurements_per_sec;
    REG_WRITE(SENS_ULP_CP_SLEEP_CYC0_REG, sleep_cycles);

    // Start ULP
    ESP_ERROR_CHECK( ulp_run(0) );
}
#endif // CONFIG_IDF_TARGET_ESP32
#endif // CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP

六、Deep-sleep 实验演示结果

??分别为定时器唤醒和触摸唤醒。
在这里插入图片描述
在这里插入图片描述

七、ESP32 Sleep.h文件中的API

/**
* @brief用于EXT1唤醒模式的逻辑功能。
*/
typedef enum {
    ESP_EXT1_WAKEUP_ALL_LOW = 0//!<当所有选定的gpio都下降时唤醒芯片
    ESP_EXT1_WAKEUP_ANY_HIGH = 1    //!<当任何选定的gpio上升时唤醒芯片
} esp_sleep_ext1_wakeup_mode_t;

# if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
typedef enum {
    ESP_GPIO_WAKEUP_GPIO_LOW = 0,
    ESP_GPIO_WAKEUP_GPIO_HIGH = 1
} esp_deepsleep_gpio_wake_up_mode_t;
# endif

/**
* @brief可以在睡眠模式下下电的电源域
*/
typedef enum {
    ESP_PD_DOMAIN_RTC_PERIPH ,      //!< RTC IO,传感器和ULP协处理器
    ESP_PD_DOMAIN_RTC_SLOW_MEM,     //!< RTC慢内存
    ESP_PD_DOMAIN_RTC_FAST_MEM,     //!< RTC快速存储器
    ESP_PD_DOMAIN_XTAL ,            //!< 晶体振荡器
    #if SOC_PM_SUPPORT_CPU_PD
    ESP_PD_DOMAIN_CPU ,             //!< CPU核心
    # endif
    ESP_PD_DOMAIN_RTC8M ,           //!< 内部8M振荡器
    ESP_PD_DOMAIN_VDDSDIO ,         //!< VDD_SDIO
    ESP_PD_DOMAIN_MAX               //!< 域个数
} esp_sleep_pd_domain_t;

/**
* @brief关闭电源选项
*/
typedef enum {
    ESP_PD_OPTION_OFF ,      //!<在休眠模式下关闭电源域
    ESP_PD_OPTION_ON ,       //!<在休眠模式下保持电源域启用
    ESP_PD_OPTION_AUTO       //!<保持电源域在睡眠模式下启用,如果需要唤醒选项之一。否则关闭电源。
} esp_sleep_pd_option_t;

/**
* @brief睡眠唤醒原因
*/
typedef enum {
    ESP_SLEEP_WAKEUP_UNDEFINED,     //!<在深度睡眠的情况下,从深度睡眠退出不是导致重置
    ESP_SLEEP_WAKEUP_ALL ,          //!<非唤醒原因,使用esp_sleep_disable_wakeup_source禁用所有唤醒源
    ESP_SLEEP_WAKEUP_EXT0 ,         //!<由外部信号RTC_IO引起的唤醒
    ESP_SLEEP_WAKEUP_EXT1 ,         //!<使用RTC_CNTL由外部信号引起的唤醒
    ESP_SLEEP_WAKEUP_TIMER ,        //!<定时器引起的唤醒
    ESP_SLEEP_WAKEUP_TOUCHPAD,      //!<touchpad引起的唤醒
    ESP_SLEEP_WAKEUP_ULP ,          //!<ULP程序导致的唤醒
    ESP_SLEEP_WAKEUP_GPIO ,         //!<GPIO导致的唤醒(仅为轻度睡眠)
    ESP_SLEEP_WAKEUP_UART ,         //!<UART引起的觉醒(仅轻度睡眠)
    ESP_SLEEP_WAKEUP_WIFI ,         //!< WIFI引起的唤醒(仅限轻度睡眠)
    ESP_SLEEP_WAKEUP_COCPU ,        //!<由COCPU引起的唤醒int
    ESP_SLEEP_WAKEUP_COCPU_TRAP_TRIG,//!<由COCPU崩溃引起的唤醒
    ESP_SLEEP_WAKEUP_BT ,           //!< BT引起的醒来(仅轻度睡眠)
} esp_sleep_source_t;

/*保留此类型定义以兼容*/
typedef esp_sleep_source_t esp_sleep_wakeup_cause_t;

/**
* @brief关闭唤醒源
* 此函数用于关闭源唤醒触发器
* 定义为函数的参数。
* @note该功能不修改RTC的唤醒配置。
* 它将在esp_sleep_start函数中执行。
* 看到文档/睡眠模式。rst的细节。
* @param source -要禁用esp_sleep_source_t类型的源的数量
* @return
* - ESP_OK表示成功
* -如果触发器未激活,则执行ESP_ERR_INVALID_STATE
*/
esp_err_t esp_sleep_disable_wakeup_source (esp_sleep_source_t source);

#if SOC_ULP_SUPPORTED
/**
* @brief开启ULP协处理器唤醒功能
* @note在修订0和1的ESP32, ULP唤醒源
* 强制RTC_PERIPH电源域时,*不能使用
* 上电(ESP_PD_OPTION_ON)或when
* 使用ext0唤醒源
* @return
* - ESP_OK表示成功
* - esp_err_not_支持,如果附加电流的触摸(CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT)是enabled。
如果ULP协处理器未启用或唤醒触发冲突,则为ESP_ERR_INVALID_STATE
*/
esp_err_t esp_sleep_enable_ulp_wakeup(void);

# endif // SOC_ULP_SUPPORTED

/**
* @brief开启定时唤醒功能
* @param time_in_us起床前时间,单位为微秒
* @return
* - ESP_OK表示成功
* - ESP_ERR_INVALID_ARG,如果值超出范围(待定)
*/
esp_err_t esp_sleep_enable_timer_wakeup (uint64_t time_in_us);

#if SOC_TOUCH_SENSOR_NUM > 0

/**
* @brief允许触摸传感器唤醒
* @注在ESP32的修订版0和1中,触摸唤醒源
* 强制RTC_PERIPH电源域时,*不能使用
* 被上电(ESP_PD_OPTION_ON)或当ext0唤醒
* 使用* source。
* @note需配置触摸按钮的FSM模式
* 作为定时器触发模式。
* @return
* - ESP_OK表示成功
* - esp_err_not_支持,如果附加电流的触摸(CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT)是enabled。
* - ESP_ERR_INVALID_STATE如果唤醒触发冲突
*/
esp_err_t esp_sleep_enable_touchpad_wakeup(void);


/**
* @brief获得引起唤醒的触摸板
* 如果唤醒是由另一个源引起的,这个函数将返回TOUCH_PAD_MAX;
* @返回触摸板引起唤醒
*/
touch_pad_t esp_sleep_get_touchpad_wakeup_status(void);

#endif // SOC_TOUCH_SENSOR_NUM > 0 .日志含义

/**
* @brief返回true,如果GPIO number可用作唤醒源。
* @note对于具有RTC IO功能的soc,这可以是任何有效的RTC IO输入引脚。
* @param gpio_num用于测试唤醒源能力的GPIO数量
* 如果GPIO number被接受为睡眠唤醒源,则返回True。
*/
bool esp_sleep_is_valid_wakeup_gpio (gpio_num_t gpio_num);

#if SOC_PM_SUPPORT_EXT_WAKEUP

/**
* @brief使用引脚唤醒
* 该函数使用RTC_IO外设的外部唤醒特性。
* 只有在RTC外设处于睡眠状态时才会工作。
* 这个功能可以监控任何RTC IO的引脚。一旦引脚转换
* 进入level argument给出的状态,芯片将被唤醒。
* @注:此函数不修改引脚配置。销是
* 配置在esp_sleep_start,立即进入睡眠模式。
* @note ESP32的修订版0和1中,ext0唤醒源
* 不能与触摸或ULP唤醒源一起使用。
* @param gpio_num用作唤醒源的GPIO编号。只有gpio有RTC
* 功能可使用:0、2、4、12-15、25-27、32-39。
* @param level将触发唤醒的输入级别(0=low, 1=high)
* @return
* - ESP_OK表示成功
* -如果选择的GPIO不是RTC GPIO,则为ESP_ERR_INVALID_ARG
* 或模式void
* - ESP_ERR_INVALID_STATE如果唤醒触发冲突
*/
Esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level);

/**
* @brief使用多个引脚唤醒
* 此功能使用RTC控制器的外部唤醒功能。
* 即使RTC外设在睡眠期间关闭,它也会工作。
* 这个功能可以监控任何数量的引脚,这是在RTC IOs。
* 一旦任何被选中的引脚进入mode参数给定的状态,
* 芯片将被唤醒。
* @注:此函数不修改引脚配置。针是
* 配置在esp_sleep_start,紧接之前
* 进入睡眠模式。
* @note内部拉和拉下不工作时,RTC外设是
* 关闭。此时需要增加外接电阻。
* 或者,RTC外设(和下拉/下拉)可能是
* 使用esp_sleep_pd_config函数保持启用。
* @param mask会导致GPIO唤醒的数字的掩码。只有GPIOs
* 有RTC功能可以在这个位图中使用:
*              0、2、4、12 - 15、25 - 27日32-39。
* @param模式选择逻辑函数,用于确定唤醒条件:
* —ESP_EXT1_WAKEUP_ALL_LOW:当所有选择的gpio都是低时唤醒
* —ESP_EXT1_WAKEUP_ANY_HIGH:当所选gpio为高时唤醒
* @return
* - ESP_OK表示成功
* -如果所选GPIO不是RTC GPIO,则为ESP_ERR_INVALID_ARG
* 或模式void
*/
Esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask,esp_sleep_ext1_wakeup_mode_t mode);

# endif // SOC_PM_SUPPORT_EXT_WAKEUP

#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
/**
* 使用特定的gpio引脚启用唤醒
* 此功能使IO引脚从深度睡眠唤醒芯片
* @注:此函数不修改引脚配置。针是
* 配置在esp_sleep_start,紧接之前
* 进入睡眠模式。
* @note你不需要关心上拉或下拉之前使用这个
* 函数,因为这将在esp_sleep_start基于
* 你给的参数掩码。顺便说一句,当你用低水平唤醒
* 芯片,我们强烈建议您添加外部寄存器(上拉式)。
* @param gpio_pin_mask GPIO唤醒码位掩码。只有GPIOs
* 有RTC功能可以在这个位图中使用。
* @param mode选择用于确定唤醒条件的逻辑函数:
* —“ESP_GPIO_WAKEUP_GPIO_LOW”表示gpio灯变低时唤醒。
* —ESP_GPIO_WAKEUP_GPIO_HIGH: gpio调高时唤醒。
* @return
* - ESP_OK表示成功
* 如果gpio num大于5或modevoid,则为ESP_ERR_INVALID_ARG
*/
Esp_err_t esp_deep_sleep_enable_gpio_wakeup(uint64_t gpio_pin_mask, esp_deepsleep_gpio_wake_up_mode_t mode);
# endif
/**
* 使用gpio开启轻睡眠唤醒功能
* 每个GPIO都支持唤醒功能,可以在任意低电平触发
* 或高水平。与EXT0和EXT1唤醒源不同,可以使用此方法
* 适用于所有IOs: RTC IOs和数字IOs。它只能用来唤醒
* 不过睡眠很浅。
* 要启用唤醒,首先调用gpio_wakeup_enable,指定gpio number和
* 唤醒级别,用于每个GPIO的唤醒。
* 然后调用此功能来启用唤醒功能。
* @note在修订0和1的ESP32, GPIO唤醒源
* 不能与触摸或ULP唤醒源一起使用。
* @return
* - ESP_OK表示成功
* - ESP_ERR_INVALID_STATE如果唤醒触发冲突
*/
esp_err_t esp_sleep_enable_gpio_wakeup(void);

/**
* 使用UART从轻度睡眠中唤醒
* 使用uart_set_wakeup_threshold功能配置UART唤醒阈值。
* 从浅睡眠中醒来需要一些时间,所以不是每个字符都发送
* 到UART可以收到的申请。
* @note ESP32不支持UART2唤醒。
* @param uart_num UART端口被唤醒
* @return
* - ESP_OK表示成功
* -如果UART不支持唤醒,则为ESP_ERR_INVALID_ARG
*/
esp_err_t esp_sleep_enable_uart_wakeup (int uart_num);

/**
* @brief WiFi MAC唤醒
* @return
* - ESP_OK表示成功
*/
esp_err_t esp_sleep_enable_wifi_wakeup(void);

/**
* @brief禁用WiFi MAC唤醒功能
* @return
* - ESP_OK表示成功
*/
esp_err_t esp_sleep_disable_wifi_wakeup(void);

/**
* 获取导致唤醒的gpio的掩码(ext1)
* 如果唤醒是由其他源引起的,这个函数将返回0。
* @返回位掩码,如果GPIOn引起唤醒,bit (n)将被设置
*/
uint64_t esp_sleep_get_ext1_wakeup_status(void);

#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
/**
* 获取gpio (gpio)的位掩码
*如果唤醒是由其他源引起的,这个函数将返回0。
* @返回位掩码,如果GPIOn引起唤醒,bit (n)将被设置
*/
uint64_t esp_sleep_get_gpio_wakeup_status(void);
# endif // SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP

/**
* @brief将RTC电源域设置为休眠模式
* 如果没有使用此API设置,所有电源域默认为ESP_PD_OPTION_AUTO。
* @param域电源域配置
* @param选项下电选项(ESP_PD_OPTION_OFF, ESP_PD_OPTION_ON, ESP_PD_OPTION_AUTO)
* @return
* - ESP_OK表示成功
* -如果参数超出范围,则为ESP_ERR_INVALID_ARG
*/
esp_err_t esp_sleep_pd_config (esp_sleep_pd_domain_t domain,esp_sleep_pd_option_t option);

/**
* @brief进入深度睡眠与配置的唤醒选项
* 这个函数不返回。
*/
void esp_deep_sleep_start(void) __attribute__((noreturn));

/**
* @brief进入轻睡眠与配置的唤醒选项
* @return
* - ESP_OK返回成功(在唤醒后返回)
* -如果WiFi或BT未停止,则为ESP_ERR_INVALID_STATE
*/
esp_err_t esp_light_sleep_start(void);

/**
* @brief进入深度睡眠模式
* 设备在达到深度睡眠时间后自动唤醒
* 唤醒时,设备调用深度睡眠唤醒存根,然后继续
* 加载应用程序。
* 调用该函数相当于调用esp_deep_sleep_enable_timer_wakeup
* 后跟对esp_deep_sleep_start的调用。
* esp_deep_sleep不关闭WiFi、BT和更高级别协议
* 连接优雅。
* 确保相关的WiFi和BT栈功能被调用来关闭任何
* 连接和反初始化外设。这些包括:
* ——esp_bluedroid_disable
* ——esp_bt_controller_disable
* ——esp_wifi_stop
* 这个函数不返回。
* @注意如果深度睡眠时间设置为0,设备将立即唤醒
* @param time_in_us深度睡眠时间,单位微秒
*/
void esp_deep_sleep(uint64_t time_in_us) __attribute__((noreturn));

/**
* @brief从睡眠中获取唤醒源
* @从上次睡眠中醒来的原因(深度睡眠或浅睡眠)
*/
esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void);

/**
* @brief默认存根运行从深度睡眠唤醒。
*允许执行代码立即从睡眠,之前
*软件引导加载程序或ESP-IDF应用程序已启动。
*这个函数是弱链接的,所以你可以实现自己的版本
*当芯片唤醒时立即运行代码
*睡眠。
*看到文档/ deep-sleep-stub。rst的细节。
*/
void esp_wake_deep_sleep(void);

/**
* @brief函数类型的存根运行从睡眠唤醒。
*/
typedefvoid(* esp_deep_sleep_wake_stub_fn_t)(void);

/**
* @brief在运行时安装一个新的存根,以运行从深度睡眠唤醒
* 如果实现了esp_wake_deep_sleep(),则没有必要
* 调用这个函数。
* 但是,可以调用这个函数来替换a
* 不同的深度睡眠存根。用作深度睡眠存根的任何函数
* 必须标记为RTC_IRAM_ATTR,并且必须遵守相同的规则
* esp_wake_deep_sleep *()。
*/
voidesp_set_deep_sleep_wake_stub (esp_deep_sleep_wake_stub_fn_t new_stub);

/**
* @brief从深度睡眠获取当前唤醒存根
* @return从深度睡眠存根返回当前唤醒,如果返回则为NULL
* 没有安装存根。
*/
esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void);

/**
* 默认的esp_wake_deep_sleep()存根。
* 看到文档/ deep-sleep-stub。rst的细节。
*/
voidesp_default_wake_deep_sleep(void);

/**
* @brief在深度睡眠后从ROM代码禁用日志记录。
* 使用RTC_STORE4的LSB。
*/
voidesp_deep_sleep_disable_rom_logging(void);

# ifdef SOC_PM_SUPPORT_CPU_PD
/**
* @brief CPU Power down低级初始化
* @param enable在轻度睡眠时启用或禁用CPU电源关闭
* @return
* - ESP_OK表示成功
* - ESP_ERR_NO_MEM内存不足
*/
esp_err_t esp_sleep_cpu_pd_low_init (bool enable);
# endif

#if SOC_GPIO_SUPPORT_SLP_SWITCH
/**
* 配置隔离休眠状态下的所有GPIO引脚
*/
voidesp_sleep_config_gpio_isolate(void);

/**
GPIO引脚在休眠和唤醒状态之间切换的开关。
* @param enable决定是否切换状态
*/
voidesp_sleep_enable_gpio_switch (bool enable);
# endif

#if CONFIG_MAC_BB_PD
/**
* @brief用于stub运行mac bb power down的函数类型。
*/
typedef void (* mac_bb_power_down_cb_t)(void);

/**
* @brief用于stub运行mac bb的功能类型。
*/
typedef void (* mac_bb_power_up_cb_t)(void);

/**
* @brief注册mac bb断电回调。
* @param cb MAC bb power down callback。
* @return
* - ESP_OK表示成功
*/
esp_err_t esp_register_mac_bb_pd_callback (mac_bb_power_down_cb_t cb);

/**
* @brief取消注册mac bb掉电回调。
* @param cb MAC bb power down callback。
* @return
* - ESP_OK表示成功
*/
esp_err_t esp_unregister_mac_bb_pd_callback (mac_bb_power_down_cb_t cb);

/**
@brief注册mac bb上电回调。
@param cb MAC bb上电回调。
* @return
* - ESP_OK表示成功
*/
esp_err_t esp_register_mac_bb_pu_callback (mac_bb_power_up_cb_t cb);

/**
* @brief取消注册mac bb上电回调。
@param cb MAC bb上电回调。
* @return
* - ESP_OK表示成功
*/
esp_err_t esp_unregister_mac_bb_pu_callback (mac_bb_power_up_cb_t cb);
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-05-26 15:21:58  更:2022-05-26 15:22:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:56:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码