ESP32 系列芯片提供三种可配置的睡眠模式,针对这些睡眠模式,我们提供了了多种低功耗解决方案,用户可以结合具体需求选择睡眠模式并进行配置。
三种睡眠模式如下:
Modem-sleep 模式:CPU 可运行,时钟可被配置。Wi-Fi/蓝牙基带和射频关闭。
Light-sleep 模式:CPU 暂停运行,Wi-Fi/蓝牙基带和射频关闭。RTC 存储器和外设以及 ULP 协处理器运行。任何唤醒事件(MAC、主机、RTC 定时器或外部中断)都会唤醒芯片。
Deep-sleep 模式:CPU 和大部分外设都会掉电,Wi-Fi/蓝牙基带和射频关闭,只有 RTC 存储器和 RTC 外设以及 ULP 协处理器可以工作。Wi-Fi 和蓝牙连接数据存储在 RTC 中
ESP32 在内置 Deep-sleep 低功耗模式、RTC 外设和 ULP 协处理器的支持下,可以满足多种应用场景下的低功耗需求。当 ESP32 进入 Deep-sleep 模式时,所有由 APB_CLK 驱动的外设、CPU 和 RAM 将掉电;RTC_CLK 继续工作;RTC 控制器、RTC 外设、ULP 协处理器、RTC 快速内存和 RTC 慢速内存可以不掉电,具体取决于 App 中的唤醒源设置。
资源包括:
RTC 外设 – 包括片上温度传感器、ADC、RTC GPIO 和 touchpad;
ULP 协处理器 – 可在 Deep-sleep 模式下,进行简单的数据采集或作为一种唤醒源。协处理器可以访问 RTC 慢速内存和 RTC 寄存器;
RTC 快速内存 – 芯片从 Deep-sleep 模式下唤醒后不会马上执行 bootloader,而是会先执行存放在 RTC 快速内存中的 esp_wake_deep_sleep() 函数;
RTC 慢速内存 – 存放 ULP 协处理器和 wake stub 代码访问的数据。
Deep-sleep 模式下支持的唤醒源包括:
1)定时器
2)touchpad
3)Ext(0):RTC IO 中某个指定 GPIO 满足指定电平即唤醒
4)Ext(1):RTC IO 中某些指定 GPIO 同时满足指定电平即唤醒
5)ULP 协处理器
使用RTC IO 外部引脚触发唤醒例程
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h" //任务
#include "freertos/queue.h" //消息队列头文件
#include "freertos/semphr.h" //信号量头文件
#include "freertos/event_groups.h" //事件头文件
#include "freertos/timers.h" //软件定时器头文件
#include "driver/gpio.h"
#include "driver/ledc.h" //LED PWM控制
#include "driver/uart.h" //串口
#include "driver/i2c.h" //I2C
//#include "ble_ancs.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
//蓝牙头文件
#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_gatt_common_api.h"
//
#include <time.h>
#include <sys/time.h>
#include "esp_sleep.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_log.h"
#include "sdkconfig.h"
//软件定时器
static TimerHandle_t Time_1500_Handle = NULL; //软件定时器句柄
static TimerHandle_t Time_3000_Handle = NULL; //软件定时器句柄
static uint32_t Time_1500_Count = 0; //记录软件定时器回调函数执行的次数
static uint32_t Time_3000_Count = 0;
//GPIO定义
#define BLINK_GPIO GPIO_NUM_2
#define BLINK_GPIO22 GPIO_NUM_22
#define Key_GPIO GPIO_NUM_21
#define Key2_GPIO GPIO_NUM_19
//Deep_sleep
static TaskHandle_t Deep_Sleep_Task_Handle = NULL; //深度睡眠句柄
static TaskHandle_t APPTaskCreat_Handle = NULL; //任务句柄
//GPIO初始化
void GPIO_init()
{
gpio_reset_pin(BLINK_GPIO);
gpio_reset_pin(BLINK_GPIO22);
gpio_reset_pin(GPIO_NUM_23);
gpio_reset_pin(Key_GPIO);
gpio_reset_pin(Key2_GPIO);
gpio_reset_pin(GPIO_NUM_12);
/* Set the GPIO as a push/pull output */
gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
gpio_set_direction(BLINK_GPIO22, GPIO_MODE_OUTPUT);
gpio_set_direction(GPIO_NUM_23, GPIO_MODE_OUTPUT);
gpio_set_direction(Key_GPIO, GPIO_MODE_INPUT);
gpio_set_direction(Key2_GPIO, GPIO_MODE_INPUT);
gpio_set_direction(GPIO_NUM_12, GPIO_MODE_INPUT);
gpio_set_level(BLINK_GPIO, 0);
gpio_set_level(BLINK_GPIO22, 0);
}
//软件定时器
void Time_1500_Callback(void *arg)
{
TickType_t tick_num1;
Time_1500_Count++;
tick_num1 = xTaskGetTickCount();
printf("Time_1500_Callback函数执行 %d 次\r\n", Time_1500_Count);
printf("定时器数值= %d 次\r\n", tick_num1);
}
void Time_3000_Callback(void *arg)
{
TickType_t tick_num2;
Time_3000_Count++;
tick_num2 = xTaskGetTickCount();
printf("Time_3000_Callback函数执行 %d 次\r\n", Time_3000_Count);
printf("定时器数值= %d 次\r\n", tick_num2);
}
void Creat_Time_init()
{
Time_1500_Handle = xTimerCreate("Time1500", //定时器名称
1500 / portTICK_PERIOD_MS, //定时器周期 1500ms
pdTRUE, //周期模式
1, //索引唯一ID
Time_1500_Callback); //回调函数
if (Time_1500_Handle != NULL)
{
xTimerStart(Time_1500_Handle, 0); //开启定时器
}
Time_3000_Handle = xTimerCreate("Time3000", //定时器名称
3000 / portTICK_PERIOD_MS, //定时器周期 3000ms
pdTRUE, //周期模式
2, //索引唯一ID
Time_3000_Callback); //回调函数
if (Time_3000_Handle != NULL)
{
xTimerStart(Time_3000_Handle, 0); //开启定时器
}
}
void Deep_Sleep_Task_Function(void *arg)
{
while (1)
{
if (Time_3000_Count==10)
{
switch (esp_sleep_get_wakeup_cause())
{
case ESP_SLEEP_WAKEUP_EXT0:
{
Time_3000_Count=0;
printf("Wake up\r\n");
}
case ESP_SLEEP_WAKEUP_UNDEFINED: //未定义,不是唤醒
default:
printf("Not a deep sleep reset\n");
}
esp_sleep_enable_ext0_wakeup(GPIO_NUM_12, 0);//RTC IO,低电平唤醒
gpio_set_level(BLINK_GPIO, 0);
gpio_set_level(BLINK_GPIO22, 0);
printf("a deep sleep start\n");
esp_deep_sleep_start();
}
vTaskDelay(100 / portTICK_RATE_MS);
}
}
//总任务的创建
void APPTaskCreat_Function(void *arg)
{
GPIO_init();
// Creat_Queue_init();
// Binary_Create_init();
// Event_Create_init();
Creat_Time_init();
// NVS_Flash_init();
// I2C0_init();
// ATH10_init();
// NVS_Task_Function();
BaseType_t xReturn = pdPASS;
xReturn = xTaskCreate(Deep_Sleep_Task_Function, //任务函数
"Deep_Sleep_Task", //任务名称
4096, //任务栈大小
NULL, //任务入口函数参数
2, //任务优先级
&Deep_Sleep_Task_Handle); //句柄
if (pdPASS == xReturn)
{
// printf("Deep_Sleep_Task任务创建成功\r\n");
}
// xReturn = xTaskCreate(CPU_Task_Function, //任务函数
// "CPU_Task", //任务名称
// 2048, //任务栈大小
// NULL, //任务入口函数参数
// 2, //任务优先级
// NULL); //句柄
// if (pdPASS == xReturn)
// {
// // printf("CPU_Task任务创建成功\r\n");
// }
// printf("删除APPTask任务成功\r\n");
vTaskDelete(APPTaskCreat_Handle); //删除任务
}
void app_main(void)
{
xTaskCreatePinnedToCore(APPTaskCreat_Function, //任务函数
"APPTaskCreat", //任务名称
2048, //任务栈大小
NULL, //任务入口函数参数
1, //任务优先级
&APPTaskCreat_Handle, //任务句柄
tskNO_AFFINITY); //指定运行任务的CPU,使用这个宏表示不会固定到任何核上
// xReturn=xTaskCreate(APPTaskCreat_Function,//任务函数
// "APPTaskCreat",//任务名称
// 2048,//任务栈大小
// NULL,//任务入口函数参数
// 1,//任务优先级
// &APPTaskCreat_Handle);
// configASSERT( APPTaskCreat_Handle );
// //启动任务调度器
// if (pdPASS==xReturn)
// {
// /* code */
// // vTaskStartScheduler();
// printf("启动任务,开启调度器成功\r\n");
// }
// else
// {
// return (-1);
// }
// while(1);
}
效果:实现30秒休眠,唤醒后运行30秒后再休眠以此反复
结果
作者:小梦小图 https://www.bilibili.com/read/cv13635271 出处:bilibili