Использование таймеров и прерываний от них в модуле ESP32


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

Внешний вид проекта использования таймеров в модуле ESP32

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

Таймеры в модуле ESP32

Также на нашем сайте мы рассматривали использование таймеров в других микроконтроллерах (платах):

Прерывания от таймеров

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

Принцип формирования прерываний от таймеров

Таймеры являются аппаратно-зависимыми, а скорость их счета (скорость таймера) можно определить по следующей формуле:

К примеру, если мы в модуле ESP32, работающим на тактовой частоте 80MHz, установим коэффициент деления предделителя (prescaler value) равный 1, то мы получим скорость счета таймера равную 80MHz, а если мы установим коэффициент деления предделителя равный 80, то мы получим скорость счета таймера равную 1MHz или 1000000Hz.

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

Процесс обработки прерывания от таймера по отношению к исполнению основной программы

Также, как и в случае с аппаратными прерываниями, прерывания от таймеров являются самым лучшим способом запуска не блокируемых ничем функций через заданные интервалы времени. Для этого в функции setup программы мы настраиваем и прикрепляем прерывание от конкретного таймера к определенной функции обработки прерывания (ISR). Далее микроконтроллер будет последовательно исполнять команды в основной функции программы main. И при срабатывании прерывания от таймера микроконтроллер будет останавливать выполнение основной программы и начинать выполнение функции обработки прерывания (Interrupt Service Routine, ISR). После того как микроконтроллер завершит выполнение функции ISR, он продолжит выполнение основной программы с того места, на котором ее выполнение прервало прерывание. Данные процессы будут происходить при каждом срабатывании прерывания от таймера.

Более подробно об использовании прерываний в модуле ESP32 вы можете прочитать в этой статье.

Наиболее часто задаваемые вопросы про прерывания от таймеров в ESP32

Как много таймеров содержит модуль ESP32?
Он содержит четыре 64-битных таймера.

Как использовать прерывания от таймеров в модуле ESP32?
Необходимо прикрепить конкретный таймер к прерыванию и назначить ему функцию обработки (ISR).

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

Схема проекта

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

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

Внешний вид собранной на макетной плате конструкции проекта показан на следующем рисунке.

Внешний вид собранной на макетной плате конструкции проекта

Объяснение кода программы для модуля ESP32

Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты. В нашем примере светодиод будет мигать с частотой 1 Гц.

Вначале программы дадим осмысленное наименование контакту, к которому подключен светодиод (GPIO21). Затем создадим указатель на переменную с именем My_timer и типом type hw_timer_t для того чтобы в последующем производить настройку таймера.

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

Затем в функции void setup() мы зададим режим работы контакта, к которому подключен светодиод, на вывод данных.

Для инициализации таймера мы будем использовать функцию timerbegin с необходимыми параметрами. Первым из них будет номер таймера, который мы будем использовать (их номера от 0 до 3 поскольку у нас 4 таймера в модуле ESP32). Второй – это коэффициент деления предделителя и последний – это флаг, показывающий должен ли счетчик таймера считать вверх (true) или вниз (false). В нашем проекте мы используем timer 0 с коэффициентом деления предделителя 80 и счетчиком, считающим вверх.

Перед тем как задействовать таймер, мы должны прикрепить (attach) к нему функцию обработки прерывания (ISR), которая будет исполняться при срабатывании прерывания. Делать мы это будем с помощью функции timerAttachInterrupt. В нашем примере мы прикрепим функцию обработки прерывания onTimer к нашему таймеру.

Далее мы будем использовать функцию timerAlarmWrite чтобы загрузить в таймер значение, при достижении которого счетчиком таймера должно срабатывать прерывание от таймера. В нашем примере нам необходимо формировать прерывание каждую секунду, поэтому мы загрузим в таймер значение 1000000 микросекунд, что равно 1 секунде. В качестве третьего параметра функции timerAlarmWrite мы используем значение true, что будет означать что счетчик таймера будет перезагружаться и, таким образом, прерывание будет срабатывать периодически.

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

Исходный код программы

Все необходимые файлы для этого проекта можно скачать по следующей ссылке.

Источник статьи

(2 голосов, оценка: 5,00 из 5)
Загрузка...
6 207 просмотров

Комментарии

Использование таймеров и прерываний от них в модуле ESP32 — 16 комментариев

  1. Здравствуйте. А если мне необходимо измерить заполнение входящего шим сигнала, могу ли я использовать аппаратный таймер? Пробовал на micros, но там погрешность +/- 1 микросекунда и при частоте 3000гц уже плавает значение. Спасибо

    • Добрый вечер. Честно говоря, не пробовал подобное. Но таймеры у модуля 64 битные, что позволяет добиться при нужных настройках хорошей точности.

  2. Добрый день. Мигание светодиодом использует 18% памяти устройства. а можно код оптимизировать ???
    и все это записать на языке си

    digitalWrite(LED, !digitalRead(LED));
    pinMode(LED, OUTPUT);

    Благодарю за статью !!

    • Добрый вечер. Конечно, код можно значительно упростить если использовать обычную программу мигания светодиодом, с использованием функции delay(), но целью этой статьи была демонстрация возможностей использования таймера в ESP32, а не написание наиболее эффективной программы мигания светодиодом

      • я имел виду не упростить а вместо вставок языка ардуино использовать си . заменить команды
        digitalWrite(LED, !digitalRead(LED));pinMode(LED, OUTPUT); кодом языка си

        • Да язык ардуино (называется правильно Wiring) это во многом и есть язык Си, он основан на нем. Или вы хотите заменить эти команды на команды языка Си непосредственно для микроконтроллера?

          • Я новичок в этом деле но хотелось бы узнать как заменить команды языка Wiring которые я выше перечислил командами языка си !!

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

  3. Скажите пожалуйста , а вот эти функции
    timerAttachInterrupt
    timerAlarmWrite
    и другие функции работы с таймером - они откуда вообще берутся? Это какая-то стандартная библиотека работы с таймерами или API - или что? Другими словами - откуда компилятор про них "знает" ? Извините, если вопрос покажется глупым...

  4. У вас на схеме подключения светодиода, которая Fridzing, ошибка. Светодиод подключен к RXD0, а в программе фигурирует GPIO21. При этом на фото все правильно.

  5. Спасибо за полезный пример. Пжт, подскажите как выйти из цикла, например, по прошествии определенного времени или по какому-то событию (например, команды из порта).

    • В функции обработчике прерывания от таймера инкрементировать переменную счетчик и при достижении ею определенного значения делать нужное вам действие, а значение переменной сбрасывать в 0. Например, если таймер срабатывает у вас каждую секунду, то чтобы отмерить 100 секунд, необходимо будет сравнивать значение этой переменной со 100.
      А чтобы выйти из цикла когда на необходимом контакте порта появится 0 или 1, то это легко сделать используя цикл while, можно даже проверку этого условия поставить в условие этого цикла

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

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