Когда ваш проект Интернета вещей питается от сетевого адаптера, вас не слишком заботит энергопотребление. Но если вы собираетесь питать свой проект от батареи, каждый мА имеет значение.

ESP32 может быть относительно энергоемким устройством в зависимости от того, в каком состоянии он находится. Обычно он потребляет около 75 мА при нормальной работе и около 240 мА при передаче данных через Wi-Fi.

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

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

ESP32 Глубокий сон

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

    • Сопроцессор ULP
    • Контроллер реального времени
    • Периферийные устройства RTC
    • RTC быстрая и медленная память

Чип потребляет ток от 0,15 мА (при включенном сопроцессоре ULP) до 10 мкА.

Функциональная блок-схема ESP32 Deep Sleep и потребление тока

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

Вместе с ЦП отключается и основная память чипа. В результате все, что хранится в этой памяти, стирается и становится недоступным.

Поскольку память RTC сохраняется, ее содержимое сохраняется даже во время глубокого сна и может быть восстановлено после пробуждения чипа. Вот почему чип сохраняет данные о соединениях Wi-Fi и Bluetooth в памяти RTC перед переходом в глубокий сон.

Если вы хотите использовать данные после перезагрузки, сохраните их в памяти RTC, определив глобальную переменную с RTC_DATA_ATTRатрибутом. Например,RTC_DATA_ATTR int myVar = 0;

После выхода из глубокого сна чип перезагружается со сбросом и начинает выполнение программы с начала.

ESP32 поддерживает запуск заглушки пробуждения для глубокого сна при выходе из глубокого сна. Эта функция запускается сразу же, как только чип просыпается – до запуска нормальной инициализации, загрузчика или кода ESP-IDF. После запуска заглушки пробуждения чип может снова перейти в спящий режим или продолжить обычный запуск ESP-IDF.

В отличие от других режимов сна, система не может автоматически перейти в режим глубокого сна. Функция esp_deep_sleep_start()используется для перехода в глубокий сон сразу после настройки источников пробуждения.

Источники пробуждения ESP32 Deep Sleep

ESP32 можно вывести из режима глубокого сна с помощью нескольких источников. Этими источниками являются:

    • Таймер
    • Сенсорная панель
  • Внешнее пробуждение (ext0 и ext1)

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

Предупреждение:

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

Источник пробуждения ESP32: Таймер

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

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

Функция esp_sleep_enable_timer_wakeup(time_in_us)используется для настройки таймера в качестве источника пробуждения. Эта функция принимает количество времени в микросекундах (мкс).

Пример кода

Давайте посмотрим, как это работает, на примере из библиотеки. Откройте среду разработки Arduino, перейдите в меню «Файл» > «Примеры» > «ESP32» > «Deep Sleep» и откройте скетч TimerWakeUp .

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

#define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  5        /* Time ESP32 will go to sleep (in seconds) */

RTC_DATA_ATTR int bootCount = 0;

/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

void setup(){
  Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  /*
  First we configure the wake up source
  We set our ESP32 to wake up every 5 seconds
  */
  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");

  /*
  Next we decide what all peripherals to shut down/keep on
  By default, ESP32 will automatically power down the peripherals
  not needed by the wakeup source, but if you want to be a poweruser
  this is for you. Read in detail at the API docs
  http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html
  Left the line commented as an example of how to configure peripherals.
  The line below turns off all RTC peripherals in deep sleep.
  */
  //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");

  /*
  Now that we have setup a wake cause and if needed setup the
  peripherals state in deep sleep, we can now start going to
  deep sleep.
  In the case that no wake up sources were provided but deep
  sleep was started, it will sleep forever unless hardware
  reset occurs.
  */
  Serial.println("Going to sleep now");
  Serial.flush(); 
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  //This is not going to be called
}

После загрузки эскиза откройте последовательный монитор и установите скорость передачи данных 115200 бит/с.

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

Выход пробуждения таймера глубокого сна esp32

Теперь попробуйте перезагрузить ESP32, нажав кнопку EN, он должен снова сбросить bootCount на 1, что указывает на то, что память RTC полностью очищена.

Объяснение кода:

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

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

#define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  5        /* Time ESP32 will go to sleep (in seconds) */

Как указывалось ранее, вы можете сохранять данные в памяти RTC ESP32 (8 КБ SRAM), которая не стирается во время глубокого сна. Однако он стирается при сбросе ESP32.

Чтобы сохранить данные в памяти 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 ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

При настройке сначала инициализируем последовательную связь с ПК.

Serial.begin(115200);

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

++bootCount;
Serial.println("Boot number: " + String(bootCount));

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

print_wakeup_reason();

Далее мы настраиваем источник пробуждения таймера с помощью esp_sleep_enable_timer_wakeup(time_in_us)функции. Здесь ESP32 настроен на пробуждение каждые 5 секунд.

esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

Наконец, ESP32 переводится в спящий режим путем вызова esp_deep_sleep_start()функции.

esp_deep_sleep_start();

В этом эскизе ESP32 входит в глубокий сон в самой функции setup(), поэтому он никогда не достигает функции Loop(). Следовательно, loop()функция остается пустой.

void loop(){
  //This is not going to be called
}

Источник пробуждения ESP32: сенсорная панель

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

сенсорные контакты esp32

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

Электропроводка

Давайте подключим кабель к GPIO#15 (Touch#3), который будет действовать как источник пробуждения при касании. Вы можете прикрепить любой проводящий объект, например проволоку, алюминиевую фольгу, проводящую ткань, проводящую краску и т. д., к сенсорному контакту и превратить его в сенсорную панель.

соединительный провод к esp32 для источника сенсорного пробуждения

Пример кода

Давайте посмотрим, как это работает, на примере из библиотеки. Откройте Arduino IDE, выберите «Файл» > «Примеры» > «ESP32» > «Deep Sleep» и откройте скетч TouchWakeUp .

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

#define Threshold 40 /* Greater the value, more the sensitivity */

RTC_DATA_ATTR int bootCount = 0;
touch_pad_t touchPin;
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

/*
Method to print the touchpad by which ESP32
has been awaken from sleep
*/
void print_wakeup_touchpad(){
  touchPin = esp_sleep_get_touchpad_wakeup_status();

  switch(touchPin)
  {
    case 0  : Serial.println("Touch detected on GPIO 4"); break;
    case 1  : Serial.println("Touch detected on GPIO 0"); break;
    case 2  : Serial.println("Touch detected on GPIO 2"); break;
    case 3  : Serial.println("Touch detected on GPIO 15"); break;
    case 4  : Serial.println("Touch detected on GPIO 13"); break;
    case 5  : Serial.println("Touch detected on GPIO 12"); break;
    case 6  : Serial.println("Touch detected on GPIO 14"); break;
    case 7  : Serial.println("Touch detected on GPIO 27"); break;
    case 8  : Serial.println("Touch detected on GPIO 33"); break;
    case 9  : Serial.println("Touch detected on GPIO 32"); break;
    default : Serial.println("Wakeup not by touchpad"); break;
  }
}

void callback(){
  //placeholder callback function
}

void setup(){
  Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32 and touchpad too
  print_wakeup_reason();
  print_wakeup_touchpad();

  //Setup interrupt on Touch Pad 3 (GPIO15)
  touchAttachInterrupt(T3, callback, Threshold);

  //Configure Touchpad as wakeup source
  esp_sleep_enable_touchpad_wakeup();

  //Go to sleep now
  Serial.println("Going to sleep now");
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  //This will never be reached
}

После загрузки эскиза откройте последовательный монитор и установите скорость передачи данных 115200 бит/с.

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

esp32 вывод пробуждения при касании глубокого сна

Объяснение кода:

Первая строка кода устанавливает пороговое значение для сенсорного контакта, равное 40. Чем выше пороговое значение, тем выше чувствительность. Вы можете изменить это значение в соответствии с вашим проектом.

#define Threshold 40 /* Greater the value, more the sensitivity */

Как указывалось ранее, вы можете сохранять данные в памяти RTC ESP32 (8 КБ SRAM), которая не стирается во время глубокого сна. Однако он стирается при сбросе ESP32.

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

RTC_DATA_ATTR int bootCount = 0;

После этого определяется переменная с именем touchPinтипа touch_pad_t(type enum), которая позже поможет нам распечатать GPIO, с помощью которого ESP32 выводится из спящего режима.

touch_pad_t touchPin;

Далее 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 ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

Также определена функция print_wakeup_touchpad(), которая печатает номер GPIO, по которому ESP32 выводится из глубокого сна.

void print_wakeup_touchpad(){
  touchPin = esp_sleep_get_touchpad_wakeup_status();

  switch(touchPin)
  {
    case 0  : Serial.println("Touch detected on GPIO 4"); break;
    case 1  : Serial.println("Touch detected on GPIO 0"); break;
    case 2  : Serial.println("Touch detected on GPIO 2"); break;
    case 3  : Serial.println("Touch detected on GPIO 15"); break;
    case 4  : Serial.println("Touch detected on GPIO 13"); break;
    case 5  : Serial.println("Touch detected on GPIO 12"); break;
    case 6  : Serial.println("Touch detected on GPIO 14"); break;
    case 7  : Serial.println("Touch detected on GPIO 27"); break;
    case 8  : Serial.println("Touch detected on GPIO 33"); break;
    case 9  : Serial.println("Touch detected on GPIO 32"); break;
    default : Serial.println("Wakeup not by touchpad"); break;
  }
}

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

void callback(){
  //placeholder callback function
}

При настройке сначала инициализируем последовательную связь с ПК.

Serial.begin(115200);

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

++bootCount;
Serial.println("Boot number: " + String(bootCount));

Затем вызываются функции print_wakeup_reason()и print_wakeup_touchpad(), но вы можете вызвать любую функцию, необходимую для выполнения желаемой задачи, например, считывания значения датчика.

print_wakeup_reason();
print_wakeup_touchpad();

Теперь прерывание необходимо привязать к одному из сенсорных выводов с нужным порогом чувствительности. Здесь прерывание привязано к сенсорной панели 3 (GPIO15).

touchAttachInterrupt(T3, callback, Threshold);

Далее мы настраиваем источник пробуждения при касании с помощью esp_sleep_enable_touchpad_wakeup()функции.

esp_sleep_enable_touchpad_wakeup();

Наконец, ESP32 переводится в спящий режим путем вызова esp_deep_sleep_start()функции.

esp_deep_sleep_start();

В этом эскизе ESP32 входит в глубокий сон самой функции setup(), поэтому он никогда не достигает loop()функции. Следовательно, loop()функция остается пустой.

void loop(){
  //This is not going to be called
}

Источник пробуждения ESP32: внешнее пробуждение.

Существует два типа внешних триггеров, выводящих ESP32 из режима глубокого сна.

    • ext0 — используйте это, если вы хотите разбудить чип только по определенному выводу GPIO.
  • ext1 — используйте это, если вы хотите разбудить чип, используя несколько контактов GPIO.

Если вы хотите использовать вывод прерывания для вывода ESP32 из глубокого сна, вам придется использовать так называемые выводы RTC_GPIO . Эти GPIO направляются в маломощную подсистему RTC, поэтому их можно использовать, когда ESP32 находится в глубоком сне.

Выводы RTC_GPIO:

контакты gpio esp32 rtc

ext0 Внешний источник пробуждения

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

Эта esp_sleep_enable_ext0_wakeup(GPIO_PIN, LOGIC_LEVEL)функция используется для включения этого источника пробуждения. Эта функция принимает два параметра. Первый — это номер контакта GPIO, а второй — логический уровень (НИЗКИЙ или ВЫСОКИЙ), по которому мы хотим инициировать пробуждение.

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

А поскольку модуль ввода-вывода RTC включен, вы можете воспользоваться внутренними повышающими или понижающими резисторами. Их необходимо настроить с помощью функций rtc_gpio_pullup_en()и rtc_gpio_pulldown_en()перед esp_deep_sleep_start()вызовом.

Электропроводка

Давайте подключим кнопку к GPIO#33, используя понижающий резистор 10 кОм.

Подключение кнопки к ESP32 для внешнего источника пробуждения ext0

Пример кода

Давайте посмотрим, как это работает, на примере из библиотеки. Откройте IDE Arduino, перейдите в меню «Файл» > «Примеры» > «ESP32» > «Deep Sleep» и откройте скетч «ExternalWakeUp» .

Этот эскиз демонстрирует самый простой пример глубокого сна с ext0 в качестве источника пробуждения.

#define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex

RTC_DATA_ATTR int bootCount = 0;

/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

void setup(){
  Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  /*
  First we configure the wake up source
  We set our ESP32 to wake up for an external trigger.
  There are two types for ESP32, ext0 and ext1 .
  ext0 uses RTC_IO to wakeup thus requires RTC peripherals
  to be on while ext1 uses RTC Controller so doesnt need
  peripherals to be powered on.
  Note that using internal pullups/pulldowns also requires
  RTC peripherals to be turned on.
  */
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1); //1 = High, 0 = Low

  //If you were to use ext1, you would use it like
  //esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

  //Go to sleep now
  Serial.println("Going to sleep now");
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  //This is not going to be called
}

После загрузки эскиза откройте последовательный монитор и установите скорость передачи данных 115200 бит/с.

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

Выход пробуждения глубокого сна esp32 ext0

Объяснение кода:

Первая строка кода устанавливает битовую маску. Это не требуется для внешнего пробуждения ext0, поэтому вы можете пока его игнорировать. Мы узнаем об этом во время объяснения кода внешнего пробуждения ext1.

#define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex

Как указывалось ранее, вы можете сохранять данные в памяти RTC ESP32 (8 КБ SRAM), которая не стирается во время глубокого сна. Однако он стирается при сбросе ESP32.

Чтобы сохранить данные в памяти 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 ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

При настройке сначала инициализируем последовательную связь с ПК.

Serial.begin(115200);

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

++bootCount;
Serial.println("Boot number: " + String(bootCount));

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

print_wakeup_reason();

Теперь внешний источник пробуждения ext0 настраивается с помощью этой esp_sleep_enable_ext0_wakeup(GPIO_PIN, LOGIC_LEVEL)функции. Эта функция принимает два параметра. Первый — это номер контакта GPIO, а второй — логический уровень (НИЗКИЙ или ВЫСОКИЙ), по которому мы хотим инициировать пробуждение. В этом примере ESP32 настроен на пробуждение, когда логический уровень GPIO#33 становится ВЫСОКИМ.

esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1);

Наконец, ESP32 переводится в спящий режим путем вызова esp_deep_sleep_start()функции.

esp_deep_sleep_start();

В этом эскизе ESP32 входит в глубокий сон самой функции setup(), поэтому он никогда не достигает loop()функции. Следовательно, loop()функция остается пустой.

void loop(){
  //This is not going to be called
}

ext1 Внешний источник пробуждения

ESP32 можно настроить на выход из глубокого сна с помощью нескольких контактов. Помните, что эти контакты должны быть среди контактов GPIO RTC.

Поскольку источник пробуждения ext1 использует контроллер RTC, для него не требуется включение периферийных устройств RTC и памяти RTC. В этом случае внутренние подтягивающие и понижающие резисторы будут недоступны.

Чтобы использовать внутренние подтягивающие или понижающие резисторы, нам необходимо запросить, чтобы периферийные устройства RTC оставались включенными во время сна, и настроить подтягивающие/подтягивающие резисторы с помощью функций rtc_gpio_pullup_en()и rtc_gpio_pulldown_en()перед переходом в спящий режим.

Эта esp_sleep_enable_ext1_wakeup(BUTTON_PIN_MASK, LOGIC_LEVEL)функция используется для включения этого источника пробуждения. Эта функция принимает два параметра. Первый — это битовая маска, которая сообщает ESP32, какие контакты мы хотим использовать, а второй параметр может быть одним из двух логических уровней, упомянутых ниже, для запуска пробуждения:

    • Просыпайтесь, если один из выбранных контактов ВЫСОКИЙ ( ESP_EXT1_WAKEUP_ANY_HIGH)
  • Просыпайтесь, если все выбранные контакты НИЗКИЕ ( ESP_EXT1_WAKEUP_ALL_LOW)

Битовая маска

Самый простой способ понять битовую маску — записать ее в двоичном формате. Вы можете видеть, что нумерация битов основана на обычной нумерации GPIO. Младший бит (LSB) представляет GPIO#0, а старший бит (MSB) представляет GPIO#39.

Представление битовой маски ext1 в двоичном виде
    • 0 представляет замаскированные контакты
  • 1 представляет контакты, которые будут включены в качестве источника пробуждения.

Поэтому, если вы хотите, чтобы GPIO просыпался, вы должны записать 1 в соответствующее место и 0 в каждый из оставшихся контактов. И, наконец, вам нужно преобразовать его в HEX.

Например, если вы хотите использовать GPIO#32 и GPIO#33 в качестве внешних источников пробуждения, битовая маска будет такой:

ext1 Представление битовой маски внешнего источника пробуждения в двоичном формате

Электропроводка

Давайте подключим две кнопки к GPIO#33 и GPIO#32, используя понижающие резисторы 10 КОм.

Подключение нескольких кнопок к ESP32 для внешнего источника пробуждения ext1

Пример кода

Давайте посмотрим, как это работает, на всё том же примере ExternalWakeUp из библиотеки. Еще раз откройте Arduino IDE, перейдите в меню «Файл» > «Примеры» > «ESP32» > «Deep Sleep» и откройте скетч «ExternalWakeup» .

Давайте внесем три изменения в эскиз, чтобы он у нас работал:

    1. Измените константу BUTTON_PIN_BITMASK.
    2. Прокомментируйте код ext0
    3. Раскомментируйте код ext1

Изменения в эскизе выделены зеленый.

#define BUTTON_PIN_BITMASK 0x300000000

RTC_DATA_ATTR int bootCount = 0;

/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

void setup(){
  Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  /*
  First we configure the wake up source
  We set our ESP32 to wake up for an external trigger.
  There are two types for ESP32, ext0 and ext1 .
  ext0 uses RTC_IO to wakeup thus requires RTC peripherals
  to be on while ext1 uses RTC Controller so doesnt need
  peripherals to be powered on.
  Note that using internal pullups/pulldowns also requires
  RTC peripherals to be turned on.
  */
  //esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1); //1 = High, 0 = Low

  //If you were to use ext1, you would use it like
  esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

  //Go to sleep now
  Serial.println("Going to sleep now");
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  //This is not going to be called
}

После загрузки эскиза откройте последовательный монитор и установите скорость передачи данных 115200 бит/с.

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

Выход пробуждения глубокого сна esp32 ext1

Объяснение кода:

Этот код идентичен коду ext0, за исключением двух изменений.

В начале кода определяется битовая маска. Поскольку в этом примере мы используем контакты GPIO#32 и GPIO#33, маска имеет 1 в соответствующих позициях, 32 0 справа и 6 0 слева.

00000011 00000000 00000000 00000000 00000000 BIN = 0x300000000 HEX

#define BUTTON_PIN_BITMASK 0x300000000

И, наконец, ext1 включен в качестве источника пробуждения.

esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);