ESP32 поддерживает несколько режимов глубокого сна (Deep Sleep), которые позволяют значительно снизить энергопотребление. В отличие от ATmega2560, ESP32 имеет встроенные механизмы для автоматического пробуждения по таймеру, сенсорам или внешним сигналам.

1. Режимы глубокого сна в ESP32

ESP32 предлагает три основных режима энергосбережения:

Режим Потребление Что отключено? Как можно разбудить?
Modem Sleep ~20 mA Wi-Fi/BT Любое прерывание
Light Sleep ~0.8 mA CPU, периферия Таймер, GPIO, UART
Deep Sleep ~5–150 µA CPU, Wi-Fi/BT, RAM Таймер, TouchPad, EXT0/EXT1, ULP-процессор

Deep Sleep — самый экономичный режим, при котором:

  • Отключается основной процессор (CPU).

  • Очищается оперативная память (RAM) (сохраняются только RTC-регистры).

  • Работает только RTC-блок (для пробуждения).

  • ULP-процессор (Ultra Low Power) может работать и мониторить датчики.

2. Как включить Deep Sleep на ESP32

2.1. Пробуждение по таймеру (через esp_sleep_enable_timer_wakeup)

Микроконтроллер просыпается через заданное время (в микросекундах).

 
#include <esp_sleep.h>

void setup() {
  Serial.begin(115200);
  Serial.println("ESP32 в Deep Sleep на 10 секунд...");
  
  // Настройка пробуждения по таймеру (в микросекундах)
  esp_sleep_enable_timer_wakeup(10 * 1000000); // 10 секунд
  
  // Переход в Deep Sleep
  esp_deep_sleep_start();
}

void loop() {}  // Не используется в Deep Sleep

2.2. Пробуждение по кнопке (EXT0 / EXT1)

  • EXT0 — пробуждение по одному пину (например, кнопка на GPIO2).

  • EXT1 — пробуждение по нескольким пинам (логическое ИЛИ/И).

Пример (пробуждение по GPIO2):

 
#include <esp_sleep.h>

void setup() {
  Serial.begin(115200);
  Serial.println("ESP32 в Deep Sleep. Нажмите кнопку на GPIO2 для пробуждения.");
  
  // Настройка пробуждения по GPIO2 (HIGH-уровень)
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_2, HIGH);
  
  // Переход в Deep Sleep
  esp_deep_sleep_start();
}

void loop() {}  // Не используется

2.3. Пробуждение по сенсору TouchPad

ESP32 может просыпаться от прикосновения к сенсорным пинам (TouchPad).

 
#include <esp_sleep.h>
#include <driver/touch_pad.h>

void setup() {
  Serial.begin(115200);
  Serial.println("ESP32 в Deep Sleep. Коснитесь TouchPad для пробуждения.");
  
  // Настройка TouchPad (например, GPIO4 - Touch0)
  touch_pad_init();
  touch_pad_config(TOUCH_PAD_NUM0);  // Touch0 на GPIO4
  
  // Настройка пробуждения по TouchPad
  esp_sleep_enable_touchpad_wakeup();
  
  // Переход в Deep Sleep
  esp_deep_sleep_start();
}

void loop() {}  // Не используется

2.4. Пробуждение от ULP-процессора

ULP (Ultra Low Power) — сопроцессор, который может работать в Deep Sleep и будить ESP32 по событию (например, по данным с датчика).

 
#include <esp_sleep.h>
#include <driver/rtc_io.h>
#include <ulp_main.h>  // Требуется прошивка ULP

extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
extern const uint8_t ulp_main_bin_end[]   asm("_binary_ulp_main_bin_end");

void setup() {
  Serial.begin(115200);
  Serial.println("ESP32 в Deep Sleep. ULP может разбудить.");
  
  // Загрузка программы ULP
  ulp_load_binary(0, ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start));
  
  // Настройка пробуждения от ULP
  esp_sleep_enable_ulp_wakeup();
  
  // Переход в Deep Sleep
  esp_deep_sleep_start();
}

void loop() {}  // Не используется

3. Как сохранить данные между сном и пробуждением?

Поскольку в Deep Sleep ОЗУ очищается, нужно использовать:

  • RTC Slow Memory (сохраняется между циклами сна).

  • EEPROM (если нужно долговременное хранение).

  • Флеш-память (но это медленно и изнашивает память).

Пример сохранения переменной в RTC-память:

 
RTC_DATA_ATTR int bootCount = 0;  // Сохраняется между пробуждениями

void setup() {
  Serial.begin(115200);
  bootCount++;
  Serial.printf("Пробуждение #%d\n", bootCount);
  
  esp_sleep_enable_timer_wakeup(5 * 1000000);  // 5 секунд
  esp_deep_sleep_start();
}

void loop() {}

4. Потребление энергии в Deep Sleep

Режим Потребление (µA) Условия
Deep Sleep 5–150 µA В зависимости от пробуждения
Light Sleep 800 µA CPU остановлен
Modem Sleep 20 mA Wi-Fi/BT отключены

Как снизить потребление?

  • Отключите неиспользуемые GPIO (rtc_gpio_isolate()).

  • Убедитесь, что питание датчиков отключено.

  • Используйте ULP-процессор вместо основного CPU.

5. Вывод

ESP32 гораздо гибче ATmega2560 в плане энергосбережения:

  • Пробуждение по таймеру, кнопке, TouchPad, UART, ULP.

  • Можно сохранять данные в RTC-память.

  • Потребление в Deep Sleep — всего 5–150 мкА.

Если нужно максимально снизить энергопотребление, используйте Deep Sleep + ULP.
Если нужно быстро просыпаться, но экономить энергию — Light Sleep.

Хотите пример для конкретного сценария? Уточните задачу — помогу настроить! 🚀

 

Deep Sleep + ULP 

 
Отличный выбор! Режим Deep Sleep + ULP (Ultra Low Power co-processor) позволяет ESP32 выполнять простые задачи (например, опрос датчиков) при крайне низком энергопотреблении (~5–150 мкА), а затем будить основной процессор только при необходимости.

1. Что такое ULP-процессор?

  • ULP — это сверхэкономичный сопроцессор, работающий даже в Deep Sleep.

  • Потребляет ~10–150 мкА (в зависимости от частоты и задач).

  • Может:

    • Читать аналоговые (ADC) и цифровые (GPIO) сигналы.

    • Работать с RTC-памятью (сохранение данных между пробуждениями).

    • Будить основной CPU по событию (например, при превышении порога датчика).

2. Как настроить Deep Sleep + ULP?

2.1. Необходимые компоненты

  1. Прошивка ULP (пишется на ассемблере или через макросы).

  2. Загрузчик ULP в основной код ESP32.

  3. Настройка пробуждения от ULP.

2.2. Пример: ULP + ADC (чтение датчика)

Шаг 1: Создаем прошивку ULP (ассемблер)

Создаем файл ulp_adc.S:

 
/* ulp_adc.S - чтение ADC1 (канал 6, GPIO34) */
#include "soc/rtc_cntl_reg.h"
#include "soc/soc_ulp.h"

.bss                /* Сегмент неинициализированной памяти */
.global adc_reading /* Переменная для хранения значения ADC */

.text               /* Сегмент кода */
.global entry       /* Точка входа */

entry:
    move r3, 0      /* Счетчик (опционально) */

    /* Чтение ADC1 (канал 6 - GPIO34) */
    adc r1, 0, 6    // r1 = adc1_channel6 (0-8191 при 12 битах)
    
    /* Сохраняем значение в RTC-память */
    move r0, adc_reading  // Адрес переменной
    st r1, r0, 0          // Сохраняем значение ADC
    
    /* Будим основной CPU */
    wake                  
    
    /* Завершаем работу ULP (если не будим) */
    halt

→ Скомпилируйте этот код в бинарный файл (ulp-adc.bin).

Шаг 2: Загрузка ULP в ESP32 (Arduino/PlatformIO)

 
#include <esp_sleep.h>
#include <driver/rtc_io.h>
#include <ulp_main.h>  // Автогенерируется при компиляции

// Объявления для бинарника ULP
extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_adc_bin_start");
extern const uint8_t ulp_main_bin_end[]   asm("_binary_ulp_adc_bin_end");

RTC_DATA_ATTR uint32_t adc_value;  // Переменная для хранения ADC

void setup() {
  Serial.begin(115200);
  
  // Загрузка программы ULP
  ulp_load_binary(0, ulp_main_bin_start, 
                 (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t));
  
  // Запуск ULP
  ulp_run(&ulp_entry - RTC_SLOW_MEM);

  // Настройка пробуждения от ULP
  esp_sleep_enable_ulp_wakeup();
  
  Serial.println("Переход в Deep Sleep + ULP...");
  esp_deep_sleep_start();  // Уходит в сон
}

void loop() {}  // Не используется

Шаг 3: Чтение данных после пробуждения

Добавьте в setup() перед сном:

 
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_ULP) {
  Serial.printf("Пробуждение от ULP! ADC value: %d\n", adc_value);
}

2.3. Пример: ULP + GPIO (мониторинг кнопки)

Если нужно мониторить цифровой сигнал (например, кнопку):

assembly
 
Copy
 
Download
/* ulp_gpio.S - мониторинг GPIO2 (кнопка) */
#include "soc/rtc_io_reg.h"
#include "soc/soc_ulp.h"

.set gpio_num, 2   /* GPIO2 */

.bss
.global button_pressed

.text
.global entry

entry:
    /* Настройка GPIO2 как входа */
    WRITE_RTC_REG(RTC_GPIO_ENABLE_W1TC_REG, RTC_GPIO_ENABLE_W1TC_S + gpio_num, 1, 1)
    
    /* Чтение GPIO2 */
    READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + gpio_num, 1)
    move r1, r0
    
    /* Если GPIO2 = LOW (кнопка нажата) */
    jumpr on_press, 1, lt
    
    /* Иначе - спать */
    halt

on_press:
    move r0, button_pressed
    move r1, 1
    st r1, r0, 0
    wake
    halt

→ Аналогично загружаем в ESP32 и настраиваем пробуждение.

3. Оптимизация энергопотребления

  1. Отключите все лишние GPIO:

    cpp
     
    Copy
     
    Download
    rtc_gpio_isolate(GPIO_NUM_2);  // Отключает GPIO2
  2. Уменьшите частоту ULP:

    cpp
     
    Copy
     
    Download
    ulp_set_wakeup_period(0, 100000);  // 100 мс между запусками ULP
  3. Используйте RTC-память вместо глобальных переменных:

    cpp
     
    Copy
     
    Download
    RTC_DATA_ATTR int sensor_data[10];

4. Потребление энергии

Режим Потребление (µA) Условия
Deep Sleep + ULP (ADC) ~120 µA Чтение ADC каждые 100 мс
Deep Sleep + ULP (GPIO) ~50 µA Мониторинг кнопки
Pure Deep Sleep ~5 µA Без ULP

5. Плюсы и минусы ULP

✅ Плюсы:

  • Крайне низкое энергопотребление.

  • Возможность мониторинга датчиков без включения CPU.

❌ Минусы:

  • Ограниченный набор команд (ассемблер).

  • Нет доступа к Wi-Fi/Bluetooth.

6. Вывод

Deep Sleep + ULP — идеальное решение для батарейных проектов, где нужно:

  • Долгое время работы (месяцы/годы от батареи).

  • Периодический опрос датчиков (температура, влажность, кнопки).

Если нужно сложное поведение, но с экономией энергии, рассмотрите Light Sleep.