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

Материал из Онлайн справочника
Версия от 09:21, 18 июня 2023; Myagkij (обсуждение | вклад)
(разн.) ← Предыдущая версия | Текущая версия (разн.) | Следующая версия → (разн.)
Перейти к навигацииПерейти к поиску

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


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

Мы можем разбудить ESP32 не только с помощью таймера или тактильных контактов, но также при помощи изменения значения на контакте/контактах RTC_GPIO (например, нажатием на кнопку/кнопки). Это называется «внешним пробуждением». При использовании этого метода пробуждения RTC-периферия останется включенной. Внешнее пробуждение можно осуществить двумя способами: ext0 и ext1.

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

Внешнее пробуждение типа «ext0»

Во-первых, ESP32 можно разбудить при помощи одного контакта RTC_GPIO. Чтобы использовать этот метод пробуждения, в коде нужно воспользоваться следующей функцией:

esp_sleep_enable_ext0_wakeup(GPIO_NUM_X, level)

Первый параметр в этой функции – это «GPIO_NUM_X», то есть контакт, которым мы хотим воспользоваться (здесь «X» – это GPIO-номер этого контакта).

Второй параметр – это значение, которое станет триггером для пробуждения («0» или «1»).

Примечание

Для этого типа пробуждения необходимо использовать только контакты RTC_GPIO.

Внешнее пробуждение типа «ext1»

Во-вторых, ESP32 можно пробудить при помощи нескольких контактов RTC_GPIO. В этом случае предусмотрены две возможности:

  • Пробуждение, если какой-либо из заданных контактов получил значение «HIGH»
  • Пробуждение, если все заданные контакты получили значение «LOW»

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

Чтобы воспользоваться этим типом пробуждения, в коде нужно вписать следующую функцию:

esp_sleep_enable_ext1_wakeup(bitmask, mode)
Внимание!

На момент написания этого руководства в документации о режиме глубокого сна была опечатка. Там указана функция esp_deep_sleep_enable_ext1_wakeup(), но в действительности работает та, что указана выше – esp_sleep_enable_ext1_wakeup()

В этой функции два параметра:

  • «bitmask», т.е. битовая маска для номеров GPIO-контактов, являющихся инициаторами пробуждения
  • «mode», т.е. тип ext1-пробуждения ESP32:
    • «ESP_EXT1_WAKEUP_ALL_LOW» – пробуждение, если у всех контактов «LOW»
    • «ESP_EXT1_WAKEUP_ANY_HIGH» – пробуждение, если у любого контакта «HIGH»
Примечание

Для этого типа пробуждения необходимо использовать только контакты RTC_GPIO.

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

Этот скетч-пример выводит ESP32 из режима глубокого сна, если переключить контакт GPIO33 на «HIGH». В этом скетче демонстрируется использование обоих методов – и ext0, и ext1. Если вы загрузите этот код на ESP32 безо всяких изменений, то плата будет выходить из режима глубокого сна при помощи метода ext0. Чтобы воспользоваться методом ext1, вам нужно убрать знаки комментария у строчки с функцией esp_sleep_enable_ext1_wakeup().

Ниже мы рассмотрим, как работают оба этих метода и как их использовать.

Сначала мы в блоке setup() запускаем последовательное соединение:

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

Затем увеличиваем значение в переменной «bootCount» и печатаем его в мониторе порта:

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

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

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

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

ext0

В этом примере ESP32 выйдет из режима глубокого сна после того, как на контакт GPIO33 будет подано значение «HIGH».

esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1); // 1 = «HIGH»,
                                             // 0 = «LOW»

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

Имейте в виду, что в данном случае в качестве инициаторов пробуждения могут использоваться только контакты типа RTC_GPIO. Они помечены на схеме ниже оранжевым цветом. Таким образом, вы вместо GPIO33 можете подключить кнопку к любому контакту RTC_GPIO.


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

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

Нажмите на кнопку, чтобы «разбудить» ESP32.

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

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

Но что, если мы хотим создать проект, где есть несколько кнопок, которые будят ESP32, но каждая – для какой-то отдельной задачи? Именно для этого и нужен метод ext1.

ext1

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

Для использования этого метода мы вместо функции esp_sleep_enable_ext0_wakeup() должны воспользоваться функцией esp_sleep_enable_ext1_wakeup(). В скетче-примере ниже строчка с этой функцией заблокирована знаками комментирования:

// если вы решили использовать ext1, вам нужна строчка ниже:
//esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

Уберите у нее знаки комментария, чтобы получилось так:

esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

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

В этом примере нам понадобится переменная «BUTTON_PIN_BITMASK», которая была задана в самом начале кода:

#define BUTTON_PIN_BITMASK 0x200000000 // это 2 в 33 степени
                                       // в шестнадцатеричном
                                       // выражении

Число «0x200000000» делает инициатором пробуждения только 1 контакт – GPIO33. Нам нужно изменить эту битовую маску, чтобы сделать инициаторами пробуждения несколько контактов.

Общий принцип создания битовой маски для GPIO-контактов

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

  1. Возведите «2» в степень, соответствующую номеру контакта. Сохраните результат в десятичном формате;
  2. Перейдите сюда и переведите это десятичное число в шестнадцатеричный формат(или воспользуйтесь любым ПО, которое может конвертировать числа из одной системы счисления в другую);
  3. Вставьте результат в переменную «BUTTON_PIN_BITMASK»;

Битовая маска для одного GPIO-контакта

Сначала давайте разберем, как сделать битовую маску для одного контакта. В скетче кнопка подключена к контакту GPIO33. Чтобы сделать маску для этого контакта, проделайте следующее:

  • Возведите «2» в степень «33» (2^33). У вас должно получиться «8589934592»
  • Переведите это число в шестнадцатеричный формат. Это можно сделать при помощи этого конвертера(или воспользуйтесь любым ПО, которое может конвертировать числа из одной системы счисления в другую):
  • Скопируйте шестнадцатеричный результат в переменную «BUTTON_PIN_BITMASK». У вас должно получиться вот так:
#define BUTTON_PIN_BITMASK 0x200000000 // это 2 в 33 степени
                                       // в шестнадцатеричном 
                                       // выражении

Битовая маска для нескольких GPIO-контактов

Если вы хотите использовать в качестве инициаторов пробуждения контакты GPIO2 и GPIO15, вам нужно сделать следующее:

  1. Возведите «2» в степень «2» (2^2), затем «2» в степень «15» (2^15), а потом сложите два этих значения друг с другом. У вас должно получиться «32772»
  2. Переведите это число в шестнадцатеричный формат. У вас должно получиться «8004»
  3. Вставьте результат в переменную «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);

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

Схема

Примечание

На данной схеме используется плата ESP32S-HiLetgo, если вы используете другую, сверьтесь с вашей распиновкой.

Для этого проекта нам нужно подсоединить кнопку к ESP32 согласно схеме ниже. То есть нам нужно подключить кнопку к контакту GPIO33 при помощи стягивающего резистора на 10 кОм.

Код

Внимание!

На момент написания этого руководства в скетче-примере из библиотеки ESP32 была ошибка. В документации указана функция esp_deep_sleep_enable_ext1_wakeup(), но в действительности работает та, что указана выше – esp_sleep_enable_ext1_wakeup(). В коде ниже эта опечатка исправлена.

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

Этот код распространяется по лицензии всеобщего достояния.

Подключение компонентов
======================
Кнопка должна быть подключена к контакту GPIO33,
притянутому к «LOW» при помощи резистора на 10 кОм

ПРИМЕЧАНИЕ
======
В качестве инициаторов внешнего пробуждения
можно использовать только контакты RTC_GPIO.
Вот они: 0,2,4,12-15,25-27,32-39.

Автор:
Пранав Черукупалли <cherukupallip@gmail.com>
*/

#define BUTTON_PIN_BITMASK 0x200000000 // это 2 в 33 степени
                                       // в шестнадцатеричном 
                                       // выражении

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»: 
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));
             //  "Номер загрузки: "

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

  /*
  Во-первых, задаем инициатор пробуждения – внешний триггер.
  Есть два типа внешних триггеров для ESP32: ext0 и ext1.
  Тип ext0 использует для пробуждения контакт RTC_IO,
  поэтому ему также нужна включенная RTC-периферия.
  Тип ext1 использует RTC-контроллер,
  поэтому ему включенная RTC-периферия не нужна.
  Имейте в виду, что для работы RTC-периферии также нужно
  использовать встроенные подтягивающие/стягивающие резисторы.
  */
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1); // 1 = «HIGH»,
                                               // 0 = «LOW»

  // если вы решили использовать метод 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(){
  // до этого фрагмента дело никогда не дойдет
}

См.также

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