Прерывания GPIO в ESP32 с использованием ESP-IDF


В этой статье мы научимся использовать прерывания GPIO в ESP32 с помощью ESP-IDF. Мы продемонстрируем прерывания GPIO на примере с использованием кнопки и светодиода. Подпрограмма обработки прерываний внешнего прерывания будет передавать сигнал функциям задач FreeRTOS для управления встроенным светодиодом. Один из выводов GPIO будет инициализирован и настроен как источник прерывания. Он будет запускать прерывание по положительному фронту входного сигнала. Это будет создано с помощью драйвера GPIO, доступного в esp-idf, который затем будет переключать светодиод. Это руководство будет посвящено настройке GPIO для ввода/вывода, инициализации и использованию прерываний, а также использованию очередей FreeRTOS для передачи сигнала из подпрограммы обработки прерываний.

Прежде чем продолжить, убедитесь, что у вас установлена ​​последняя версия VS Code и настроено расширение ESP-IDF:

Если вы новичок в ESP32 ESP-IDF и не знаете, как использовать его контакты GPIO, вы можете обратиться к следующим статьям по началу работы:

Прерывания GPIO в ESP32

Прерывание GPIO — это разновидность внешнего прерывания, при котором внешний триггерный сигнал возникает, например, при нажатии клавиши. При срабатывании прерывания процессор приостанавливает выполнение основной программы. В этот момент вызывается обработчик прерываний (Interrupt Service Routine, ISR). Затем процессор временно переходит к выполнению другой задачи (ISR), а после завершения обработки прерывания возвращается к основной программе. На рисунке ниже показан этот процесс:

Процесс обработки прерывания

Использование таких прерываний очень удобно, поскольку нам не нужно постоянно отслеживать состояние цифровых входных контактов. В этом руководстве мы будем использовать кнопку для запуска прерывания по GPIO. На приведенной ниже схеме показаны контакты GPIO ESP32, которые можно использовать для внешних прерываний. Обратите внимание, что контакты GPIO6, GPIO7, GPIO8, GPIO9, GPIO10 и GPIO11 использовать нельзя.

Контакты прерываний ESP32

Пример прерывания GPIO на ESP32 с помощью ESP-IDF 

Давайте создадим и соберем проект ESP-IDF, чтобы продемонстрировать, как использовать прерывания GPIO для ESP32 с помощью driver/gpio.h и взаимодействовать с задачами и очередями FreeRTOS.

Создание примера проекта с прерываниями GPIO на ESP32

Откройте VS Code и перейдите в меню View > Command Palette («Вид» > «Палитра команд»). Введите в строке поиска ESP-IDF: New Project и нажмите Enter.

Укажите название проекта и каталог. Мы назвали наш проект «ESP32_GPIO_INTERRUPT». Для платы ESP-IDF мы выбрали опцию custom board («Пользовательская плата»). В качестве целевой платформы ESP-IDF мы выбрали модуль ESP32. Нажмите кнопку ‘Choose Template’ («Выбрать шаблон»), чтобы продолжить.

Создание примера проекта с прерываниями GPIO на ESP32

В разделе Extension («Расширение») выберите опцию ESP-IDF:

Выбор опции ESP-IDF в разделе Extension («Расширение»)

На вкладке get-started («Начало работы») мы щелкнем по пункту «sample_project». Затем нажмем ‘Create project using template sample_project’) («Создать проект, используя шаблон sample_project»).

Создание проекта с использованием шаблона sample_project

Вы получите уведомление о создании проекта. Чтобы открыть проект в новом окне, нажмите «Да».

Это откроет проект ESP32_GPIO_INTERRUPT, который мы создали на вкладке EXPLORER. Внутри папки нашего проекта находится несколько папок. Это относится ко всем проектам, которые вы будете создавать с помощью ESP-IDF Explorer. Перейдем к файлу main.c. Папка main содержит исходный код, то есть файл main.c находится именно здесь.

Теперь перейдите в файл main > main.c и откройте его. Скопируйте приведенный ниже код из этого файла и сохраните его.

Код ESP32 для работы с прерываниями GPIO

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

Для начала мы подключим необходимые библиотеки для этого проекта. Это включает библиотеку driver/gpio.h, поскольку нам нужно работать с контактами GPIO, и библиотеки FreeRTOS, так как мы хотим создавать задачи и очереди для мигания светодиода.

Мы подключили кнопку к выводу GPIO15. Поэтому мы определим переменную с именем 'INPUT_PIN', которая будет хранить значение вывода GPIO 15. Она будет использоваться позже в коде для считывания цифрового входа.

Встроенный светодиод ESP32 подключен к GPIO2. Поэтому мы определим переменную с именем 'LED_PIN', которая будет хранить значение контакта GPIO 2. Она будет использоваться позже в коде для управления цифровым выходом.

Функция gpio_interrupt_handler — это обработчик прерываний (ISR). Она вызывается всякий раз, когда происходит прерывание.

Внутри обработчика прерывания мы вызовем функцию xQueueSendFromISR(). Она отправит элемент из очереди. Эта функция принимает три параметра. Первый параметр — 'xQueue', это дескриптор очереди, в которую должен быть помещен элемент. В нашем случае это 'interuptQueue'. Второй параметр — 'pvItemToQueue', это указатель на элемент, помещенный в очередь. В нашем случае это '&pinNumber'. Третий параметр — 'pxHigherPriorityTaskWoken', который в нашем случае равен NULL.

Функция LED_Control_Task приведена ниже. Внутри этой функции мы сначала создаём две целочисленные переменные 'pinNumber' и 'count' и устанавливаем их значения равными 0. Затем внутри бесконечной функции while мы проверяем, получен ли элемент из очереди, используя функцию xQueueReceive(). Эта функция принимает три параметра. Первый параметр — это 'xQueue', дескриптор очереди, из которой должен быть получен элемент. В нашем случае это 'interuptQueue'. Второй параметр — это 'pvBuffer', указатель на буфер, в который будет скопирован полученный элемент. В нашем случае это '&pinNumber'. Третий параметр — это 'xTicksToWait', максимальное время, в течение которого задача должна блокироваться, ожидая получения элемента, если очередь пуста на момент вызова. В нашем случае оно установлено равным 'portMAX_DELAY'. Таким образом, при возникновении прерывания вызывается функция gpio_set_level() для установки уровня LED_PIN в соответствии с уровнем INPUT_PIN. В это время терминал ESP-IDF выводит сообщение о нажатии GPIO, его состоянии, номере контакта и счетчике.

app_main()

Внутри функции app_main() мы сначала настроим входные и выходные GPIO. Сначала мы настроим вывод LED_PIN как GPIO. Для этого мы воспользуемся функцией gpio_pad_select_gpio(). Укажите вывод LED_PIN в качестве параметра внутри этой функции. Затем мы установим направление вывода как выходное с помощью функции gpio_set_direction(). Эта функция принимает два аргумента. Первый аргумент — это вывод GPIO, а второй — режим (вход или выход), в котором мы хотим установить вывод. В нашем случае мы хотим установить вывод LED_PIN как выходной.

Аналогично, мы настроим INPUT_PIN как GPIO и зададим его направление как входное. Кроме того, мы включим подтягивающий резистор и выключим подтягивающий резистор на входном выводе. Таким образом, при нажатии кнопки состояние INPUT_PIN перейдет в высокое состояние, а при отпускании — в низкое. Затем мы установим тип срабатывания прерывания для INPUT_PIN с помощью функции gpio_set_intr_type(). Эта функция принимает два параметра. Первый параметр — номер вывода GPIO, в нашем случае это 'INPUT_PIN'. Второй параметр — тип срабатывания, который устанавливается как 'GPIO_INTR_POSEDGE', что означает, что прерывание будет срабатывать при изменении состояния вывода с низкого на высокое. Это происходит при каждом нажатии кнопки.

Далее мы создадим экземпляр очереди с помощью функции xQueueCreate(). Эта функция вернет дескриптор, через который мы будем ссылаться на новую очередь. Он называется 'interuptQueue'. Функция xQueueCreate() принимает два параметра. Первый параметр — это максимальное количество элементов, которое может вместить очередь, а второй — количество байтов для каждого элемента. В нашем случае мы установили максимальное количество элементов равным 10, а количество байтов — размеру (целым числом).

Затем мы создадим задачу для управления светодиодом. Для создания задачи мы используем функцию  xTaskCreate(). Эта функция принимает несколько аргументов.

  • Первый аргумент — это имя функции. В нашем случае мы установили его значение равным LED_Control_Task.
  • Второй аргумент — это имя задачи для описательных целей. В нашем случае мы задали второй аргумент как «LED_Control_Task».
  • Третий аргумент задает размер стека задачи. Он указывает объем памяти, который мы хотим зарезервировать для конкретной задачи. Мы установили его равным '2048'.
  • Четвертый аргумент — это параметр. Это значение, которое передается в качестве параметра создаваемой задаче. В нашем случае мы установим этот аргумент равным NULL, что указывает на то, что мы не используем это свойство.
  • Пятый аргумент — это приоритет задачи. Мы установили его равным «1».
  • Последний аргумент — это дескриптор, используемый для изменения функции задачи, например, приостановки, удаления, возобновления, получения или установки конфигурации задачи. Он необязателен, поэтому мы установили его значение равным NULL.

Затем мы вызовем функцию gpio_install_isr_service() для установки службы обработки прерываний. Она принимает один параметр, обозначающий флаги для выделения прерываний. В нашем случае мы указали параметр как '0'. Наконец, мы добавим обработчик прерываний для INPUT_PIN с помощью функции gpio_isr_handler_add(). Эта функция принимает три параметра. Первый параметр — это номер контакта GPIO, который мы указали как 'INPUT_PIN'. Второй параметр — это функция обработчика прерываний для нашего GPIO, в нашем случае это gpio_interrupt_handler. Третий параметр — это параметр для обработчика прерываний, в нашем случае это (void *)INPUT_PIN.

Настройка оборудования

Соберите схему как показано на рисунке ниже:

Схема проекта для работы с прерываниями GPIO в ESP32

Здесь кнопка подключена к выводу прерывания ESP32. В коде мы использовали GPIO15 в качестве входного вывода, поэтому один из выводов кнопки подключен к GPIO15. Поскольку мы уже настроили подтягивающий резистор на этом GPIO, нет необходимости добавлять физический резистор самостоятельно. При нажатии кнопки состояние GPIO15 изменится с НИЗКОГО на ВЫСОКОЕ (происходит положительный фронт сигнала), и будет срабатывать прерывание. Другой вывод кнопки подключен к напряжению 3,3 В от ESP32 для получения активного высокого сигнала при нажатии.

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

Компиляция скетча

Для прошивки микросхемы введите следующую команду в последовательном терминале. Не забудьте заменить COM-порт на тот, через который подключена ваша плата.

После успешной прошивки кода нажмите кнопку, подключенную к GPIO5. Ее состояние изменится с LOW на HIGH, и произойдет прерывание. Это приведет к включению встроенного светодиода. Терминал ESP-IDF отобразит количество нажатий GPIO и его текущее состояние.

Тестирование работы проекта использования прерываний GPIO в ESP32 в окне терминала

(Проголосуй первым!)
Загрузка...
3 просмотров

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *