ESP32:Примеры/Режим глубокого сна: пробуждение с помощью нескольких GPIO-контактов
Режим глубокого сна: пробуждение с помощью нескольких GPIO-контактов
В этом примере мы разберем проект, где ESP32 можно будет разбудить с помощью разных кнопок, а код будет определять, с помощью какой кнопки было инициировано пробуждение. В данном случае контактами для пробуждения будут служить GPIO2 и GPIO15.
Справочная информация
Внешнее пробуждение типа «ext0»
Во-первых, ESP32 можно разбудить при помощи одного контакта RTC_GPIO. Чтобы использовать этот метод пробуждения, в коде нужно воспользоваться следующей функцией:
esp_sleep_enable_ext0_wakeup(GPIO_NUM_X, level)
Первый параметр в этой функции – это «GPIO_NUM_X», то есть контакт, которым мы хотим воспользоваться (здесь «X» – это GPIO-номер этого контакта).
Второй параметр – это значение, которое станет триггером для пробуждения («0» или «1»).
Внешнее пробуждение типа «ext1»
Во-вторых, ESP32 можно пробудить при помощи нескольких контактов RTC_GPIO. В этом случае предусмотрены две возможности:
- Пробуждение, если какой-либо из заданных контактов получил значение «HIGH»
- Пробуждение, если все заданные контакты получили значение «LOW»
Этот тип пробуждения выполняется с помощью RTC-контроллера. Следовательно, RTC-периферию и RTC-память при использовании этого режима можно отключить.
Чтобы воспользоваться этим типом пробуждения, в коде нужно вписать следующую функцию:
esp_sleep_enable_ext1_wakeup(bitmask, mode)
В этой функции два параметра:
- «bitmask», т.е. битовая маска для номеров GPIO-контактов, являющихся инициаторами пробуждения
- «mode», т.е. тип ext1-пробуждения ESP32:
- «ESP_EXT1_WAKEUP_ALL_LOW» – пробуждение, если у всех контактов «LOW»
- «ESP_EXT1_WAKEUP_ANY_HIGH» – пробуждение, если у любого контакта «HIGH»
Общий принцип создания битовой маски для GPIO-контактов
Чтобы получить нужную битовую маску, проделайте следующее:
- Возведите «2» в степень, соответствующую номеру контакта. Сохраните результат в десятичном формате;
- Перейдите сюда и переведите это десятичное число в шестнадцатеричный формат(или воспользуйтесь любым ПО, которое может конвертировать числа из одной системы счисления в другую);
- Вставьте результат в переменную «BUTTON_PIN_BITMASK»;
Битовая маска для одного GPIO-контакта
Сначала давайте разберем, как сделать битовую маску для одного контакта. Допустим в скетче кнопка подключена к контакту GPIO33. Чтобы сделать маску для этого контакта, проделайте следующее:
- Возведите «2» в степень «33» (2^33). У вас должно получиться «8589934592»
- Переведите это число в шестнадцатеричный формат. Это можно сделать при помощи этого конвертера(или воспользуйтесь любым ПО, которое может конвертировать числа из одной системы счисления в другую):
- Скопируйте шестнадцатеричный результат в переменную «BUTTON_PIN_BITMASK». У вас должно получиться вот так:
#define BUTTON_PIN_BITMASK 0x200000000 // это 2 в 33 степени
// в шестнадцатеричном
// выражении
Битовая маска для нескольких GPIO-контактов
Если вы хотите использовать в качестве инициаторов пробуждения контакты GPIO2 и GPIO15, вам нужно сделать следующее:
- Возведите «2» в степень «2» (2^2), затем «2» в степень «15» (2^15), а потом сложите два этих значения друг с другом. У вас должно получиться «32772»
- Переведите это число в шестнадцатеричный формат. У вас должно получиться «8004»
- Вставьте результат в переменную «BUTTON_PIN_BITMASK», чтобы получилось так:
#define BUTTON_PIN_BITMASK 0x8004
Определение GPIO-контакта, используемого для пробуждения
Если вы используете несколько контактов для пробуждения ESP32, то в коде также нужен фрагмент для определения того, какой именно контакт вызвал пробуждение. Для этого используется следующая функция:
esp_sleep_get_ext1_wakeup_status();
Эта функция возвращает число, которое получится если возвести «2» в степень, равную номеру GPIO-контакта (2^GPIO), вызвавшего пробуждение. Следовательно, чтобы рассчитать номер контакта, ставшего причиной пробуждения, нужно проделать следующие расчеты:
GPIO = log(GPIO_reason)/log(2);
Проверка скетча
Подключив кнопки к контактам GPIO2 и GPIO15, а также убедившись, что в IDE Arduino выбраны правильные плата и COM-порт, загрузите на ESP32 код выше.
Итак, ESP32 уже должна быть в режиме глубокого сна. Вы можете разбудить ее, нажав на одну из двух подключенных к ней кнопок.
Откройте монитор порта на скорости 115200 бод. Понажимайте на кнопки, чтобы разбудить ESP32.
В мониторе порта должно появиться примерно следующее:
Итак, в этом примере мы научились выводить ESP32 из режима глубокого сна при помощи внешнего пробуждения. Это значит, что вы теперь знаете, как будить ESP32 с помощью изменения состояния на каком-либо GPIO-контакте.
Если вкратце, мы научились следующему:
- Для внешнего пробуждения можно использовать только контакты типа RTC_GPIO;
- Внешнее пробуждение бывает двух типов: ext0 и ext1;
- Метод ext0 позволяет будить ESP32 с помощью одного GPIO-контакта;
- Метод ext1 позволяет будить ESP32 с помощью нескольких GPIO-контактов;
Необходимое оборудование
- Плата ESP32 - 1шт.;
- Кнопка - 2 шт.;
- Резистор 10кОм - 2шт.;
- Провода перемычки;
- Макетная плата - 1шт.;
Схема
Кнопки подключены к GPIO2 и GPIO15.
Код
/*
Режим глубокого сна и внешнее пробуждение
=====================================
Этот скетч-пример демонстрирует, как выводить ESP32
из режима глубокого сна при помощи внешнего триггера,
а также, как сохранять данные в RTC-память,
чтобы потом использовать их между загрузками.
Этот код распространяется по лицензии всеобщего достояния.
=====================================
ПРИМЕЧАНИЕ
======
В качестве инициатора внешнего пробуждения
могут использоваться только контакты типа RTC_GPIO.
Вот они: 0, 2, 4, 12-15, 25-27, 32-39.
Автор:
Пранав Черукупалли <cherukupallip@gmail.com>
*/
#define BUTTON_PIN_BITMASK 0x8004 // битовая маска
// для контактов GPIO2 и GPIO15
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;
// "Пробуждение не связано с режимом глубокого сна"
}
}
/*
Это функция для печати в мониторе порта номера GPIO-контакта,
ставшего триггером вывода ESP32 из режима сна.
*/
void print_GPIO_wake_up(){
int GPIO_reason = esp_sleep_get_ext1_wakeup_status();
Serial.print("GPIO that triggered the wake up: GPIO ");
// "GPIO-контакт, ставший триггером пробуждения: GPIO"
Serial.println((log(GPIO_reason))/log(2), 0);
}
void setup(){
Serial.begin(115200);
delay(1000); // даем время на установку последовательного соединения
// увеличиваем значение в счетчике загрузок
// и печатаем это значение с каждой загрузкой ESP32:
++bootCount;
Serial.println("Boot number: " + String(bootCount));
// "Номер загрузки: "
// печатаем причину пробуждения ESP32:
print_wakeup_reason();
// печатаем GPIO-контакт, ставший триггером пробуждения:
print_GPIO_wake_up();
/*
Во-первых, задаем инициатора пробуждения – внешний триггер.
Внешний триггер может быть двух типов: ext0 и ext1.
Пробуждение типа ext0 использует один контакт RTC_GPIO,
поэтому ему нужна включенная RTC-периферия.
Пробуждение типа ext1 использует RTC-контроллер,
поэтому ему включенная периферия не нужна.
Кроме того, чтобы RTC-периферия оставалась включенной,
понадобится использовать встроенные подтягивающие
и стягивающие резисторы.
*/
// если вы используете метод ext1, вам понадобится вот эта строчка:
esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);
// переходим в режим сна:
Serial.println("Going to sleep now");
// "Переходим в режим сна"
delay(1000);
esp_deep_sleep_start();
Serial.println("This will never be printed");
// "Это сообщение никогда не будет напечатано"
}
void loop(){
// до этого фрагмента скетч никогда не доберется
}
См.также
Внешние ссылки