Инструкции

Питание ESP32 и режимы сна: от 260 мА до 10 микроампер

13 мин чтения·Август 2026

Датчик, который отправляет показания раз в полчаса, может прожить от пары батареек год — или разрядить их за неделю. Разница целиком в том, что происходит между отправками. Разбираем режимы сна ESP32, способы проснуться и главную практическую ловушку: почему готовая плата потребляет в сотни раз больше, чем обещает даташит.

Сколько потребляет

Цифры из даташита классического ESP32 при 3,3 В и 25 °C. У ESP32-C3, ESP32-S3 и ESP32-C6 значения свои, но порядок величин и соотношение между режимами те же:

РежимЧто живётТок
Активный, радио работаетвсёдо 260 мА в пике передачи
Modem-sleep, 240 МГцпроцессор, радио выключено30–68 мА
Modem-sleep, 80 МГцто же, ниже частота20–31 мА
Light-sleepОЗУ и регистры сохраняются0,8 мА
Deep-sleepRTC-таймер и RTC-память10 мкА
Deep-sleep с сопроцессором ULPплюс ULP150 мкА
Hibernationтолько RTC-таймер5 мкА
Питание снято (CHIP_PU на землю)ничего1 мкА

Разница между активным режимом и глубоким сном — примерно в двадцать тысяч раз. Отсюда единственная стратегия для автономных устройств: большую часть времени спать, просыпаться на секунды, сделать дело и заснуть снова.

Чем режимы отличаются

Modem-sleep выключает только радио. Процессор работает, программа выполняется. Включается автоматически, когда Wi-Fi простаивает.

Light-sleep останавливает процессор, но сохраняет содержимое ОЗУ и регистров. Вызов esp_light_sleep_start() возвращает управление в следующую строку, будто программа просто подождала. Всё состояние на месте, переменные целы.

Deep-sleep обесточивает почти всё: процессор, основную память, периферию. Остаются RTC-контроллер, RTC-память и, если нужно, сопроцессор ULP. Пробуждение равносильно перезагрузке: esp_deep_sleep_start() не возвращается никогда, а выполнение начинается заново с setup().

Hibernation — крайний случай deep-sleep, где выключена и RTC-память. Живёт только таймер.

Сон по таймеру

#define SLEEP_SECONDS 30

RTC_DATA_ATTR int bootCount = 0;

void setup() {
  Serial.begin(115200);
  delay(1000);

  bootCount++;
  Serial.printf("Пробуждение номер %d\n", bootCount);

  // здесь полезная работа: прочитать датчик, отправить, записать

  esp_sleep_enable_timer_wakeup(SLEEP_SECONDS * 1000000ULL);
  Serial.println("Засыпаю");
  Serial.flush();

  esp_deep_sleep_start();   // управление сюда не вернётся
}

void loop() {
}

Обратите внимание на три детали. Аргумент esp_sleep_enable_timer_wakeup()в микросекундах, отсюда множитель. Serial.flush() перед сном обязателен, иначе последние строки не успеют уйти в порт. И весь код живёт в setup(): до loop() дело просто не доходит.

Атрибут RTC_DATA_ATTR кладёт переменную в RTC-память, которая переживает глубокий сон. Именно так между пробуждениями сохраняют счётчики и состояние. Но перезагрузку по питанию или кнопке сброса такая переменная не переживёт — для этого нужен NVS через Preferences.

Пробуждение по выводу

У классического ESP32 два механизма.

ext0 — один вывод и заданный уровень:

esp_sleep_enable_ext0_wakeup(GPIO_NUM_33, 0);   // проснуться, когда GPIO 33 станет LOW

ext1 — несколько выводов сразу, задаются битовой маской:

esp_sleep_enable_ext1_wakeup(BIT64(GPIO_NUM_32) | BIT64(GPIO_NUM_33),
                             ESP_EXT1_WAKEUP_ANY_HIGH);

Оба работают только с выводами, относящимися к RTC. У классического ESP32 это GPIO 0, 2, 4, 12–15, 25–27 и 32–39.

⚠️

У классического ESP32 для ext1 доступны только два режима: ESP_EXT1_WAKEUP_ANY_HIGH (любой из выбранных выводов стал высоким) и ESP_EXT1_WAKEUP_ALL_LOW (все стали низкими). Режима «любой стал низким» там нет — его добавили только в более поздних чипах. Если нужна кнопка на землю, используйте ext0.

Узнать причину пробуждения можно так:

switch (esp_sleep_get_wakeup_cause()) {
  case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Таймер"); break;
  case ESP_SLEEP_WAKEUP_EXT0:  Serial.println("Вывод (ext0)"); break;
  case ESP_SLEEP_WAKEUP_EXT1:  Serial.println("Вывод (ext1)"); break;
  case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Касание"); break;
  default: Serial.println("Обычное включение"); break;
}

Отличия других чипов

Карта возможностей заметно различается:

Чипext0ext1Пробуждение по касаниюВыводы для пробуждения
ESP32ДаДаДаGPIO 0, 2, 4, 12–15, 25–27, 32–39
ESP32-S3ДаДаДаGPIO 0–21
ESP32-C6НетДаНет8 выводов RTC
ESP32-C3НетНетНеттолько GPIO 0–5

У ESP32-C3 выводов RTC нет вовсе, и функции esp_sleep_enable_ext0_wakeup() там просто не существует — код с ней не скомпилируется. Вместо неё используется другой механизм:

// только для ESP32-C3, только выводы GPIO 0–5
esp_deep_sleep_enable_gpio_wakeup(BIT64(GPIO_NUM_3), ESP_GPIO_WAKEUP_GPIO_LOW);

Это одна из тех вещей, из-за которых скетч, отлаженный на DevKit, отказывается работать на ESP32-C3 Super Mini.

Почему плата ест больше даташита

Десять микроампер в таблице относятся к чипу, а не к плате. На типовой отладочной плате рядом с ним стоят потребители, которые не засыпают вместе с ним:

  • Стабилизатор питания — имеет собственный ток покоя и продолжает его потреблять, пока подано питание.
  • Светодиод питания — горит постоянно, обычно несколько миллиампер.
  • Мост USB-UART — потребляет, даже когда обмена нет. У плат на ESP32-C3 и ESP32-S3 с собственным USB отдельного моста нет, и это слагаемое отпадает.

В сумме типичная плата в глубоком сне потребляет единицы или первые десятки миллиампер вместо микроампер. Разброс большой: у экономичных плат без лишней обвязки цифра заметно ниже, и проверять её нужно на своём экземпляре.

ℹ️

Точной цифры Espressif не публикует: в документации на DevKit не указаны даже модели стабилизатора и моста. Независимые замеры дают порядок 5–15 мА, но проверять стоит на своей плате — разброс между клонами большой.

Что с этим делают:

  • Выпаивают светодиод питания. Самый простой шаг, экономит несколько миллиампер.
  • Берут модуль, а не плату. Голый WROOM с собственным стабилизатором с малым током покоя даёт те самые микроамперы.
  • Считают честно. Если устройство должно жить год, сначала измерьте реальное потребление, а потом считайте ёмкость батареи.

Как считать время работы

Средний ток складывается из потребления во сне и коротких всплесков активности:

средний ток = ток сна + (ток работы × время работы) / период

Датчик, который просыпается на 3 секунды каждые 30 минут и тратит 120 мА на передачу:

(120 мА × 3 с) / 1800 с = 0,2 мА  плюс ток сна

С голым модулем (0,01 мА) выходит около 0,21 мА, и аккумулятор 18650 на 2500 мАч теоретически протянет больше года. С обычным DevKit, потребляющим во сне 10 мА, средний ток станет 10,2 мА — и та же батарея сядет за десять дней. Разница исключительно в обвязке платы.

Что ещё экономит

Понизить частоту процессора, когда полная скорость не нужна:

setCpuFrequencyMhz(80);   // вместо 240

Выключать Wi-Fi между сеансами связи:

WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);

Сокращать время подключения. Установка соединения — самая дорогая часть цикла: плата держит радио включённым несколько секунд. Помогает статический IP и запоминание канала и BSSID точки доступа: это убирает сканирование и получение адреса по DHCP. Про статический адрес — в статье Подключение ESP32 к Wi-Fi.

Что дальше

Связанные статьи