Esp32 arduino timer: Timer — Arduino-ESP32 2.0.6 documentation

Использование таймеров на ESP32 | kotyara12.ru

Добрый день, уважаемый читатель! Сегодня поговорим о таймерах, которые предоставляет нам платформа ESP32.

Наверное я не сильно погрешу против истины, если скажу что в практически всех прошивках используются таймеры для отсчета необходимых временных интервалов. В том или ином виде. Это могут быть временные интервалы между считыванием данных с сенсоров, включение нагрузки на заданное время и так далее. Давайте посмотрим, какие средства предоставляет нам ESP32:

  • Функция ets_delay_us()
  • Функция sys_delay_ms()
  • Функции FreeRTOS – vTaskDelay() и vTaskDelayUntil()
  • Аппаратные таймеры 64-bit General Purpose Timer – 4 шт.
  • Программные таймеры (много)

Возможно, этот список не полный, я пока знаком далеко не со всеми внутренностями ESP-IDF. Если вы знакомы с ещё какими-либо способами – пожалуйста, прошу в комментарии. Начнем с самого простого способа.

 

Функция ets_delay_us()

Есть простая системная функция, которая выполняет задержку на время us в микросекундах с полной блокировкой программы. Аналог delay() для Arduino, но с большим разрешением.

void ets_delay_us(uint32_t us)

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

Функция sys_delay_ms()

Еще один “не таймер“. Аналог функции delay(), которую мы все помним еще по Arduino.

void sys_delay_ms(uint32_t ms)

Внутри эта функция просто вызывает vTaskDelay(ms / portTICK_PERIOD_MS).

Функции vTaskDelay() и vTaskDelayUntil()

И eще два “не таймера“. Эти функции предоставляет нам даже не ESP32, а FreeRTOS и предназначены они для приостановки выполнения текущей задачи на заданное количество тиков. В отличие от ets_delay_us() не нагружают процессор, а наоборот – освобождают его от части работы, что гораздо полезнее. А значит могут с успехом применяться при создании довольно точных временных интервалов, например для периодического выполнения той или иной полезной работы.

Задержка задачи на заданное количество тиков:

void vTaskDelay(const TickType_t xTicksToDelay)

Тик – это один “шаг” операционной системы, который в конечном итоге привязан к “кварцованной” таковой частоте процессора, а значит отсчитываемый интервал должен быть достаточно точным. Конечно, это не полноценный таймер, но для отсчета 30 секунд между изменениями с сенсоров вполне подойдет. Пересчитать необходимую длительность в миллисекундах в тики достаточно легко. Для этого у нас есть два макроса:

  • время в тиках = время в мс / portTICK_PERIOD_MS
  • время в тиках = pdMS_TO_TICKS ( время в мс )

portTICK_PERIOD_MS и pdMS_TO_TICKS – это макросы, привязанные к частоте операционной системы, вы можете использовать любой способ (я предпочитаю второй). Но vTaskDelay() не обеспечивает идеального контроля частоты периодической задачи, поскольку время, затраченное на выполнение этого самого периодического кода, а также другие задачи и прерывания будут влиять на частоту, с которой вызывается vTaskDelay(), и, следовательно, на время, при котором выполняется следующая итерация задачи. Чтобы уменьшить влияние этих эффектов, существует немного более продвинутая функция:

BaseType_t xTaskDelayUntil (TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement)

Как видите, здесь добавился ещё один параметр – указатель на переменную pxPreviousWakeTime, где будет хранится время последнего вызова этой функции. И при следующем вызове xTaskDelayUntil() заданное количество тиков будет скорректировано с учетом этих данных. Таким образом легко организовать равномерный интервал выполнения какой-либо задачи. Пример использования vTaskDelay() мы уже рассматривали в одной из предыдущих статей, его можно найти на GitHub.  

 

Аппаратные таймеры

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

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

Чип ESP32 содержит четыре аппаратных таймера общего назначения – две группы по два таймера. Все они являются 64-битными универсальными таймерами, основанными на 16-битных масштабаторах (их ещё называют предделители) и 64-битных счетчиках увеличения/уменьшения, которые могут перезапускаться автоматически.

Для работы с аппаратными таймерами подключите библиотеку:#include "driver/timer.h"

Общая схема работы с аппаратными таймерами такова:

  • Инициализируйте таймер с помощью функции timer_init(). Здесь вы задаете коэффициент деления входящей частоты (то есть минимальный интервал таймера), направление счета и параметры автоматического аппаратного перезапуска.
  • Задайте начальное и конечное значение счетчика таймера с помощью timer_set_counter_value() и timer_set_alarm_value().
  • Создайте функцию – обработчик прерывания и подключите его к таймеру – timer_isr_callback_add() и timer_enable_intr().
  • Запустите счетчик таймера с помощью функции timer_start()

Рассмотрим все эти этапы поподробнее.

Инициализация таймера и настройка параметров

Для инициализации таймера необходимо вызывать функцию:

esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, const timer_config_t *config)

где:

  • timer_group_t group_num – номер группы таймеров, может принимать всего два значения:TIMER_GROUP_0 илиTIMER_GROUP_1 (нумерация начинается с головы поезда нуля)
  • timer_idx_t timer_num – номер таймера в группе, может принимать всего два значения:TIMER_0 илиTIMER_1
  • const timer_config_t *config – указатель на параметры таймера, которые выглядят так:

Рассмотрим эту структуру подробнее:

  • uint32_t divider – Делитель тактовой частоты, или масштабатор. Диапазон делителя может быть от 2 до 65536. Да, да, делитель не может быть равным 0 или 1, то есть максимальная частота таймера 40MHz, что соответствует минимальному интервалу 0,025 микросекунды.
  • timer_count_dir_t counter_dir – направление счета: TIMER_COUNT_DOWN – вниз или TIMER_COUNT_UP – вверх
  • timer_autoreload_t auto_reload – разрешить автоматический аппаратный рестарт таймера после генерации прерывания; может принимать значения TIMER_AUTORELOAD_DIS или TIMER_AUTORELOAD_EN. При TIMER_AUTORELOAD_EN получится периодический таймер, при TIMER_AUTORELOAD_DIS – однократный.
  • timer_alarm_t alarm_en – разрешить или нет сигнал “будильника” для таймера; может принимать значения TIMER_ALARM_DIS или TIMER_ALARM_EN
  • timer_start_t counter_en – разрешить счет (работу таймера) или нет; может принимать два значения: TIMER_PAUSE или TIMER_START. При TIMER_PAUSE необходимо будет запустить таймер “вручную” после завершения всех настроек, иначе таймер будет запущен немедленно
  • timer_intr_mode_t intr_type – всегда TIMER_INTR_LEVEL (0), других вариантов пока просто нет, можно не заполнять.

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

esp_err_t timer_set_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t load_val)

Здесь также необходимо задать идентификаторы группы и таймера, а также 64-битное начальное значение счетчика

Для задания конечного значения счетчика (по которому будет сгенерировано прерывание) необходимо вызывать другую похожую функцию:

esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_value) 

Впрочем, для изменения параметров таймера есть ещё целая кучка функций:

  • timer_set_divider() – для изменения значения делителя (во избежание неопределенности рекомендуется остановить таймер перед изменением этого значения)
  • timer_set_counter_mode() – для изменения направления счета
  • timer_set_auto_reload() – для изменения режима аппаратного перезапуска
  • timer_set_alarm() – для включения или отключения “будильника”

Создание обработчика прерываний

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

Обработчики прерывания – не совсем простые функции. Прерывание приостанавливает выполнение всех потоков вашей программы, поэтому к обработчикам прерываний предъявляются определенные требования:

  • Обработчик прерывания должен выполняться как можно меньше по времени, иначе сработает WDT для прерываний и устройство будет аварийно перезагружено.
  • Обработчик прерывания должен постоянно находится в быстрой памяти IRAM, поэтому его следует пометить соответствующим атрибутом IRAM_ATTR.
  • В обработчиках прерываний не допускается использование библиотечных функций ESP_LOGx, но можно использовать специальную облегченную версию ESP_DRAM_LOGx.
  • Следует всегда помнить, что обработчики прерываний выполняются вне контекста прикладных задач. Дабы соблюдать потокобезопасность из обработчика прерываний лучше всего отправить какие-либо данные в очередь другой задачи, включить флаг в EventGroup и т.д. Да, в принципе можно просто изменить значение какой-либо глобальной статической переменной bool или int, которая будет управлять потоком в другой задаче, но это не приветствуется.

Вначале нужно создать callback-функцию, которая будет вызвана при генерации прерывания, называется она обработчик прерывания (ISR handler или ISR callback). Создается она по следующем шаблону:

Ничего сверхсложного, но стоит обратить внимание на два существенных момента:

  • Функция эта должна быть обязательно помечена как IRAM_ATTR, чтобы заставить компилятор постоянно держать её в быстрой памяти.
  • Обратите внимание на возвращаемое значение: какое значение должна вернуть эта функция (кстати, в других ISR-обработчиках возвращаемые значения обычно не используются). Если вы вызывали функции FreeRTOS (например xQueueSendFromISR()) из обработчика прерываний, то вам необходимо вернуть значение true или false на основе возвращаемого значения аргумента pxHigherPriorityTaskWoken. Если возвращаемое значение pxHigherPriorityTaskWoken любых вызовов FreeRTOS равно pdTRUE, то вы должны вернуть true; в противном случае вернуть false.

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

Затем необходимо подключить её к нашему таймеру с помощью

esp_err_t timer_isr_callback_add(timer_group_t group_num, timer_idx_t timer_num, timer_isr_t isr_handler, void *arg, int intr_alloc_flags) 

где:

  • timer_group_t group_num – номер группы таймеров
  • timer_idx_t timer_num – номер таймера в группе
  • timer_isr_t isr_handler – указатель на функцию обработчик
  • void *arg – указатель на какие-либо данные, которые можно передать в обработчик для идентификации таймера
  • int intr_alloc_flags – просто поставьте 0

После этого необходимо разрешить прерывания:

esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num) 

А если у нас насколько таймеров? Можно использовать два пути:

  • Написать один обработчик для всех таймеров, но передавать в него какие-либо данные через void *arg, которые будут однозначно идентифицировать таймер, с которого поступило прерывание.
  • А можно по простому – написать несколько разных обработчиков и подключить их отдельно.

Управление hardware таймером

Все готово к запуску нашего космического корабля таймера. Делается это совсем просто:

esp_err_t timer_start(timer_group_t group_num, timer_idx_t timer_num) 

Кстати, если Вам по какой-либо причине необходимо временно приостановить таймер, вы можете сделать это с помощью функции timer_pause().

Примеры приложений с hardware таймерами

Официальный пример работы с аппаратными таймерами вы можете посмотреть по ссылке: esp-idf/timer_group_example_main.c В данном примере используется сразу два таймера в двух группах (с разными режимами работы соответственно) – этот пример в полной мере демонстрирует возможности работы с ними.

Но, на мой взгляд, новичку сравнительно непросто будет разобраться в указанном выше примере, поэтому я создал ещё более простой пример всего с одним таймером без всяких “хитростей”: dzen/timer_hardware. В примере всего 1 таймер, настроенный на повтор через каждые 3 секунды. А через каждый 5 секунд работает основной цикл, используя vTaskDelay(). Все предельно просто. Если прошить данный пример в микроконтроллер, по получим следующую картинку:

Как видите, всё работает “как часы”. Так это и есть часы!

В моем примере для просты нет никакого контроля ошибок и возвращаемых значений – сделайте это самостоятельно. Нужна в этом помощь – пишите в комментариях, запилим ещё одну статью.

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

 

Программные таймеры

Аппаратные таймеры – это хорошо, но их только четыре! А в реальном приложении количество требуемых таймеров может легко исчисляться десятками. Для решения этой проблемы в Espressif придумали способ решения – программные таймеры, привязанные к одному из аппаратных таймеров.

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

  • Максимальное разрешение (то есть минимальный интервал таймера) равно периоду тика FreeRTOS.
  • Обратные вызовы таймера отправляются из задачи с низким приоритетом

Аппаратные таймеры свободны от обоих ограничений, но зачастую они менее удобны в использовании. Например, компонентам приложения может потребоваться запуск событий таймера в определенное время в будущем, но аппаратный таймер содержит только одно значение «сравнения», используемое для генерации прерывания. Это означает, что поверх аппаратного таймера необходимо создать какое-то средство для управления списком ожидающих событий, которое может отправлять обратные вызовы для этих событий по мере возникновения соответствующих аппаратных прерываний. Внутри все программные таймеры используют всего один 64-битный аппаратный LAC-таймер.

Для работы с программными таймерами используется немного другая библиотека: #include "esp_timer. h". Общая схема работы с программными таймерами похожа на аппаратные:

  • Создайте функцию – обработчик событий таймера
  • Инициализируйте таймер с помощью функции esp_timer_create()
  • Запустите счетчик таймера с помощью функции esp_timer_start_once() (однократно) или esp_timer_start_periodic() (постоянно)

Как видите, процесс запуска программного таймера немного короче. Да и вообще использование программных таймеров, на мой взгляд, проще, чем аппаратных. Настраивать меньше, а для обработки событий используется обычная функция обратного вызова, а не обработчик прерываний (поэтому можно немного порезвиться). Рассмотрим все эти этапы поподробнее.

Создание функции обратного вызова

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

Создание (инициализация) таймера

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

esp_err_t esp_timer_create(const esp_timer_create_args_t *create_args, esp_timer_handle_t *out_handle) 

где:

  • const esp_timer_create_args_t *create_args – указатель на структуру, содержащую параметры создаваемого таймера
  • esp_timer_handle_t *out_handle – указатель на хендл таймера, который вы сможете потом использовать для управление этим таймером

Рассмотрим esp_timer_create_args_t поподробнее:

  • esp_timer_cb_t callback – функция обратного вызова
  • void* arg – аргументы для передачи в функцию обратного вызова
  • esp_timer_dispatch_t dispatch_method – метод обработки таймаута: из задачи или через прерывание
  • const char* name – имя таймера, используется только для отладки
  • bool skip_unhandled_events – пропустить обработку событий, если обработка события таймера по какой-либо причине была пропущена. Обратный вызов таймера будет вызван в любом случае, он не будет потерян. В худшем случае, когда таймер не обрабатывался более одного периода (для периодических таймеров), обратные вызовы будут вызываться один за другим, не дожидаясь установленного периода. Это может быть неприемлемо для некоторых приложений, и для устранения такого поведения была введена опция skip_unhandled_events. Если установлено значение skip_unhandled_events = true, то периодический таймер, который истекал несколько раз, не имея возможности вызвать обратный вызов, по-прежнему будет приводить только к одному событию обратного вызова после того, как только станет возможной обработка.

Я заполнил эту структуру так:

Обязательно проверьте хендл таймера на NULL после вызова esp_timer_create(), чтобы избежать исключения и внеплановой перезагрузки MCU.

Запуск таймера

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

  • Чтобы запустить таймер в однократном режиме, вызовите esp_timer_start_once(esp_timer_handle_t timer, uint64_t timeout_us), передав временной интервал, через который должен быть вызван обратный вызов. При вызове обратного вызова таймер считается остановленным.
  • Чтобы запустить таймер в периодическом режиме, вызовите esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period), передав период, с которым должен быть вызван обратный вызов. Таймер продолжает работать до тех пор , пока не будет вызван esp_timer_stop().

Обратите внимание, что таймер не должен работать, когда вызывается esp_timer_start_once() или esp_timer_start_periodic(). Чтобы перезапустить работающий таймер, сначала остановите его, а только затем вызовите одну из функций запуска.

В итоге весь процесс запуска таймера будет выглядеть как-то так:

Как видите, всё довольно просто.

Результаты работы примера

Пример для работы с программными таймерами вы найдете на GitHub по ссылке: dzen/timer_software

Таймер общего назначения — ESP32

[中文]

Введение

Микросхема ESP32 содержит две группы аппаратных таймеров. Каждая группа имеет два аппаратных таймера общего назначения. Все они являются 64-битными универсальными таймерами, основанными на 16-битных предварительных масштабаторах и 64-битных счетчиках увеличения/уменьшения, которые могут перезагружаться автоматически.

Функциональный обзор

В следующих разделах этого документа описаны типичные шаги по настройке и работе с таймером:

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

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

  • Сигналы тревоги — показывает, как устанавливать и использовать сигналы тревоги.

  • Прерывания — объясняет, как использовать обратные вызовы прерывания.

Инициализация таймера

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

Прежде всего, таймер следует инициализировать, вызвав функцию timer_init() и передав ей структуру timer_config_t , чтобы определить, как должен работать таймер. В частности, могут быть установлены следующие параметры таймера:

  • Источник тактового сигнала : Выберите источник тактового сигнала, который вместе с делителем определяют разрешение рабочего таймера. По умолчанию источником синхронизации является APB_CLK (обычно 80 МГц).

  • Делитель : Устанавливает скорость «тикания» счетчика таймера. Параметр делитель используется как делитель источника тактового сигнала.

  • Режим : Устанавливает, должен ли счетчик увеличиваться или уменьшаться. Его можно определить с помощью counter_dir , выбрав одно из значений из timer_count_dir_t .

  • Включение счетчика : Если счетчик включен, он начнет увеличиваться/уменьшаться сразу после вызова timer_init() . Вы можете изменить поведение с помощью counter_en , выбрав одно из значений из timer_start_t .

  • Включение тревоги : Можно установить с помощью alarm_en .

  • Автоматическая перезагрузка : Устанавливает, должен ли счетчик auto_reload начальное значение счетчика сигнала тревоги таймера или продолжить увеличение или уменьшение.

Чтобы получить текущие значения настроек таймера, используйте функцию timer_get_config() .

Управление таймером

После включения таймера начинает работать его счетчик. Чтобы включить таймер, вызовите функцию timer_init() с counter_en , установленную на true , или вызовите timer_start() . Вы можете указать начальное значение счетчика таймера, вызвав timer_set_counter_value() . Чтобы проверить текущее значение таймера, вызовите timer_get_counter_value() или timer_get_counter_time_sec() .

Чтобы приостановить таймер в любое время, вызовите timer_pause() . Чтобы возобновить его, вызовите timer_start() .

Чтобы перенастроить таймер, вы можете вызвать timer_init() . Эта функция описана в разделе Инициализация таймера.

Вы также можете перенастроить таймер, используя специальные функции для изменения индивидуальных настроек:

Настройка

Специальная функция

Описание

Разделитель

timer_set_divider()

Изменить скорость тиканья. Во избежание непредсказуемых результатов таймер следует ставить на паузу при смене делителя. Если таймер работает, timer_set_divider() приостанавливает его, изменяет настройку и снова запускает таймер.

Режим

timer_set_counter_mode()

Установить, должен ли счетчик увеличиваться или уменьшаться

Автоматическая перезагрузка

timer_set_auto_reload()

Установите, следует ли перезагружать начальное значение счетчика при тревоге таймера

Тревоги

Чтобы установить будильник, вызовите функцию timer_set_alarm_value() , а затем включите будильник с помощью timer_set_alarm() . Тревогу также можно включить на этапе инициализации таймера, когда вызывается timer_init() .

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

  • Будет запущено прерывание, если оно было настроено ранее. См. Раздел «Прерывания» о том, как настроить прерывания.

  • Когда auto_reload включен, счетчик таймера будет автоматически перезагружен, чтобы снова начать отсчет с ранее настроенного значения. Это значение должно быть установлено заранее с помощью timer_set_counter_value() .

Примечание

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

  • После срабатывания сигнал тревоги автоматически отключается, и его необходимо повторно включить для повторного срабатывания.

Чтобы проверить указанное значение тревоги, вызовите timer_get_alarm_value() .

Прерывания

Регистрация обратного вызова прерывания для определенного таймера может быть выполнена вызовом timer_isr_callback_add() и передачей идентификатора группы, идентификатора таймера, обработчика обратного вызова и пользовательских данных. Обработчик обратного вызова будет вызываться в контексте ISR, поэтому пользователь не должен помещать какой-либо блокирующий API в функцию обратного вызова.
Преимущество использования обратного вызова прерывания вместо предварительной обработки прерывания с нуля заключается в том, что вам не нужно иметь дело с проверкой состояния прерывания и очисткой, все они решаются до того, как обратный вызов будет запущен в обработчике прерывания драйвера по умолчанию.

Для получения дополнительной информации об использовании прерываний см. приведенный ниже пример приложения.

Пример приложения

Пример 64-битного аппаратного таймера: периферия/timer_group.

Справочник по API

Функции

esp_err_t timer_get_counter_value (timer_group_t group_num , timer_idx_t timer_num , uint64_t * timer_val )

Считать значение счетчика аппаратного таймера.

Возврат
Параметры
  • group_num : Группа таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

  • timer_val : Указатель для приема значения счетчика таймера.

esp_err_t timer_get_counter_time_sec (timer_group_t group_num , timer_idx_t timer_num , double * время )

Чтение значения счетчика аппаратного таймера в единицах заданной шкалы.

Возврат
Параметры
  • group_num : Группа таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

  • time : Указатель, тип double*, для приема значения счетчика таймера в секундах.

esp_err_t timer_set_counter_value (timer_group_t group_num , timer_idx_t timer_num , uint64_t load_val )

Установить значение счетчика на аппаратный таймер.

Возврат
Параметры
  • group_num : Группа таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

  • load_val : Значение счетчика для записи в аппаратный таймер.

esp_err_t timer_start (timer_group_t group_num , timer_idx_t timer_num )

Запуск счетчика аппаратного таймера.

Возврат
Параметры
  • group_num : Номер группы таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

esp_err_t timer_pause (timer_group_t group_num , timer_idx_t timer_num )

Приостановить счетчик аппаратного таймера.

Возврат
Параметры
  • group_num : Номер группы таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

esp_err_t timer_set_counter_mode (timer_group_t group_num , timer_idx_t timer_num , timer_count_dir_t counter_dir )

Установка режима счета для аппаратного таймера.

Возврат
Параметры
  • group_num : Номер группы таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

  • counter_dir : Направление счета таймера, прямой или обратный отсчет

esp_err_t timer_set_auto_reload (timer_group_t group_num , timer_idx_t timer_num , timer_autoreload_t reload )

Включение или отключение функции перезагрузки счетчика при возникновении аварийного события.

Возврат
Параметры
  • group_num : Номер группы таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

  • перезагрузка : Режим перезагрузки счетчика.

esp_err_t timer_set_divider (timer_group_t group_num , timer_idx_t timer_num , uint32_t делитель )

Установка делителя частоты источника аппаратного таймера. Часы групп таймеров являются делителем часов APB.

Возврат
Параметры
  • group_num : Номер группы таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

  • делитель : Значение делителя часов таймера. Диапазон делителя от 2 до 65536.

esp_err_t timer_set_alarm_value (timer_group_t group_num , timer_idx_t timer_num , uint64_t alarm_value )

Установка значения сигнала тревоги таймера.

Возврат
Параметры
  • group_num : Группа таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

  • alarm_value : 64-битное значение для установки значения аварийного сигнала.

esp_err_t timer_get_alarm_value (timer_group_t group_num , timer_idx_t timer_num , uint64_t * alarm_value )

Получить значение сигнала таймера.

Возврат
Параметры
  • group_num : Группа таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

  • alarm_value : Указатель 64-битного значения для принятия значения аварийного сигнала.

esp_err_t timer_set_alarm (timer_group_t group_num , timer_idx_t timer_num , timer_alarm_t alarm_en )

Включить или отключить генерацию тревожных событий таймера.

Возврат
Параметры
  • group_num : Группа таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

  • alarm_en : Включение или отключение функции будильника по таймеру.

esp_err_t timer_isr_callback_add (timer_group_t group_num , timer_idx_t timer_num , timer_isr_t isr_handler , void * arg , int intr_alloc_flags )

Добавить обратный вызов дескриптора ISR для соответствующего таймера.

Обратный вызов должен возвращать логическое значение, чтобы определить, нужно ли выполнять YIELD в конце ISR.

Примечание

Этот обработчик ISR будет вызываться из ISR. Этот обработчик ISR не должен обрабатывать статус прерывания и должен быть коротким. Если вы хотите реализовать некоторые конкретные приложения или написать весь ISR, вы можете вызвать timer_isr_register(…) для регистрации ISR.

Параметры
  • group_num : Номер группы таймеров

  • timer_num : Индекс таймера группы таймеров

  • isr_handler : Функция обработчика прерываний, это функция обратного вызова.

  • arg : Параметр для функции обработчика

  • intr_alloc_flags : Флаги, используемые для выделения прерывания. Одно или несколько (ORred) значений ESP_INTR_FLAG_*. См. esp_intr_alloc. h для получения дополнительной информации.

Если установлено значение ESP_INTR_FLAG_IRAM для intr_alloc_flags, функция-обработчик должна быть объявлена ​​с атрибутом IRAM_ATTR и может вызывать функции только в IRAM или ROM. Он не может вызывать другие API-интерфейсы таймера.

Возврат
esp_err_t timer_isr_callback_remove (timer_group_t group_num , timer_idx_t timer_num )

Удалить обратный вызов дескриптора ISR для соответствующего таймера.

Возврат
Параметры
esp_err_t timer_isr_register (timer_group_t group_num , timer_idx_t timer_num , void (* fn )(void *), void * arg , int intr_alloc_flags , timer_isr_handle_t * handle , )

Регистр Обработчик прерывания таймера, обработчик является ISR. Обработчик будет прикреплен к тому же ядру ЦП, на котором выполняется эта функция.

Если для intr_alloc_flags установлено значение ESP_INTR_FLAG_IRAM, функция-обработчик должна быть объявлена ​​с атрибутом IRAM_ATTR и может вызывать функции только в IRAM или ROM. Он не может вызывать другие API-интерфейсы таймера. В этом случае используйте прямой доступ к регистру для настройки таймеров изнутри ISR.

Примечание

Если использовать эту функцию для регистрации ISR, вам необходимо записать весь ISR. В обработчике прерывания вам нужно вызвать timer_spinlock_take(..) перед обработкой и вызвать timer_spinlock_give(…) после обработки.

Параметры
  • group_num : Номер группы таймеров

  • timer_num : Индекс таймера группы таймеров

  • fn : Функция обработчика прерываний.

  • arg : Параметр для функции обработчика

  • intr_alloc_flags : Флаги, используемые для выделения прерывания. Одно или несколько (ORred) значений ESP_INTR_FLAG_*. См. esp_intr_alloc.h для получения дополнительной информации.

  • дескриптор : Указатель на дескриптор возврата. Если не NULL, здесь будет возвращен дескриптор прерывания.

Возврат
esp_err_t timer_init (timer_group_t group_num , timer_idx_t timer_num , const timer_config_t * config )

Инициализирует и настраивает таймер.

Возврат
Параметры
  • group_num : Номер группы таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

  • config : Указатель на параметры инициализации таймера.

esp_err_t timer_deinit (timer_group_t group_num , timer_idx_t timer_num )

Деинициализирует таймер.

Возврат
Параметры
  • group_num : Номер группы таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

esp_err_t timer_get_config (timer_group_t group_num , timer_idx_t timer_num , timer_config_t * config )

Получить значение настройки таймера.

Возврат
Параметры
  • group_num : Номер группы таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера, 0 для hw_timer[0] и 1 для hw_timer[1]

  • config : Указатель структуры для приема параметров таймера.

esp_err_t timer_group_intr_enable (timer_group_t group_num , timer_intr_t intr_mask )

Разрешение группового прерывания таймера по маске включения.

Возврат
Параметры
  • group_num : Номер группы таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • intr_mask : Маска разрешения прерывания таймера.

    • TIMER_INTR_T0: прерывание t0

    • TIMER_INTR_T1: прерывание t1

    • TIMER_INTR_WDT: прерывание сторожевого таймера

esp_err_t timer_group_intr_disable (timer_group_t group_num , timer_intr_t intr_mask )

Отключить групповое прерывание таймера по маске отключения.

Возврат
Параметры
  • group_num : Номер группы таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • intr_mask : Маска отключения прерывания таймера.

    • TIMER_INTR_T0: прерывание t0

    • TIMER_INTR_T1: прерывание t1

    • TIMER_INTR_WDT: прерывание сторожевого таймера

esp_err_t timer_enable_intr (timer_group_t group_num , timer_idx_t timer_num )

Разрешить прерывание по таймеру.

Возврат
Параметры
esp_err_t timer_disable_intr (timer_group_t group_num , timer_idx_t timer_num )

Отключить прерывание таймера.

Возврат
Параметры
void timer_group_intr_clr_in_isr (timer_group_t group_num , timer_idx_t timer_num )

Очистить состояние прерывания таймера, только что использованное в ISR.

Параметры
недействительным timer_group_clr_intr_status_in_isr (timer_group_t group_num , timer_idx_t timer_num )

Очистить состояние прерывания таймера, только что использованное в ISR.

Параметры
void timer_group_enable_alarm_in_isr (timer_group_t group_num , timer_idx_t timer_num )

Разрешить прерывание по тревоге, только что использованное в ISR.

Параметры
uint64_t timer_group_get_counter_value_in_isr (timer_group_t group_num , timer_idx_t timer_num )

Получить текущее значение счетчика, только что использованное в ISR.

Возврат
  • Значение счетчика

Параметры
недействительным timer_group_set_alarm_value_in_isr (timer_group_t group_num , timer_idx_t timer_num , uint64_t alarm_val )

Установите порог срабатывания сигнализации для таймера, только что использованного в ISR.

Параметры
  • group_num : Номер группы таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера.

  • alarm_val : Порог срабатывания сигнализации.

void timer_group_set_counter_enable_in_isr (timer_group_t group_num , timer_idx_t timer_num , timer_start_t counter_en )

Включить/отключить счетчик, только что использованный в ISR.

Параметры
  • group_num : Номер группы таймеров, 0 для TIMERG0 или 1 для TIMERG1

  • timer_num : Индекс таймера.

  • counter_en : Включить/выключить.

timer_intr_t timer_group_intr_get_in_isr (timer_group_t group_num )

Получить статус замаскированного прерывания, только что использованного в ISR.

Возврат
  • Статус прерывания

Параметры
uint32_t timer_group_get_intr_status_in_isr (timer_group_t group_num )

Получить статус прерывания, только что использованный в ISR.

Возврат
  • Статус прерывания

Параметры
void timer_group_clr_intr_sta_in_isr (timer_group_t group_num , timer_intr_t intr_mask )

Очистить состояние замаскированного прерывания, только что использованного в ISR.

Параметры
bool timer_group_get_auto_reload_in_isr (timer_group_t group_num , timer_idx_t timer_num )

Получить статус включения автоматической перезагрузки, только что использованный в ISR.

Возврат
Параметры
esp_err_t timer_spinlock_take (timer_group_t group_num )

Включите спин-блокировку таймера, чтобы войти в критическую защиту.

Возврат
Параметры
esp_err_t timer_spinlock_give (timer_group_t group_num )

Установите блокировку таймера для выхода из критической защиты.

Возврат
Параметры

Макросы

ТАЙМЕР_BASE_CLK

Частота часов на входе групп таймеров

Определения типов

typedef bool (* timer_isr_t )(void *)

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

Возврат
Примечание

Если вы вызвали функции FreeRTOS в обратном вызове, вам необходимо вернуть значение true или false в зависимости от возвращаемого значения аргумента pxHigherPriorityTaskWoken . Например, xQueueSendFromISR вызывается в обратном вызове, если возвращаемое значение pxHigherPriorityTaskWoken любого вызова FreeRTOS равно pdTRUE, возвращается true; в противном случае вернуть ложь.

определение типа intr_handle_t timer_isr_handle_t

Дескриптор прерывания, используемый для освобождения isr после использования. Псевдонимы для дескриптора int на данный момент.

Заголовочный файл

  • hal/include/hal/timer_types.h

Конструкции

структура timer_config_t

Структура данных с настройками конфигурации таймера.

Публичные члены

timer_alarm_t alarm_en

Включение тревоги по таймеру

timer_start_t counter_en

Включение счетчика

timer_intr_mode_t intr_type

Режим прерывания

timer_count_dir_t counter_dir

Встречное направление

timer_autoreload_t авто_перезагрузка

Автоматическая перезагрузка таймера

uint32_t делитель

Делитель счетчика часов. Диапазон делителя от 2 до 65536.

Списки

перечисление timer_group_t

Выбирает группу таймеров из 2 доступных групп.

Значения:

ТАЙМЕР_ГРУППА_0 = 0

Группа аппаратных таймеров 0

ТАЙМЕР_ГРУППА_1 = 1

Группа аппаратного таймера 1

ТАЙМЕР_ГРУППА_МАКС
перечисление timer_idx_t

Выберите аппаратный таймер из групп таймеров.

Значения:

ТАЙМЕР_0 = 0

Выберите таймер 0 из GROUPx

ТАЙМЕР_1 = 1

Выберите таймер 1 из GROUPx

ТАЙМЕР_МАКС
перечисление timer_count_dir_t

Определяет направление счетчика.

Значения:

TIMER_COUNT_DOWN = 0

Счет по убыванию от cnt.high|cnt.low

TIMER_COUNT_UP = 1

Счет по возрастанию от нуля

TIMER_COUNT_MAX
перечисление timer_start_t

Определяет, включен таймер или приостановлен.

Значения:

ТАЙМЕР_ПАУЗА = 0

Счетчик таймера паузы

ТАЙМЕР_СТАРТ = 1

Счетчик пускового таймера

перечисление timer_intr_t

Типы прерываний таймера.

Значения:

ТАЙМЕР_INTR_T0 = БИТ(0)

прерывание таймера 0

ТАЙМЕР_INTR_T1 = БИТ(1)

прерывание таймера 1

TIMER_INTR_WDT = БИТ(2)

прерывание сторожевого таймера

ТАЙМЕР_ИНТР_НЕТ = 0
перечисление timer_alarm_t

Определяет, включать ли режим тревоги.

Значения:

ТАЙМЕР_ALARM_DIS = 0

Отключить тревогу таймера

ТАЙМЕР_АВАРИЙНЫЙ СИГНАЛ_EN = 1

Включить тревогу таймера

ТАЙМЕР_ALARM_МАКС
перечисление timer_intr_mode_t

Выберите тип прерывания при работе в режиме тревоги.

Значения:

ТАЙМЕР_INTR_LEVEL = 0

Режим прерывания: режим уровня

ТАЙМЕР_ИНТР_МАКС
перечисление timer_autoreload_t

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

Значения:

ТАЙМЕР_АВТОЗАГРУЗКА_DIS = 0

Отключить автоматическую перезагрузку: аппаратное обеспечение не будет загружать значение счетчика после аварийного события

ТАЙМЕР_АВТОЗАГРУЗКА_EN = 1

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

ТАЙМЕР_АВТОЗАГРУЗКА_МАКС

ESP32TimerInterrupt — библиотеки Arduino

Эта библиотека позволяет использовать прерывания от аппаратных таймеров на платах на основе ESP32 (включая ESP32_S2, ESP32_S3 и ESP32_C3)

Автор
Кой Хоанг
Веб-сайт
https://github. com/khoih-prog/ESP32TimerInterrupt
Категория
Контроль устройств
Лицензия
MIT
Тип библиотеки
Добавлено
Архитектуры
esp32

Эти аппаратные таймеры ESP32, использующие прерывание, продолжают работать, даже если другие функции блокируются. Более того, они намного более точны (конечно, в зависимости от точности тактовой частоты), чем другие программные таймеры, использующие millis() или micros(). Это обязательно, если вам нужно измерить некоторые данные, требующие большей точности. Теперь он поддерживает 16 таймеров на основе ISR, потребляя при этом только 1 аппаратный таймер. Интервал таймера очень длинный (ulong миллисекунды). Наиболее важной особенностью является то, что они являются таймерами на основе ISR. Следовательно, их выполнение не блокируется функциями или задачами с плохим поведением. Эта важная функция абсолютно необходима для критически важных задач.

Имя файла Дата выпуска Размер файла
ESP32TimerInterrupt-2. 3.0.zip 2022-11-16 69,74 КиБ
ESP32TimerInterrupt-2.2.0.zip 2022-08-12 67,33 КиБ
ESP32TimerInterrupt-2.1.0.zip 2022-08-11 66,39 КиБ
ESP32TimerInterrupt-2.0.2.zip 2022-06-16 65,95 КиБ
ESP32TimerInterrupt-2.0.1.zip 2022-03-14 65,67 КиБ
ESP32TimerInterrupt-2.0.0.zip 2022-02-13 58,28 КиБ
ESP32TimerInterrupt-1.5.0.zip 2022-01-19 85,30 КиБ
ESP32TimerInterrupt-1.4.1.zip 2021-11-14 117,86 КиБ
ESP32TimerInterrupt-1.

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

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