ESP32: Режим легкого сна и источники пробуждения (Arduino IDE)
Легкий сон (Light Sleep) – один из режимов энергосбережения, поддерживаемых ESP32. В этом руководстве мы рассмотрим, как реализовать режим легкого сна на ESP32 и различные источники пробуждения. Мы разберем пробуждение по таймеру, различные методы внешнего пробуждения, пробуждение по GPIO, сенсорное пробуждение и пробуждение через UART.
Необходимые условия
Это руководство посвящено программированию ESP32 с использованием ядра Arduino. Перед началом работы у вас должно быть установлено ядро ESP32 Arduino в вашей Arduino IDE. Следуйте руководству ниже для установки ESP32 в Arduino IDE, если вы ещё этого не сделали.
Введение в режим легкого сна
ESP32 предлагает несколько режимов энергосбережения: модемный сон (modem sleep), легкий сон (light sleep) и глубокий сон (deep sleep). Мы подробно рассмотрели :doc:`глубокий сон в предыдущей статье <../esp32-deep-sleep-arduino-ide-wake-up-sources/index>`_.
Вы можете сравнить различные режимы в следующей таблице из даташита ESP32 от Espressif.
В отличие от глубокого сна, который полностью отключает процессор и большинство периферийных устройств, легкий сон сохраняет состояние процессора и данные в оперативной памяти. Это означает, что переменные программы и состояния сохраняются, позволяя ESP32 возобновить работу практически мгновенно после пробуждения.
Это означает, что когда ESP32 просыпается, он продолжит выполнение кода с того места, где остановился перед засыпанием (в отличие от глубокого сна, при котором код выполняется с самого начала). Кроме того, режим легкого сна поддерживает больше источников пробуждения, таких как пробуждение по GPIO и пробуждение через UART.
Даташит ESP32 от Espressif также содержит таблицу сравнения энергопотребления различных режимов питания.
С точки зрения энергопотребления, легкий сон потребляет меньше энергии, чем активный режим, но больше, чем глубокий сон.
Легкий сон идеально подходит для приложений, которым нужна умеренная экономия энергии, но при этом они должны быстро реагировать на определенные события или прерывания, например, временно неактивные датчики, периодически проверяющие данные.
Настройка легкого сна на ESP32
Перевести ESP32 в режим легкого сна очень просто. После настройки источника или источников пробуждения, вам просто нужно вызвать функцию esp_light_sleep_start().
esp_light_sleep_start();
После этого ESP32 проснется, когда будет активирован требуемый источник(и) пробуждения. Когда ESP32 просыпается, он вернется к тому месту в коде, где остановился.
Источники пробуждения из легкого сна
После перевода ESP32 в режим легкого сна существует несколько способов его пробуждения.
Пробуждение по таймеру: таймер RTC может быть настроен для пробуждения ESP32 через заданный интервал времени. Используйте функцию
esp_sleep_enable_timer_wakeup().Пробуждение по GPIO: GPIO можно настроить для срабатывания пробуждения по высокому или низкому сигналу. Это полезно для пробуждения платы кнопкой или сигналом от датчиков. Вы можете использовать
esp_sleep_enable_ext0_wakeup(),esp_sleep_enable_ext1_wakeup_io()илиesp_sleep_enable_gpio_wakeup().Сенсорное пробуждение: пробуждение из легкого сна при касании сенсорных пинов ESP32. Используйте функцию
touchSleepWakeUpEnable().Пробуждение через UART: пробуждение ESP32 при получении данных через UART на определенном порту с помощью функции
esp_sleep_enable_uart_wakeup().
Отключение источников пробуждения
Для отключения ранее включенных источников пробуждения используйте функцию esp_sleep_disable_wakeup_source() и передайте в качестве аргумента источник пробуждения, который вы хотите отключить. Если вы хотите отключить все источники пробуждения, передайте ESP_SLEEP_WAKEUP_ALL в качестве аргумента.
Список источников пробуждения можно найти здесь: аргумент источника пробуждения.
Легкий сон с пробуждением по таймеру
В этом разделе мы покажем, как перевести ESP32 в режим легкого сна и разбудить его через заданный интервал.
Для пробуждения ESP32 через заданный период времени необходимо настроить пробуждение по таймеру с помощью функции esp_sleep_enable_timer_wakeup(). Передайте в качестве аргумента время в микросекундах.
esp_sleep_enable_timer_wakeup(uint64_t time_in_us)
Пример легкого сна с пробуждением по таймеру
Следующий пример переводит ESP32 в режим легкого сна. ESP32 будет просыпаться каждые 10 секунд.
/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-light-sleep-arduino/
*********/
int counter = 0;
const int ledPin = 2; // GPIO pin for onboard LED
uint64_t sleepTime = 10000000; // Sleep duration in microseconds (10 seconds)
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
// Enable wake-up by timer
esp_err_t result = esp_sleep_enable_timer_wakeup(sleepTime);
if (result == ESP_OK) {
Serial.println("Timer Wake-Up set successfully as wake-up source.");
} else {
Serial.println("Failed to set Timer Wake-Up as wake-up source.");
}
}
void loop() {
Serial.printf("Counter: %d\n", counter);
counter++;
digitalWrite(ledPin, HIGH); // LED on to indicate wake-up
delay(2000);
digitalWrite(ledPin, LOW); // Turn off LED before going to sleep
Serial.println("Going into light sleep mode");
delay(500);
esp_light_sleep_start(); // Enter light sleep
Serial.println("Returning from light sleep");
}
Этот пример включает светодиод при пробуждении ESP32 и увеличивает переменную-счетчик в каждом цикле. Это демонстрирует, что оперативная память ESP32 сохраняет данные, поэтому переменные и состояния программы остаются нетронутыми при пробуждении ESP32.
Когда ESP32 просыпается, он возвращается к тому месту в коде, где остановился (в отличие от :doc:`глубокого сна <../esp32-deep-sleep-arduino-ide-wake-up-sources/index>`_, при котором код начинает выполняться сначала).
Как работает код?
Давайте кратко рассмотрим основные части кода для легкого сна с пробуждением по таймеру.
В setup() мы вызываем функцию esp_sleep_enable_timer_wakeup() для включения пробуждения по таймеру. В качестве аргумента передаем переменную sleepTime (10000000 микросекунд = 10 секунд).
esp_err_t result = esp_sleep_enable_timer_wakeup(sleepTime);
Функция esp_sleep_enable_timer_wakeup() возвращает ESP_OK, если пробуждение по таймеру было успешно настроено. Мы проверяем это в следующих строках.
if (result == ESP_OK) {
Serial.println("Timer Wake-Up set successfully as wake-up source.");
} else {
Serial.println("Failed to set Timer Wake-Up as wake-up source.");
}
В каждом loop() мы увеличиваем переменную counter.
counter++;
Зажигаем встроенный светодиод на две секунды.
digitalWrite(ledPin, HIGH); // LED on to indicate wake-up
delay(2000);
digitalWrite(ledPin, LOW); // Turn off LED before going to sleep
И переводим ESP32 в режим легкого сна, вызывая функцию esp_light_sleep_start().
esp_light_sleep_start(); // Enter light sleep
Когда ESP32 проснется, он продолжит выполнение кода. Таким образом, после пробуждения будет напечатано следующее сообщение.
Serial.println("Returning from light sleep");
В каждом цикле loop() и цикле пробуждения переменная counter увеличивается. Это доказывает, что ESP32 может сохранять значения переменных во время легкого сна.
Легкий сон с внешним пробуждением
В этом разделе вы узнаете, как перевести ESP32 в режим легкого сна и разбудить его с помощью внешнего пробуждения, в данном случае – кнопкой. Любой GPIO, являющийся RTC GPIO, может быть использован для пробуждения ESP32.
Существует три различных способа использования внешнего пробуждения с легким сном: метод ext0, метод ext1 и пробуждение по GPIO. Мы рассмотрим каждый из них.
Внешнее пробуждение ext0
Внешнее пробуждение ext0 позволяет разбудить ESP32, когда RTC GPIO устанавливается в заранее определенное состояние. Периферия RTC остается включенной во время сна, если запрошен этот источник пробуждения.
Для использования этого источника пробуждения используйте функцию esp_sleep_enable_ext0_wakeup() и передайте в качестве аргумента номер GPIO в формате GPIO_NUM_X (где X соответствует номеру GPIO) и уровень (0=LOW, или 1=HIGH).
Например:
esp_sleep_enable_ext0_wakeup(GPIO_NUM_27, level);
Примечание: с этим источником пробуждения можно использовать только пины, являющиеся RTC GPIO. Вот список RTC GPIO для различных моделей чипов ESP32:
ESP32-S3: 0-21;
ESP32: 0, 2, 4, 12-15, 25-27, 32-39;
ESP32-S2: 0-21;
Рекомендуемое чтение: :doc:`Справочник по распиновке ESP32: Какие GPIO пины следует использовать? <../esp32-pinout-reference-gpios/index>`_
Рекомендуемое чтение: Справочник по распиновке ESP32-S3 DevKitC: Объяснение GPIO
Пример легкого сна с внешним пробуждением (ext0)
Вот простой пример использования легкого сна с внешним пробуждением ext0. Этот пример пробуждает ESP32 нажатием кнопки. Каждый раз при пробуждении он включает светодиод на пять секунд и увеличивает переменную counter.
Для тестирования этого примера подключите кнопку к GPIO 27 ESP32, как показано на рисунке ниже (поскольку мы используем внутренний подтягивающий резистор к земле, нам не нужно добавлять его в схему).
После подключения схемы вы можете загрузить код на вашу плату.
/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-light-sleep-arduino/
*********/
int counter = 0;
const int ledPin = 2; // GPIO pin for onboard LED
#define buttonPin GPIO_NUM_27 // Connect a pushbutton to GPIO 27
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT_PULLDOWN); // pull-down resistor
// Enable wake-up by EXT0 using the button on GPIO 27
esp_err_t result = esp_sleep_enable_ext0_wakeup(buttonPin, 1); // 1 = wake up on HIGH signal
if (result == ESP_OK) {
Serial.println("EXT0 Wake-Up set successfully as wake-up source.");
} else {
Serial.println("Failed to set EXT0 Wake-Up as wake-up source.");
}
}
void loop() {
Serial.printf("Counter: %d\n", counter);
counter++;
digitalWrite(ledPin, HIGH); // LED on to indicate wake-up
delay(5000);
digitalWrite(ledPin, LOW); // Turn off LED before going to sleep
Serial.println("Going into light sleep mode");
delay(500);
esp_light_sleep_start(); // Enter light sleep
Serial.println("Returning from light sleep");
}
Как работает код?
Сначала определяем GPIO, который будет использоваться для пробуждения. В этом примере это GPIO 27.
#define buttonPin GPIO_NUM_27 // GPIO pin for pushbutton
В setup() определяем кнопку как вход с подтягивающим резистором к земле.
pinMode(buttonPin, INPUT_PULLDOWN); // pull-down resistor
Затем включаем источник пробуждения ext0 на GPIO 27. Мы передаем 1 для уровня, что означает, что ESP32 проснется по сигналу HIGH – поскольку мы используем подтягивающий резистор к земле, при нажатии кнопки будет получен сигнал HIGH.
// Enable wake-up by EXT0 using the button on GPIO 27
esp_err_t result = esp_sleep_enable_ext0_wakeup(buttonPin, 1); // 1 = wake up on HIGH signal
В loop() мы увеличиваем переменную counter, зажигаем встроенный светодиод на пять секунд и, наконец, вызываем esp_light_sleep_start() для перевода платы в режим легкого сна.
esp_light_sleep_start(); // Enter light sleep
Тестирование кода
Загрузите код на вашу плату. Откройте Serial Monitor со скоростью 115200 бод. Нажмите кнопку, чтобы разбудить ESP32.
Каждый раз при нажатии кнопки ESP32 просыпается, печатает и увеличивает переменную counter, зажигает встроенный светодиод на пять секунд и снова засыпает.
Внешнее пробуждение ext1
Вы можете разбудить ESP32, используя несколько GPIO с этим источником пробуждения. Источник пробуждения ext1 реализован контроллером RTC. Таким образом, периферия RTC и память RTC могут быть отключены в этом режиме.
Используйте функцию esp_sleep_enable_ext1_wakeup_io(). Передайте в качестве аргументов битовую маску GPIO, используемых для пробуждения, и режим/логику пробуждения.
Вы можете использовать одну из следующих двух логик:
ESP_EXT1_WAKEUP_ALL_LOW: пробуждение, когда все GPIO переходят в LOW;ESP_EXT1_WAKEUP_ANY_HIGH: пробуждение, если любой из GPIO переходит в HIGH.
Если вы используете ESP32-S2, ESP32-S3, ESP32-C6 или ESP32-H2, доступны следующие режимы:
ESP_EXT1_WAKEUP_ANY_LOW: пробуждение, когда любой из выбранных GPIO переходит в LOW;ESP_EXT1_WAKEUP_ANY_HIGH: пробуждение, когда любой из выбранных GPIO переходит в HIGH.
Примечание: можно использовать только пины, являющиеся RTC GPIO.
Пример легкого сна с внешним пробуждением (ext1)
В следующем примере мы используем две кнопки для пробуждения ESP32. ESP32 проснется при нажатии любой из кнопок.
Для тестирования этого примера мы подключим кнопку к GPIO27 и ещё одну к GPIO26. Мы будем использовать внутренние подтягивающие резисторы ESP32 к земле. Вы можете использовать следующую схему в качестве справки для подключения.
И вот код, который нужно загрузить на плату.
/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-light-sleep-arduino/
*********/
#include "esp_sleep.h"
#include "driver/rtc_io.h"
int counter = 0;
const int ledPin = 2; // GPIO pin for onboard LED
const gpio_num_t buttonPin1 = GPIO_NUM_26; // RTC IO for pushbutton 1
const gpio_num_t buttonPin2 = GPIO_NUM_27; // RTC IO for pushbutton 2
#define BUTTON_PIN_BITMASK(GPIO) (1ULL << GPIO) // Macro for individual GPIO bitmask
// Create a bitmask for GPIO 26 and GPIO 27
uint64_t bitmask = BUTTON_PIN_BITMASK(buttonPin1) | BUTTON_PIN_BITMASK(buttonPin2);
// Method to print the GPIO that triggered the wakeup
void print_GPIO_wake_up(){
int GPIO_reason = esp_sleep_get_ext1_wakeup_status();
Serial.print("GPIO that triggered the wake up: GPIO ");
Serial.println((log(GPIO_reason))/log(2), 0);
}
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
pinMode(buttonPin1, INPUT_PULLDOWN); // pull-down resistor
pinMode(buttonPin2, INPUT_PULLDOWN); // pull-down resistor
// Configure GPIO 26 and GPIO 27 as RTC IOs for EXT1 wake-up
rtc_gpio_deinit(buttonPin1);
rtc_gpio_deinit(buttonPin2);
// Enable EXT1 wake-up source
esp_err_t result = esp_sleep_enable_ext1_wakeup(bitmask, ESP_EXT1_WAKEUP_ANY_HIGH);
if (result == ESP_OK) {
Serial.println("EXT1 Wake-Up set successfully.");
} else {
Serial.println("Failed to set EXT1 Wake-Up as wake-up source.");
}
}
void loop() {
Serial.printf("Counter: %d\n", counter);
counter++;
digitalWrite(ledPin, HIGH); // LED on to indicate wake-up
delay(2000);
digitalWrite(ledPin, LOW); // Turn off LED before going to sleep
Serial.println("Going into light sleep mode");
delay(500);
esp_light_sleep_start(); // Enter light sleep
// After wake-up, disable the hold function on the RTC GPIOs
rtc_gpio_hold_dis(buttonPin1);
rtc_gpio_hold_dis(buttonPin2);
Serial.println("----------------------");
Serial.println("Returning from light sleep");
// Print the GPIO (button) that caused the wake-up
print_GPIO_wake_up();
}
При нажатии любой из кнопок ESP32 просыпается и выводит, какой GPIO/кнопка была нажата.
Внешнее пробуждение по GPIO
Помимо методов ext0 и ext1, существует ещё один метод, позволяющий настроить отдельные GPIO для пробуждения ESP32 по сигналу HIGH или LOW. С этим методом вы можете использовать любой GPIO, будь то RTC GPIO или «обычный» цифровой вход.
1) Для использования этого метода сначала нужно использовать функцию gpio_wakeup_enable() для определения GPIO, которые вы хотите использовать в качестве источника пробуждения, и соответствующего уровня. Номер GPIO должен быть в формате GPIO_NUM_X (X – номер GPIO). Уровень может быть одним из следующих вариантов:
GPIO_INTR_LOW_LEVEL– пробуждение ESP32, когда GPIO переходит в LOWGPIO_INTR_HIGH_LEVEL– пробуждение ESP32, когда GPIO переходит в HIGH
2) Вы можете вызвать функцию gpio_wakeup_enable() несколько раз для настройки нескольких GPIO.
3) После настройки GPIO, которые будут пробуждать ESP32, необходимо вызвать функцию esp_sleep_enable_gpio_wakeup() для включения этого источника пробуждения.
Затем просто вызовите функцию esp_light_sleep_start() для перевода ESP32 в состояние легкого сна.
Пример легкого сна с внешним пробуждением по GPIO
Следующий пример работает точно так же, как предыдущий, но мы используем этот новый метод. Мы используем прерывания на кнопках, чтобы определить, какая из них стала причиной пробуждения.
/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-light-sleep-arduino/
*********/
#include "esp_sleep.h"
#include "driver/gpio.h"
int counter = 0;
const int ledPin = 2; // GPIO pin for onboard LED
const gpio_num_t buttonPin1 = GPIO_NUM_26; // GPIO for pushbutton 1
const gpio_num_t buttonPin2 = GPIO_NUM_27; // GPIO for pushbutton 2
int wakeup_gpio; // Variable to store the GPIO that caused wake-up
// ISR for buttonPin1
void IRAM_ATTR handleInterrupt1() {
wakeup_gpio = buttonPin1;
}
// ISR for buttonPin2
void IRAM_ATTR handleInterrupt2() {
wakeup_gpio = buttonPin2;
}
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
pinMode(buttonPin1, INPUT_PULLDOWN); // pull-down resistor
pinMode(buttonPin2, INPUT_PULLDOWN); // pull-down resistor
// Configure GPIOs as wake-up source
gpio_wakeup_enable(buttonPin1, GPIO_INTR_HIGH_LEVEL); // Trigger wake-up on high level
gpio_wakeup_enable(buttonPin2, GPIO_INTR_HIGH_LEVEL); // Trigger wake-up on high level
// Enable GPIO wake-up source
esp_err_t result = esp_sleep_enable_gpio_wakeup();
if (result == ESP_OK) {
Serial.println("GPIO Wake-Up set successfully.");
} else {
Serial.println("Failed to set GPIO Wake-Up as wake-up source.");
}
// Attach interrupts to GPIO pins
attachInterrupt(digitalPinToInterrupt(buttonPin1), handleInterrupt1, RISING);
attachInterrupt(digitalPinToInterrupt(buttonPin2), handleInterrupt2, RISING);
}
void loop() {
Serial.printf("Counter: %d\n", counter);
counter++;
digitalWrite(ledPin, HIGH); // LED on to indicate wake-up
delay(5000);
digitalWrite(ledPin, LOW); // Turn off LED before going to sleep
Serial.println("Going into light sleep mode");
delay(500);
esp_light_sleep_start(); // Enter light sleep
Serial.println("----------------------");
Serial.println("Returning from light sleep");
// Print the GPIO that caused the wake-up
Serial.printf("Wake-up caused by GPIO %d\n", wakeup_gpio);
}
В этом коде вы начинаете с определения GPIO, подключенных к кнопкам, в следующем формате:
const gpio_num_t buttonPin1 = GPIO_NUM_26; // GPIO for pushbutton 1
const gpio_num_t buttonPin2 = GPIO_NUM_27; // GPIO for pushbutton 2
Мы создаем глобальную переменную для сохранения GPIO, вызвавшего пробуждение.
int wakeup_gpio; // Variable to store the GPIO that caused wake-up
В setup() используем функцию gpio_wakeup_enable() для настройки GPIO в качестве источников пробуждения и уровня.
// Configure GPIOs as wake-up source
gpio_wakeup_enable(buttonPin1, GPIO_INTR_HIGH_LEVEL); // Trigger wake-up on high level
gpio_wakeup_enable(buttonPin2, GPIO_INTR_HIGH_LEVEL); // Trigger wake-up on high level
Затем, чтобы включить GPIO в качестве источника пробуждения, вызываем функцию esp_sleep_enable_gpio_wakeup().
// Enable GPIO wake-up source
esp_err_t result = esp_sleep_enable_gpio_wakeup();
Также в setup() мы устанавливаем кнопки как прерывания, чтобы они вызывали функцию при нажатии. Это позволяет нам проверить, какой GPIO вызвал пробуждение.
// Attach interrupts to GPIO pins
attachInterrupt(digitalPinToInterrupt(buttonPin1), handleInterrupt1, RISING);
attachInterrupt(digitalPinToInterrupt(buttonPin2), handleInterrupt2, RISING);
Рекомендуемое чтение: :doc:`Прерывания ESP32 с использованием PIR датчика движения <../esp32-pir-motion-sensor-interrupts-timers/index>`_.
Функции-обработчики прерываний определены перед setup() и обновляют переменную wakeup_gpio.
//ISR for buttonPin1
void IRAM_ATTR handleInterrupt1() {
wakeup_gpio = buttonPin1;
}
//ISR for buttonPin2
void IRAM_ATTR handleInterrupt2() {
wakeup_gpio = buttonPin2;
}
В loop(), как и в предыдущих примерах, мы обновляем переменную counter, зажигаем встроенный светодиод и переводим плату в режим легкого сна.
Serial.printf("Counter: %d\n", counter);
counter++;
digitalWrite(ledPin, HIGH); // LED on to indicate wake-up
delay(5000);
digitalWrite(ledPin, LOW); // Turn off LED before going to sleep
Serial.println("Going into light sleep mode");
delay(500);
esp_light_sleep_start(); // Enter light sleep
После пробуждения из сна мы выводим GPIO, вызвавший пробуждение.
Serial.println("----------------------");
Serial.println("Returning from light sleep");
// Print the GPIO that caused the wake-up
Serial.printf("Wake-up caused by GPIO %d\n", wakeup_gpio);
Легкий сон с сенсорным пробуждением
Можно разбудить ESP32 из легкого сна, коснувшись его сенсорных пинов – по сути, когда происходит прерывание сенсорного датчика. Для этого используйте функцию touchSleepWakeUpEnable(), которая принимает в качестве аргумента сенсорный пин и порог пробуждения. Например:
touchSleepWakeUpEnable(T3, THRESHOLD);
Значения, считываемые сенсорным пином, уменьшаются при касании. Значение порога означает, что ESP32 проснется, когда значение, считанное на сенсорном пине, станет ниже 40. Вы можете настроить это значение в зависимости от желаемой чувствительности.
Рекомендуемое чтение: :doc:`Сенсорные пины ESP32 с Arduino IDE <../esp32-touch-pins-arduino-ide/index>`_.
Важно: однако, если вы используете модель ESP32-S2 или ESP32-S3, все работает немного иначе. В этом случае чем ниже значение, тем выше чувствительность.
Примечание: сенсорные пины пронумерованы следующим образом (для ESP32):
T0 (GPIO 4)
T1 (GPIO 0)
T2 (GPIO 2)
T3 (GPIO 15)
T4 (GPIO 13)
T5 (GPIO 12)
T6 (GPIO 14)
T7 (GPIO 27)
T8 (GPIO 33)
T9 (GPIO 32)
Если вы используете ESP32-S2 или ESP32-S3, нумерация будет другой.
Пример легкого сна с сенсорным пробуждением
Следующий код разбудит ESP32, когда он обнаружит касание на GPIO 15 (T3) или GPIO27 (T7).
Примечание: Я тестировал этот источник пробуждения с легким сном, и в моем случае он был немного ненадежным. Иногда работал хорошо, а иногда ESP32 падал после пробуждения. Я не уверен, связано ли это с моим оборудованием или кодом. Попробуйте сами и проверьте свои результаты. (Дайте знать, если у вас есть советы, как сделать этот метод более надежным).
Примечание: Если вы используете ESP32-S2 или ESP32-S3, он может обнаружить сенсорное пробуждение только на одном GPIO.
/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-light-sleep-arduino/
*********/
#if CONFIG_IDF_TARGET_ESP32
#define THRESHOLD 40 // Greater the value, more the sensitivity
#else // ESP32-S2 and ESP32-S3 + default for other chips (to be adjusted)
#define THRESHOLD 5000 // Lower the value, more the sensitivity
#endif
int counter = 0;
const int ledPin = 2; // GPIO pin for onboard LED
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 = (touch_pad_t) esp_sleep_get_touchpad_wakeup_status();
#if CONFIG_IDF_TARGET_ESP32
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;
}
#else
if (touchPin < TOUCH_PAD_MAX) {
Serial.printf("Touch detected on GPIO %d\n", touchPin);
} else {
Serial.println("Wakeup not by touchpad");
}
#endif
}
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
delay(1000); //Take some time to open up the Serial Monitor
#if CONFIG_IDF_TARGET_ESP32
//Setup sleep wakeup on Touch Pad 3 + 7 (GPIO15 + GPIO 27)
touchSleepWakeUpEnable(T3, THRESHOLD);
touchSleepWakeUpEnable(T7, THRESHOLD);
#else //ESP32-S2 + ESP32-S3
//Setup sleep wakeup on Touch Pad 3 (GPIO3)
touchSleepWakeUpEnable(T3, THRESHOLD);
#endif
}
void loop() {
Serial.printf("Counter: %d\n", counter);
counter++;
digitalWrite(ledPin, HIGH); // LED on to indicate wake-up
delay(5000);
digitalWrite(ledPin, LOW); // LED on to indicate wake-up
Serial.println("Going into light sleep...");
delay(500);
esp_light_sleep_start();
Serial.println("----------------------");
Serial.println("Returning from light sleep");
delay(2000);
print_wakeup_reason();
print_wakeup_touchpad();
}
Как работает код?
Давайте кратко рассмотрим основные части этого кода.
Установка порога
Первое, что нужно сделать – установить пороговое значение для сенсорных пинов.
#define THRESHOLD 40 // Greater the value, more the sensitivity
Значения, считываемые сенсорным пином, уменьшаются при касании. Пороговое значение означает, что ESP32 проснется, когда значение, считанное на сенсорном пине, станет ниже 40. Вы можете настроить это значение в зависимости от желаемой чувствительности.
Важно: однако, если вы используете модель ESP32-S2 или ESP32-S3, все работает немного иначе. Поэтому в коде есть отдельная секция с другим порогом для этих плат. В этом случае чем ниже значение, тем выше чувствительность.
#if CONFIG_IDF_TARGET_ESP32
#define THRESHOLD 40 // Greater the value, more the sensitivity
#else // ESP32-S2 and ESP32-S3 + default for other chips (to be adjusted)
#define THRESHOLD 5000 // Lower the value, more the sensitivity
#endif
Причина пробуждения и сенсорный пин пробуждения
У нас есть функция print_wakeup_reason() для проверки и вывода причины пробуждения.
//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;
}
}
И функция print_wakeup_touchpad() для определения, какой сенсорный пин вызвал пробуждение.
// Method to print the touchpad by which ESP32 has been awaken from sleep
void print_wakeup_touchpad() {
touchPin = esp_sleep_get_touchpad_wakeup_status();
#if CONFIG_IDF_TARGET_ESP32
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;
}
#else
if (touchPin < TOUCH_PAD_MAX) {
Serial.printf("Touch detected on GPIO %d\n", touchPin);
} else {
Serial.println("Wakeup not by touchpad");
}
#endif
Настройка сенсорных пинов как источника пробуждения
Чтобы установить сенсорный пин в качестве источника пробуждения, используйте функцию touchSleepWakeUpEnable(), которая принимает в качестве аргументов сенсорный пин и пороговое значение для пробуждения платы.
В этом примере GPIO 15 (T3) и GPIO 27 (T7) установлены как источники пробуждения с одинаковым пороговым значением.
#if CONFIG_IDF_TARGET_ESP32
// Setup sleep wakeup on Touch Pad 3 + 7 (GPIO15 + GPIO 27)
touchSleepWakeUpEnable(T3, THRESHOLD);
touchSleepWakeUpEnable(T7, THRESHOLD);
Если вы используете модель ESP32-S2 или S3, пример определяет пробуждение только на GPIO 3 (T3). Обратите внимание, что нумерация сенсорных пинов может отличаться в зависимости от используемой модели платы.
#else // ESP32-S2 + ESP32-S3
// Setup sleep wakeup on Touch Pad 3 (GPIO3)
touchSleepWakeUpEnable(T3, THRESHOLD);
loop()
В каждом loop() мы увеличиваем переменную counter для отслеживания количества пробуждений ESP32. Мы также зажигаем встроенный светодиод на несколько секунд перед переводом ESP32 в режим легкого сна.
void loop() {
Serial.printf("Counter: %d\n", counter);
counter++;
digitalWrite(ledPin, HIGH); // LED on to indicate wake-up
delay(5000);
digitalWrite(ledPin, LOW); // LED on to indicate wake-up
Serial.println("Going into light sleep...");
delay(500);
esp_light_sleep_start();
После пробуждения ESP32 выводит причину пробуждения и какой сенсорный пин его вызвал.
print_wakeup_reason();
print_wakeup_touchpad();
Подключение схемы
Для тестирования этого примера подключите перемычку к GPIO 15 и/или GPIO 27, как показано на схеме ниже.
Если вы используете ESP32-S2 или модель ESP32-S3, пожалуйста, проверьте расположение ваших сенсорных пинов.
Тестирование примера
Загрузите код на ваш ESP32 и откройте Serial Monitor со скоростью 115200 бод.
ESP32 переходит в режим легкого сна.
Вы можете разбудить его, коснувшись провода, подключенного к Touch Pin 3 или Touch Pin 7.
Когда вы касаетесь провода, ESP32 отображает в Serial Monitor: номер загрузки, причину пробуждения и какой сенсорный GPIO вызвал пробуждение.
Легкий сон с пробуждением через UART
ESP32 может пробуждаться из легкого сна по входным данным UART, включив пробуждение UART с помощью esp_sleep_enable_uart_wakeup().
Также следует вызвать функцию uart_set_wakeup_threshold() для установки количества положительных фронтов на пине RX, которые вызовут пробуждение. Три положительных фронта – это значение, установленное в большинстве случаев.
Следующий пример показывает, как разбудить ESP32 с помощью UART. Этот конкретный пример пробуждает ESP32 через UART 0. Мы отправим сообщение через Serial Monitor, чтобы разбудить ESP32. Но для практического применения вы захотите подключить датчик или другую плату к пину RX ESP32 и отправлять байты через серийный порт для его пробуждения.
Чтобы узнать больше о UART с ESP32, рекомендуем ознакомиться с нашим руководством: ESP32 UART коммуникация (Serial): Настройка пинов, интерфейсов, отправка и прием данных (Arduino IDE).
/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-light-sleep-arduino/
*********/
#include <driver/uart.h>
int counter = 0;
const int ledPin = 2; // GPIO pin for onboard LED
String receivedMessage = ""; // Variable to store the complete message
// 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;
case ESP_SLEEP_WAKEUP_UART: Serial.println("Wakeup caused by UART"); break;
default: Serial.printf("Wakeup was not caused by light sleep: %d\n", wakeup_reason); break;
}
}
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
delay(1000); //Take some time to open up the Serial Monitor
// Enable UART wake-up from light sleep
uart_set_wakeup_threshold(UART_NUM_0, 3); // 3 edges on U0RXD to wakeup
esp_sleep_enable_uart_wakeup(0); // UART0 (default Serial (includes Serial Monitor))
}
void loop() {
Serial.printf("Counter: %d\n", counter);
counter++;
digitalWrite(ledPin, HIGH); // LED on to indicate wake-up
delay(5000);
digitalWrite(ledPin, LOW); // LED on to indicate wake-up
Serial.println("Going into light sleep...");
delay(500);
esp_light_sleep_start();
Serial.println("----------------------");
Serial.println("Returning from light sleep");
delay(2000);
print_wakeup_reason();
// Clear the internal wake-up indication by sending some extra data
Serial.write(' '); // Send a single space character
while (Serial.available()) {
char incomingChar = Serial.read(); // Read each character from the buffer
if (incomingChar == '\n') { // Check if the user pressed Enter (new line character)
// Print the message
Serial.print("You sent: ");
Serial.println(receivedMessage);
// Clear the message buffer for the next input
receivedMessage = "";
} else {
// Append the character to the message string
receivedMessage += incomingChar;
}
}
}
Этот код похож на предыдущие примеры, но использует пробуждение по UART. Мы вызываем следующие две функции в setup() для настройки пробуждения по UART на UART0 (который также является UART, используемым для серийной связи с Serial Monitor).
// Enable UART wake-up from light sleep
uart_set_wakeup_threshold(UART_NUM_0, 3); // 3 edges on U0RXD to wakeup
esp_sleep_enable_uart_wakeup(0); // UART0 (default Serial (includes Serial Monitor))
В loop() мы вызываем функцию esp_light_sleep_start() для перевода ESP32 в режим легкого сна.
esp_light_sleep_start();
Когда он просыпается, выводит причину пробуждения и проверяет, есть ли входящие данные UART для чтения.
print_wakeup_reason();
// Clear the internal wake-up indication by sending some extra data
Serial.write(' '); // Send a single space character
while (Serial.available()) {
char incomingChar = Serial.read(); // Read each character from the buffer
if (incomingChar == '\n') { // Check if the user pressed Enter (new line character)
// Print the message
Serial.print("You sent: ");
Serial.println(receivedMessage);
// Clear the message buffer for the next input
receivedMessage = "";
} else {
// Append the character to the message string
receivedMessage += incomingChar;
}
}
Затем он начинает выполнять loop() сначала. Увеличивает номер счетчика и зажигает встроенный светодиод перед повторным засыпанием.
Serial.printf("Counter: %d\n", counter);
counter++;
digitalWrite(ledPin, HIGH); // LED on to indicate wake-up
delay(5000);
digitalWrite(ledPin, LOW); // LED on to indicate wake-up
Serial.println("Going into light sleep...");
delay(500);
esp_light_sleep_start();
Тестирование кода
После загрузки кода на плату откройте Serial Monitor со скоростью 115200 бод. ESP32 перейдет в режим легкого сна.
Отправьте что-нибудь на ESP32 через Serial, используя Serial Monitor – достаточно одного символа. ESP32 мгновенно проснется и продолжит выполнение кода с того места, где остановился. Если вы хотите, чтобы он прочитал серийные данные, нужно отправить их сразу после пробуждения.
Заключение
В этом руководстве мы рассмотрели легкий сон ESP32 и различные способы его пробуждения. Он поддерживает пробуждение по таймеру, внешнее пробуждение с использованием GPIO, с помощью сенсорных пинов и даже через UART.
Надеемся, что это руководство было полезным. Если вам нужен более энергосберегающий вариант, вы можете рассмотреть глубокий сон ESP32:
Узнайте больше об ESP32 с нашими ресурсами:
Примечание
Источник: :doc:`Random Nerd Tutorials - ESP32 Light Sleep Mode and Wake-Up Sources (Arduino IDE) <../esp32-light-sleep-arduino/index>`_. Авторы: Rui Santos & Sara Santos.