ESP32 Урок 5. GPIO interrupt



В прошлом уроке нам удалось попробовать использование порта ввода-вывода на вход.

Только работали мы с кнопкой, отслеживая её состояние в неком цикле, что накладывает ряд ограничений на работу всей программы. Для этого и придумано следить за состоянием портов именно посредством прерываний. Как это всё работает, мы уже неоднократно видели, например в аналогичном уроке для ESR8266 и уроках для работы с другими контроллерами.

Мы знаем также, что внешние прерывания обрабатываются разные, вернее они работают по разным событиям (нарастание,  спад и т.д.). Есть также универсальные прерывания, которые отслеживают и то и это. ESP32 в этом плане также не исключение и в нём это всё есть. И не только это. В технической документации (Technical Reference Manual) есть описание регистра GPIO_PINn_REG, в котором есть битовое поле, отвечающее за настройку типов прерываний для порта ввода-вывода

 

 

Вот описание установки значения в данном поле:

GPIO_PINn_INT_TYPE Interrupt type selection: (R/W) 0: GPIO interrupt disable; 1: rising edge trigger; 2: falling edge trigger; 3: any edge trigger; 4: low level trigger; 5: high level trigger.

Третий тип установки отслеживает и фронт и спад сигнала.

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

Так как мы будем использовать не один тип изменения сигнала на ножке, давайте подключим две кнопки, одну по-прежнему к GPIO4, а другую — к GPIO5

 

 

Проект мы за основу возьмём из прошлого урока с именем BUTTON01 и дадим ему имя EXTI01.

Откроем наш новый проект в Espressif IDE и внесём некоторые изменения в файл конфигурации Kconfig.projbuild.

Во второй пункт мы добавим номер кнопки, так как их будет два

 

config BUTTON_GPIO_1

  int "Button GPIO1 number"

  range 0 48

  default 4

  help

      GPIO number Button 1.

 

Ниже добавим ещё один пункт для второй кнопки

 

config BUTTON_GPIO_2

  int "Button GPIO2 number"

  range 0 48

  default 5

  help

      GPIO number Button 2.

 

Обратите внимание, что номер порта по умолчанию тоже будет другой.

Попробуем собрать проект, и сконфигурировать его. При сборке скорей всего будет ошибка на изменение имени переменной, не обращаем внимание на это

 

Из тела функции app_main файла main.c удалим весь код, кроме бесконечного цикла, останется вот это

 

 

Теперь у нас, конечно же, код соберётся.

Добавим в данную функцию объявление переменой для счётчика циклов

 

 

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

Поэтому создадим переменную типа такой структуры

 

 

Объявим несколько макросов — один для маски ножки выхода, а другой для маски ножек входа, а также макрос для настройки флага прерываний

 

 

 

Вернёмся в функцию app_main и проинициализируем поля переменной структуры настройками для ножки, работающей на выход

 

 

Применим данные настройки с помощью специальной функции

 

 

Теперь заполним поля для ножек, работающих на вход, и также применим настройки. Поля, которые не меняются, повторно инициализировать не надо

 

 

Мы хотим, чтобы типы прерываний были разные, а у нас присвоился один и тот же тип для обеих ножек при помощи присвоения значения перечислимого типа GPIO_INTR_POSEDGE полю intr_type.

Мы можем определённой ножке порта применить другой тип при помощи функции. Так и поступим

 

 

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

Добавим глобальную переменную для очереди

 

 

Также подключим библиотеку для работы с очередями

 

 

Создадим очередь в app_main

 

Выше функции app_main добавим функцию задачи, которая будет выводить в порт информацию по событиям прерываний

 

 

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

 

 

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

 

 

Включим прерывания

 

 

Мы можем назначить один и тот же обработчик прерывания на оба входа. Добавим функцию для него выше функции task1

 

 

В данном обработчике мы при помощи параметра передаём в очередь номер ножки порта. Стоит обратить внимание, что для передачи в очередь из обработчиков прерываний используется несколько другая функция, нежели из обычных задач.

В функции app_main объявим наш обработчик для каждой ножки

 

 

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

 

 

Ну вот, в принципе, и всё. Соберём код, прошьём контроллер и запустим терминал. Терминал мы сегодня запустим прямо в среде Espressif IDE. Если у кого он ещё не добавлен в окно ввода-вывода, то делается это посредством выбора пункта меню Window->Show View->Terminal

 

 

Запускаем терминал, настраиваем порт и видим как наращивается наш счётчик. В такт с этим мигает светодиод на плате

 

 

 

Нажмём на кнопку 1 и, так как кнопка прижимает ножку на общий провод, то у нас в терминале отобразится уровень 0

 

 

 

Отожмём кнопку, разорвав цепь, и увидим, что на ножке у нас теперь уровень 1

 

 

Также мы в сообщении видим номер ножки порта.

Нажмём теперь кнопку 2

 

 

И в данном случае мы не получим никакого сообщения, так как в случае нажатия кнопки у нас происходит спад, а ножка 5 у нас настроена только на отслеживание фронта

 

 

Отожмём кнопку и вот результат

 

 

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

Всем спасибо за внимание!

 

Данная статья в Дзен.

 

 

Предыдущий урок Программирование МК ESP32 Следующий урок

 

Исходный код

 

 

Недорогие отладочные платы ESP32 можно купить здесь: Недорогие отладочные платы ESP32

 

 

Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)

ESP32 Name

 

Смотреть ВИДЕОУРОК в Дзен (нажмите на картинку)

ESP32 Name

Один комментарий на “ESP32 Урок 5. GPIO interrupt
  1. Anton:

    Не работает ваш код. Ругается на xQueueHandle gpio_evt_queue = NULL;

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

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

*