ESP32:Примеры/Режим глубокого сна: пробуждение при помощи таймера

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.


Режим глубокого сна: пробуждение при помощи таймера

Плату ESP32 можно переключить в режим глубокого сна, а затем разбудить через определенное время. Эта функция особенно полезна, если ваш проект завязан на времени (например, выполняет ежедневные задачи) и требует низкого энергопотребления.

RTC-контроллер оснащен таймером, который позволяет будить ESP32 через определенное время. В этом примере мы рассмотрим как сделать это при помощи IDE Arduino.

Пробуждение платы ESP32 при помощи заранее заданного времени делается очень просто. В IDE Arduino вам нужно лишь задать время сна (в микросекундах) при помощи следующей функции:

esp_sleep_enable_timer_wakeup(time_in_us);

Справочная информация

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

В этом примере мы изучим, что такое режим глубокого сна, как переключить ESP32 в режим глубокого сна, а также рассмотрим разные способы пробуждения ESP32 из этого режима.

ESP32 может работать в следующих режимах:

  • Активный режим;
  • Модемный режим сна;
  • Режим легкого сна;
  • Режим глубокого сна;
  • Режим гибернации;

В ниже представлена таблица из технической документации ESP32 со сравнением всех этих пяти режимов:

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

А вот и сама таблица 10 с подробностями об энергопотреблении в активном режиме.

Почему именно режим глубокого сна?

Постоянная работа ESP32 в активном режиме – это неидеальный вариант, т.к. при его использовании заряд в батареях кончается очень быстро.

Если перевести ESP32 в режим глубокого сна, это сократит энергопотребление, благодаря чему батарей хватит на более долгий срок.

Если переключить ESP32 в режим глубокого сна, то это значит, что у нее будут отключены самые энергоемкие активности, но продолжат работать активности, необходимые для пробуждения процессора, если произойдет что-то интересное.

В режиме глубокого сна не работает ни процессор, ни WiFi, но по-прежнему может работать сопроцессор ULP (англ. «ultra low power», т.е. «процессор с ультранизким потреблением»). Когда ESP32 находится в режиме глубокого сна, также остается включенной RTC-память. То есть мы можем написать программу для сопроцессора ULP и сохранить ее в RTC-память, чтобы получить доступ к периферийным устройствам, а также ко внутренним таймерам и датчикам.

Этот режим работы предназначен для случаев, когда вам нужно пробудить главный CPU при помощи внешнего события или таймера (или обоих сразу), а также продолжать работать в режиме низкого энергопотребления.

Контакты RTC_GPIO

Во время режима глубокого сна сопроцессор ULP может использовать некоторые контакты ESP32, а именно – контакты RTC_GPIO и сенсорные контакты. Найти контакты RTC_GPIO можно, например, в технической документации ESP32 (на странице 7).

В дальнейшем, работая с контактами RTC_GPIO, вы можете использовать либо эту таблицу, либо распиновку ниже. Контакты RTC_GPIO помечены на ней оранжевым цветом.


Способы пробуждения ESP32 из режима глубокого сна

После того, как ESP32 переведена в режим глубокого сна, есть несколько способов ее пробудить:

  • При помощи таймера. Он разбудит ESP32 через определенное количество времени;
  • При помощи внешнего пробуждения. Здесь есть две возможности: пробуждение либо при помощи одного внешнего инициатора, либо при помощи нескольких внешних инициаторов;
  • При помощи сенсорных контактов;
  • При помощи сопроцессора ULP;

Написание скетча, использующего режим глубокого сна

Чтобы написать скетч, переключающий ESP32 в режим глубокого сна, а затем пробуждающего его от него, вам нужно помнить следующее:

  1. Во-первых, нужно настроить инициаторы пробуждения (т.е. то, что будет будить ESP32). Инициатор пробуждения может быть один или несколько
  2. Вы можете задать, какую периферию выключить или держать включенной во время режима глубокого сна. Впрочем, по умолчанию ESP32 автоматически выключает периферийные устройства, которые не нужны заданному вами инициатору пробуждения
  3. Наконец, вам понадобится функция esp_deep_sleep_start(), чтобы перевести ESP32 в режим глубокого сна;

Как работает этот код

Теперь давайте разберемся, как устроен этот код.

В первом комментарии описывается, какие компоненты выключаются во время режима глубокого сна с пробуждением по таймеру.

/*
В этом режиме выключены процессоры, большая часть RAM
и вся цифровая периферия, получающая тактовый сигнал через APB_CLK.
Единственные компоненты чипа, что по-прежнему могут работать – 
это RTC-контроллер, RTC-периферия и RTC-память.

Этот скетч-пример демонстрирует основы
работы с режимом глубокого сна при помощи таймера,
а также показывает, как сохранять данные в RTC-память,
чтобы заново использовать их между загрузками.
*/

То есть, если использовать пробуждение по таймеру, то включенными останутся RTC-контроллер, RTC-периферия и RTC-память.

Задаем время сна

В первых двух строчках задается время, в течение которого будет спать ESP32.

#define uS_TO_S_FACTOR 1000000 /* коэффициент пересчета
                                  микросекунд в секунды */
#define TIME_TO_SLEEP 5        /* время, в течение которого
                                  будет спать ESP32 (в секундах) */

В этом скетче-примере используется коэффициент пересчета из микросекунд в секунды, чтобы время сна в переменной «TIME_TO_SLEEP» можно было задать в секундах. В данном случае мы переводим ESP32 в режим сна на 5 секунд.

Сохраняем данные в RTC-память

При работе с платой ESP32 данные можно сохранять в RTC-память. ESP32 (точнее, ее RTC-модуль) оснащена 8 Кб памяти SRAM, которую называют «быстрой RTC-памятью». Хранящиеся в ней данные не стираются во время глубокого сна, но стираются при нажатии на кнопку сброса (это кнопка на ESP32 под названием «EN»).

Чтобы сохранить данные на RTC-память, перед объявлением переменной нужно добавить конструкцию «RTC_DATA_ATTR». В результате код сохранит переменную «bootCount» в RTC-память. Эта переменная будет считать, сколько раз ESP32 пробуждалась от глубокого сна.

RTC_DATA_ATTR int bootCount = 0;

Сообщаем причину пробуждения

Далее пишем в коде функцию print_wakeup_reason(), которая будет печатать в мониторе порта причину вывода ESP32 из режима глубокого сна.

void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case 1  : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
                         //  "Пробуждение от внешнего сигнала с помощью RTC_IO"
    case 2  : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
                         //  "Пробуждение от внешнего сигнала с помощью RTC_CNTL"  
    case 3  : Serial.println("Wakeup caused by timer"); break;
                         //  "Пробуждение от таймера"
    case 4  : Serial.println("Wakeup caused by touchpad"); break;
                         //  "Пробуждение от сенсорного контакта"
    case 5  : Serial.println("Wakeup caused by ULP program"); break;
                         //  "Пробуждение от ULP-программы"
    default : Serial.println("Wakeup was not caused by deep sleep"); break;
                         //  "Пробуждение не связано с режимом глубокого сна"

  }
}

setup()

Блок setup() – это то, где будет находиться весь код нашей программы, потому что ESP32 сразу после запуска будет переведена в режим глубокого сна и никогда не доберется до блока loop().

Начинаем код с инициализации последовательной коммуникации на скорости 115200 бод.

Serial.begin(115200);

Затем делаем так, чтобы переменная «bootCount» увеличивалась на единицу с каждой загрузкой. Также печатаем это значение в мониторе порта.

++bootCount;
Serial.println("Boot number: " + String(bootCount));
           //  "Количество загрузок: "

После этого код вызывает функцию print_wakeup_reason(), но вы можете вписать здесь любую функцию, выполняющую необходимую для вас задачу – например, считывающую данные с датчика. То есть вы можете, например, настроить ESP32, чтобы она раз в день «просыпалась» и считывала данные с какого-либо датчика.

Далее задаем инициатора пробуждения при помощи следующей функции:

esp_sleep_enable_timer_wakeup(time_in_us);

Параметром для этой функции служит время в микросекундах.

Затем, после выполнения всех необходимых задач переводим ESP32 в режим глубокого сна при помощи следующей функции:

esp_deep_sleep_start();

loop()

Блок loop() оставляем пустым, потому что ESP32 перейдет в режим сна до того, как доберется до этой части скетча. Поэтому нам и нужно было поместить весь скетч в setup().

Загружаем скетч на ESP32. Убедитесь, что в IDE Arduino выбраны правильная плата и COM-порт.

Проверка проекта-примера

Открываем монитор порта на скорости 115200 бод.

В результате ESP32 будет просыпаться каждые 5 секунд, печатать сообщение в мониторе порта, а затем снова переключаться в режим глубокого сна.

При каждом пробуждении ESP32 значение в счетчике загрузок «bootCount» будет увеличиваться на «1». Кроме того, код будет сообщать в мониторе порта причину пробуждения (см. ниже).

Однако имейте в виду, что если нажать на кнопку EN на ESP32, это сбросит счетчик загрузок к «1».

Итак, в этом примере мы продемонстрировали, как использовать таймер для вывода ESP32 из режима глубокого сна.

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

Необходимое оборудование

  • Плата ESP32 - 1шт.;

Схема

Для данного примера нужна только плата.

Код

/*
Режим глубокого сна и пробуждение по таймеру
=====================================
ESP32 может работать в режиме глубокого сна,
позволяющего более экономно расходовать энергопотребление,
что важно при разработке IoT-проектов.

В этом режиме выключены процессоры, большая часть RAM
и вся цифровая периферия, получающая тактовый сигнал через APB_CLK.
Единственные компоненты чипа, что по-прежнему могут работать – 
это RTC-контроллер, RTC-периферия и RTC-память.

Этот скетч-пример демонстрирует основы
работы с режимом глубокого сна при помощи таймера,
а также показывает, как сохранять данные в RTC-память,
чтобы заново использовать их между загрузками.

Этот код распространяется по лицензии всеобщего достояния.
Автор: Пранав Черукупалли <cherukupallip@gmail.com>
*/

#define uS_TO_S_FACTOR 1000000  /* коэффициент пересчета
                                   микросекунд в секунды */
#define TIME_TO_SLEEP  5        /* время, в течение которого
                                   будет спать ESP32 (в секундах) */

RTC_DATA_ATTR int bootCount = 0;

/*
Метод для печати в мониторе порта причины пробуждения ESP32
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case 1  : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
                         //  "Пробуждение от внешнего сигнала с помощью RTC_IO"
    case 2  : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
                         //  "Пробуждение от внешнего сигнала с помощью RTC_CNTL"  
    case 3  : Serial.println("Wakeup caused by timer"); break;
                         //  "Пробуждение от таймера"
    case 4  : Serial.println("Wakeup caused by touchpad"); break;
                         //  "Пробуждение от сенсорного контакта"
    case 5  : Serial.println("Wakeup caused by ULP program"); break;
                         //  "Пробуждение от ULP-программы"
    default : Serial.println("Wakeup was not caused by deep sleep"); break;
                         //  "Пробуждение не связано с режимом глубокого сна"

  }
}

void setup(){
  Serial.begin(115200);
  delay(1000); // даем время на установление
               // последовательной коммуникации

  // увеличиваем значение в счетчике загрузок
  // и печатаем это значение с каждой загрузкой:
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));
              // "Количество загрузок: "

  // печатаем причину пробуждения ESP32:
  print_wakeup_reason();

  /*
  Сначала настраиваем инициатор пробуждения.
  Задаем, чтобы ESP32 просыпалась каждые 5 секунд.
  */
  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");
             //  "ESP32 будет просыпаться каждые ... секунд"

  /*
  Теперь нам нужно решить, будет ли периферия включена или нет.
  По умолчанию ESP32 автоматически выключит всю периферию,
  которая не нужна инициатору пробуждения,
  но если вы опытный пользователь, то решать вам.

  Подробнее об этом читайте в документации об API:
  http://esp-idf.readthedocs.io/en/latest/api- reference/system/deep_sleep.html
 
  Оставьте знаки комментария у двух строчек ниже.
  В первой из них показывается, как переключить всю RTC-периферию
  в режим глубокого сна,
  а во второй - сообщается о переключении в монитор порта.
  */
  //esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
  //Serial.println("Configured all RTC Peripherals to be powered down in sleep");
               //  "Перевод всей RTC-периферии в режим сна"

  /*
  Теперь, когда мы задали инициатора пробуждения, а также,
  если необходимо, задали, останется ли в режиме сна RTC-периферия,
  мы можем начать, собственно, перевод платы в режим сна.

  Если активировать режим сна, не задав инициаторов пробуждения,
  ESP32 будет пребывать в нем вечно, пока пользователь
  не выполнит аппаратный сброс.
  */
  Serial.println("Going to sleep now");
              // "Переход в режим сна"
  delay(1000);
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
              // "Этого напечатано не будет"
}

void loop(){
  // Этот блок кода вызван не будет
}

См.также

Внешние ссылки