В этом уроке мы научимся настраивать и генерировать прерывания таймера для ESP32 с помощью ESP-IDF. ESP32 имеет две группы 64-битных таймеров общего назначения, каждая из которых содержит 16-битные делители частоты и 64-битные счетчики вверх/вниз. Мы рассмотрим, как запускать определенную процедуру обработки прерываний на основе прерывания таймера.
Настройка прерываний таймера будет осуществляться в ESP-IDF с использованием API esp_timer. ESP-IDF предоставляет драйвер esp_timer High Resolution Timer, содержащий API для создания как периодических, так и однократных таймеров с разрешением по времени в микросекунды и 64-битным диапазоном для аппаратных таймеров.

Также вам могут быть интересны следующие статьи:
- таймер высокого разрешения на ESP32 с помощью ESP-IDF;
- таймеры и задержки в FreeRTOS на ESP32 с помощью ESP-IDF;
- использование таймеров и прерываний от них в модуле ESP32 (с помощью Arduino IDE).
Прежде чем продолжить, убедитесь, что у вас установлена последняя версия VS Code и настроено расширение ESP-IDF:
- Установка ESP32 ESP-IDF на Windows и его интеграция с Visual Studio Code
- Установка ESP32 ESP-IDF на Linux Ubuntu
Также на нашем сайте вы можете прочитать статью про начало работы с ESP32 с использованием ESP-IDF.
Пример прерывания таймера ESP-IDF
Мы создадим проект в VS Code с расширением ESP-IDF, в котором будет использоваться прерывание таймера для переключения встроенного светодиода ESP32. Светодиод будет настроен как цифровой выход и будет переключаться через заданное количество интервалов. Давайте покажем, как это сделать с помощью функций из esp_timer.h.
Создание примера проекта
Откройте VS Code и перейдите в меню View > Command Palette («Вид» > «Палитра команд»). Введите в строке поиска ESP-IDF: New Project и нажмите Enter.
Укажите название проекта и каталог. Мы назвали наш проект «ESP32_TIMER_INTERRUPT». Для платы ESP-IDF мы выбрали опцию custom board («Пользовательская плата»). В качестве целевой платформы ESP-IDF мы выбрали модуль ESP32. Нажмите кнопку ‘Choose Template’ («Выбрать шаблон»), чтобы продолжить.
В разделе Extension («Расширение») выберите опцию ESP-IDF:
На вкладке get-started («Начало работы») мы щелкнем по пункту «sample_project». Затем нажмем ‘Create project using template sample_project’) («Создать проект, используя шаблон sample_project»).
Вы получите уведомление о создании проекта. Чтобы открыть проект в новом окне, нажмите «Да».
Это открывает наш проект ESP32_TIMER_INTERRUPT, который мы создали на вкладке EXPLORER. Внутри папки проекта находится несколько папок. Это одинаково для всех проектов, которые вы будете создавать с помощью ESP-IDF Explorer. Перейдем к файлу main.c. Папка main содержит исходный код, то есть файл main.c находится именно здесь.
Теперь перейдите в файл main > main.c и откройте его. Скопируйте приведенный ниже код из этого файла и сохраните его.
Код прерывания таймера ESP32
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <stdio.h> #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" #include "driver/gpio.h" void timer_callback(void *param) { static bool ON; ON = !ON; gpio_set_level(GPIO_NUM_2, ON); } void app_main(void) { gpio_pad_select_gpio(GPIO_NUM_2); gpio_set_direction(GPIO_NUM_2, GPIO_MODE_OUTPUT); const esp_timer_create_args_t my_timer_args = { .callback = &timer_callback, .name = "My Timer"}; esp_timer_handle_t timer_handler; ESP_ERROR_CHECK(esp_timer_create(&my_timer_args, &timer_handler)); ESP_ERROR_CHECK(esp_timer_start_periodic(timer_handler, 50)); while (true) { esp_timer_dump(stdout); vTaskDelay(pdMS_TO_TICKS(1000)); } } |
Как работает код?
API для таймера высокого разрешения определены в файле components/esp_timer/include/esp_timer.h. Поэтому мы включим этот драйвер в самом начале вместе с другими необходимыми библиотеками, такими как библиотеки FreeRTOS для генерации задержки, esp_log.h для отладки и driver/gpio.h для настройки выходных GPIO ESP32.
|
1 2 3 4 5 6 |
#include <stdio.h> #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" #include "driver/gpio.h" |
Таймер имеет функцию обратного вызова, которая вызывается каждый раз, когда таймер срабатывает. Функция timer_callback используется для переключения встроенного светодиода. Встроенный светодиод ESP32 подключен к GPIO2. Поэтому мы вызываем функцию gpio_set_level() для установки уровня GPIO2 на значение, хранящееся в переменной 'ON'. Переменная 'ON' имеет тип статического логического значения (static bool), которое будет инвертировать свое логическое значение, поскольку она содержит значение !ON.
|
1 2 3 4 5 6 7 |
void timer_callback(void *param) { static bool ON; ON = !ON; gpio_set_level(GPIO_NUM_2, ON); } |
Внутри функции app_main() мы сначала настроим выходной GPIO. Для этого мы сначала воспользуемся функцией gpio_pad_select_gpio(), чтобы указать GPIO_NUM_2 в качестве вывода GPIO. Затем мы установим направление вывода как выходное с помощью функции gpio_set_direction(). Эта функция принимает два аргумента. Первый аргумент — это вывод GPIO, а второй — режим (вход или выход), в котором мы хотим установить вывод. В нашем случае мы хотим установить GPIO_NUM_2 в качестве выходного вывода.
|
1 2 |
gpio_pad_select_gpio(GPIO_NUM_2); gpio_set_direction(GPIO_NUM_2, GPIO_MODE_OUTPUT); |
Создание таймера
Далее мы определим конфигурацию таймера, которая будет передана функции esp_timer_create(). Структура конфигурации таймера esp_timer_create_args_t содержит функцию обратного вызова таймера, которая будет вызвана по истечении времени таймера, и имя таймера, которое будет использоваться в функции esp_timer_dump().
|
1 2 3 |
const esp_timer_create_args_t my_timer_args = { .callback = &timer_callback, .name = "My Timer"}; |
Затем мы создаём переменную типа esp_timer_handle_t, которая является обработчиком таймера для одного esp_timer. В нашем случае это переменная типа 'timer_handler'.
|
1 |
esp_timer_handle_t timer_handler; |
После определения обработчика таймера мы создадим экземпляр esp_timer с помощью функции esp_timer_create(). Эта функция принимает два параметра. Первый параметр — это указатель на структуру esp_tier_create_args_t, которую мы определили ранее. В нашем случае это '&my_timer_args'. Второй параметр — это указатель на переменную esp_timer_handle_t, содержащую созданный нами ранее дескриптор таймера. В нашем случае это '&timer_handler'.
|
1 |
ESP_ERROR_CHECK(esp_timer_create(&my_timer_args, &timer_handler)); |
Запуск таймера
После создания таймера он запускается. Для запуска периодического таймера используется функция esp_timer_start_periodic(). Этот вызов функции запускает периодический таймер, который будет срабатывать через каждый указанный период времени в микросекундах. Функция принимает два параметра. Первый параметр — это дескриптор таймера, а второй — период времени в микросекундах, через который вызывается функция обратного вызова. Период времени устанавливается равным 1000000 микросекунд, что эквивалентно 1 секунде. Следовательно, прерывание таймера будет срабатывать каждую секунду.
|
1 |
ESP_ERROR_CHECK(esp_timer_start_periodic(timer_handler, 1000000)); |
Внутри бесконечного цикла while мы будем выводить список таймеров в поток каждую секунду, используя функцию esp_timer_dump(). Она принимает один параметр — поток, куда будут выводиться данные. Эта функция выведет список активных таймеров в следующем формате: имя таймера, период таймера и время следующего срабатывания будильника с момента загрузки в микросекундах.
|
1 2 3 4 5 |
while (true) { esp_timer_dump(stdout); vTaskDelay(pdMS_TO_TICKS(1000)); } |
Компиляция скетча
Для прошивки микросхемы введите следующую команду в последовательном терминале. Не забудьте заменить COM-порт на тот, через который подключена ваша плата.
|
1 |
idf.py -p COMX flash monitor |
После успешной прошивки кода встроенный светодиод начнет мигать с задержкой в 1 секунду. Каждую секунду будет срабатывать прерывание таймера, которое вызовет функцию timer_callback(), переключающую состояние светодиода. Кроме того, терминал ESP-IDF также будет выводить данные таймера, а также период его работы и время с момента загрузки для следующего будильника.
2 просмотров







