Ардуино: примеры аппаратного прерывания по таймеру

Вопросы и ответы

Что такое таймер и принцип его работы

Таймер-счетчик — это отдельный модуль внутри микроконтроллера, который состоит из:

  • системы управления (на основе различных регистров);
  • логические элементы;
  • предварительный делитель (устанавливает скорость автомобиля).

Принцип работы модуля прост: он постоянно рассчитывает значения и в нужный момент запускает собственную программу для выполнения поставленной задачи. Программа работает в специальном обработчике. Чтобы попасть в него, вам нужно включить общие прерывания на Arduino (в C команда sei (); позволяет сделать это();).

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

Подключение библиотеки timer-api.h

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

Для этого вам понадобятся:

  1. Скачайте архив с библиотекой.
  2. Откройте среду программирования (например, Arduino).
  3. Щелкните «Эскиз».
  4. Выберите пункт «Библиотека ссылок».
  5. Установите архив с библиотекой.

Библиотека timer-api.h

Чтобы использовать функции этой сборки в своей программе, вам нужно написать строку в начале скетча: #include «timer-api.h».

Рекомендуется устанавливать эту библиотеку в следующих случаях:

  • если вы не хотите загружать код с дополнительными строчками настроек таймера;
  • если специальный режим работы таймера не требуется (например, CTC или PWM), а необходимо только в нужный момент войти в диспетчер подпрограмм микроконтроллера.

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

Видео

Варианты частот для timer_init_ISR_XYHz

Тюнинг автомобиля начинается с определения скорости его работы. Для этого в библиотеке есть функция timer_init_ISR_XYHz. Вместо XY должна быть указана частота вызова подпрограммы обслуживания прерывания (ISR — Interrupt Service Routine).

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

Библиотека позволяет активировать выполнение подпрограммы с частотой до 500 кГц. Также возможна работа с частотой 1 МГц, но многочисленные тесты показали, что получить эффективный результат невозможно.

КГц Гц
500 500
200 200
100 100
50 50
ветры ветры
10 10
5 5
2 2
1 1

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

Таймер Стм

Библиотека GyverTimers

Библиотека GyverTimers позволяет генерировать прерывания таймера с указанной частотой на выбранном канале таймера или на нескольких каналах одновременно со смещением: прерывания будут происходить с одинаковой частотой, но «сдвинуты» относительно друг друга. Вы также можете установить действие для отображения таймера: включить / отключить / переключить: таймер будет управлять выбранным выводом независимо от вычислительного ядра MC, поэтому вы можете генерировать прямоугольный сигнал (прямоугольный сигнал), как за один цикл, так и за два и три раза с регулируемым фазовым сдвигом… Для Arduino Nano / UNO / Pro Mini доступны три таймера: Timer0, Timer1, Timer2. Для Arduino MEGA — пять: Timer0, Timer1, Timer2, Timer3, Timer4, Timer5. В библиотеке таймеры описаны как объекты, доступ осуществляется как обычно через точку. Например Timer1.stop();

Таблица таймеров ATmega328p

Таймер Битовая глубина Частоты Периоды Выходить Штырь Arduino МК брошь
Таймер0 8 бит 61 Гц .. 1 МГц 16 384 .. 1 мкс КАНАЛ_А D6 PD6
КАНАЛ_B D5 PD5
Таймер1 16 бит 0,24 Гц .. 1 МГц 4 200 000 .. 1 мкс КАНАЛ_А D9 PB1
КАНАЛ_B D10 PB2
Таймер2 8 бит 61 Гц .. 1 МГц 16 384 .. 1 мкс КАНАЛ_А D11 PB3
КАНАЛ_B RE3 PD3

Таблица таймеров ATmega2560

Таймер Битовая глубина Частоты Периоды Выходить Штырь Arduino МК брошь
Таймер0 8 бит 61 Гц .. 1 МГц 16 384 .. 1 мкс КАНАЛ_А 13 PB7
КАНАЛ_B 4 PG5
Таймер1 16 бит 0,24 Гц .. 1 МГц 4 200 000 .. 1 мкс КАНАЛ_А одиннадцать PB5
КАНАЛ_B 12 PB6
CHANNEL_C 13 PB7
Таймер2 8 бит 61 Гц .. 1 МГц 16 384 .. 1 мкс КАНАЛ_А 10 PB4
КАНАЛ_B девять PH6
Таймер 3 16 бит 0,24 Гц .. 1 МГц 4 200 000 .. 1 мкс КАНАЛ_А 5 PE3
КАНАЛ_B 2 PE4
CHANNEL_C 3 PE5
Таймер 4 16 бит 0,24 Гц .. 1 МГц 4 200 000 .. 1 мкс КАНАЛ_А 6 PH3
КАНАЛ_B 7 PH4
CHANNEL_C восемь PH5
Таймер 5 16 бит 0,24 Гц .. 1 МГц 4 200 000 .. 1 мкс КАНАЛ_А 46 PL3
КАНАЛ_B 45 PL4
CHANNEL_C 44 год PL5

Максимальный период

В таблице выше показаны диапазоны для тактовой частоты 16 МГц. Для других системных часов максимальный период рассчитывается по формуле, где F_CPU — системная частота в Гц:

  • 8-битный таймер: (1000000UL / F_CPU) * (1024 * 256)
  • 16-битный таймер: (1000000UL / F_CPU) * (1024 * 65536)

Настройка частоты/периода

  • setPeriod (точка); — установка периода в микросекундах и запуск таймера. Возвращает реальный период в мкс (точность ограничена разрешением таймера).
  • setFrequency (частота); — установка частоты в Герцах и запуск таймера. Возвращает фактическую частоту в Гц (точность ограничена разрешением таймера).
  • setFrequencyFloat (переменная частота); — установив частоту в Герцах и запустив таймер, можно использовать десятичные дроби. Возвращает фактическую частоту (точность ограничена разрешением таймера).

Контроль работы таймера

  • пауза (); — приостановить отсчет таймера без сброса счетчика
  • возобновить (); — продолжить счет после перерыва
  • останавливаться (); — остановить счет и сбросить счетчик
  • начать заново (); — перезапустить таймер (сбросить счетчик)

Прерывания

  • enableISR (канал, фаза); — запускать прерывания на выбранном канале с выбранным фазовым сдвигом. Если ничего не указано, будут выбраны канал A и фаза 0
    • Канал — CHANNEL_A, CHANNEL_B или CHANNEL_С (см. Таблицу выше!)
    • Фаза — числовое значение 0-359
  • отключить ISR (канал); — отключить прерывания на выбранном канале. Если ничего не указано, будет выбран канал А

Библиотека обеспечивает прямой доступ к прерыванию без «Arduin» attachInterrupt, что сокращает время, необходимое для вызова функции обработчика прерывания. Прерывание с настроенной частотой будет обрабатываться в блоке вида ISR (канал) {}, например:

Аппаратные выходы

  • outputEnable (канал, режим); — включить управление аппаратным выходом таймера
    • Канал: CHANNEL_A или CHANNEL_B (+ CHANNEL_C для ATmega2560, см. Таблицу таймера).
    • Режим: TOGGLE_PIN, CLEAR_PIN, SET_PIN (включение / отключение / включение вывода при срабатывании таймера)
  • outputDisable (канал); — отключить вывод таймера
    • Канал: CHANNEL_A или CHANNEL_B (+ CHANNEL_C для Mega2560, см. Таблицу таймера)
  • outputState (канал, состояние); — вручную изменить статус канала. Например, чтобы установить каналы в разные состояния, чтобы начать генерировать двухтактный меандр.
    • Канал: CHANNEL_A или CHANNEL_B (+ CHANNEL_C для ATmega2560, см. Таблицу таймера).
    • Статус: ВЫСОКИЙ или НИЗКИЙ

Важно: при генерации меандра реальная частота будет вдвое меньше указанной из-за особенностей самого таймера. См. Примеры с меандром.

Сдвиг фазы (с 1.6)

Используя phaseShift (источник, угол), вы можете сдвигать прерывания или изменять контакты на источнике выбранного канала в зависимости от фазового угла — угла сдвига в градусах от 0 до 360.

  • Для 8-битных таймеров можно установить смещение только для второго канала (CHANNEL_B)
  • 16 бит могут сдвигать все три канала

Настройка по умолчанию

Используя метод setDefault (), вы можете сбросить настройки таймера на значения по умолчанию «Arduin»: частота и режим работы.

Примеры использования attachInterrupt

Перейдем к практике и рассмотрим простейший пример использования прерываний. В этом примере мы определяем функцию-обработчик, которая при изменении сигнала на выводе 2 Arduino Uno будет переключать состояние вывода 13, к которому мы традиционно подключаем светодиод.

Давайте рассмотрим несколько примеров более сложных прерываний и их обработчиков: для таймеров и кнопок.

Прерывания по нажатию кнопки с антидребезгом

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

Вы можете устранить дребезжание, используя функцию millis: она позволяет измерить время, прошедшее с момента первого нажатия кнопки.

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

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

Таймер называется счетчиком, который считает с определенной частотой, полученной от процессора с частотой 16 МГц. Делитель частоты может быть настроен для получения желаемого режима счета. Вы также можете настроить счетчик для генерации прерываний при достижении указанного значения.

Таймер и прерывание по таймеру позволяют выполнять прерывание один раз в миллисекунду. В Arduino есть 3 таймера: Timer0, Timer1 и Timer2. Timer0 используется для генерации прерываний один раз в миллисекунду, а счетчик обновляется и передается в функцию millis (). Этот таймер является восьмибитным и ведет отсчет от 0 до 255. Прерывание генерируется, когда значение достигает 255. По умолчанию, делитель тактовой частоты 65 используется для получения частоты, близкой к 1 кГц.

Регистры сравнения используются для сравнения состояния таймера и сохраненных данных. В этом примере код сгенерирует прерывание, когда счетчик достигнет 0xAF.

Вы хотите определить обработчик прерывания для вектора прерывания таймера. Вектор прерывания — это указатель на адрес позиции инструкции, которая будет выполняться при вызове прерывания. Несколько векторов прерываний объединены в таблицу векторов прерываний. Таймер в этом случае будет называться TIMER0_COMPA_vect. В этом обработчике будут выполняться те же действия, что и loop ().

Модифицированные библиотеки от Paul Stoffregen

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

Pay OWN Timer One Заключение Мы платим таймеру три потенциальных клиента

Подросток 3.1 3, 4 25, 32
Подросток 3.0 3, 4
Подросток 2.0 4, 14, 15 девять
Подросток ++ 2.0 25, 26, 27 14, 15, 16
Ардуино Уно 9, 10
Ардуино Леонардо 9, 10, 11 5
Ардуино Мега 11, 12, 13 2, 3, 5
Электропроводка-S 4, 5
Я кровоточу 12, 13

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

пустое резюме (); Прерванный таймер возобновляет работу. Новый период не начинается.

Деление частоты

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

Алгоритм этого частотного регулирования следующий:

  1. Объявите переменную для учетной записи (например, schet).
  2. Зарегистрируйте команду schet ++ в функции timer_handle_interrupts++.
  3. Как только переменная достигнет желаемого значения, предпримите необходимые действия.

Методы библиотек TimerOne и TimerThree

Настройка

пустая инициализация (длинные микросекунды = 1000000); Вам необходимо сначала вызвать этот метод, прежде чем использовать какие-либо другие методы библиотеки. При желании вы можете установить период таймера (в микросекундах), по умолчанию период установлен на 1 секунду. Обратите внимание, что это нарушает функцию analogWrite () на цифровых выводах 9 и 10 на Arduino .void setPeriod (длинные микросекунды); Установите период в микросекундах.

Минимальный период и максимальная частота, поддерживаемые этой библиотекой, составляют 1 микросекунду и 1 МГц соответственно.Максимальный период составляет 8388480 микросекунд или приблизительно 8,3 секунды. Обратите внимание, что установка периода изменит частоту подключенного выключателя, а также частоту и рабочий цикл на обоих выходах ШИМ.

Управление запуском

void start (); Запустить таймер, начиная новый период void stop (); Остановить таймер void restart (); Перезапускает таймер, сбрасывает счетчик и начинает новый период.

Управление выходным ШИМ сигналом

void pwm (char pin, int duty, long microseconds = -1); Генерирует сигнал ШИМ на указанном выводе. Выходные контакты Timer1 — это контакты PORTB 1 и 2, поэтому вам нужно выбрать один, все остальное игнорируется. На Arduino это цифровые пины 9 и 10, эти псевдонимы тоже работают. Выходные контакты Timer3 — это контакты PORTE, которые соответствуют контактам 2, 3 и 5 Arduino Mega. Рабочий цикл задается 10-битным значением в диапазоне от 0 до 1023 (0 соответствует постоянному логическому нулю на выходе, а 1023 — постоянной логической единице).

Обратите внимание, что при необходимости вы можете установить период в этой функции, добавив значение в микросекундах в качестве последнего аргумента void setPwmDuty (char pin, int duty); Быстрый способ настроить рабочий цикл сигнала ШИМ, если вы уже настроили его, вызвав метод pwm ().

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

Прерывания

void attachInterrupt (void (* isr) (), длинные микросекунды = -1); Вызов функции через указанный интервал в микросекундах. Будьте осторожны при попытке запустить слишком сложный обработчик прерывания на слишком высокой тактовой частоте, поскольку ЦП может никогда не вернуться в основной цикл программы, и программа «зависнет». Обратите внимание, что период также можно установить в этой функции, если необходимо, добавив значение в микросекундах в качестве последнего аргумента void detachInterrupt (); Отключите связанное прерывание.

Остальные

беззнаковое длинное чтение (); Считывает время с момента последнего переполнения в микросекундах.

Timer3

Обратите внимание, что библиотеку Timer1 можно использовать на Arduino Mega, но она не поддерживает все три вывода OCR1A, OCR1B и OCR1C. Поддерживаются только A и B. OCR1A подключается к выводу 11 Mega, а OCR1B подключается к выводу 12. Если один из трех вызовов указывает вывод, 1 установит вывод 11 на Mega, а 2 установит вывод 12 Библиотека Timer3 проверено только на Mega.

Библиотеку таймера Timer3 можно найти здесь (TimerThree.zip)

Чтобы установить его, просто распакуйте и поместите файлы в каталог Arduino / hardware / libraries / Timer3/.

Прерывания в языке Arduino

Теперь давайте перейдем к практике и поговорим о том, как использовать прерывания в ваших проектах.

Синтаксис AttachInterrupt()

Функция attachInterrupt используется для обработки прерываний. Он используется для подключения внешнего прерывания к обработчику.

Синтаксис вызова: attachInterrupt (прерывание, функция, режим)

Аргументы функции:

  • прерывание — номер вызванного прерывания (стандартный 0 — для 2-го пина, для платы Arduino Uno 1 — для 3-го пина),
  • function — имя функции для вызова в случае прерывания (важно — функция не должна принимать или возвращать какое-либо значение),
  • mode — условие срабатывания прерывания.

вы можете установить следующие условия ответа:

  • LOW — выполняется при низком уровне сигнала при нулевом контакте. Прерывание может повторяться циклически, например, при нажатии кнопки.
  • ИЗМЕНЕНИЕ — по фронту происходит прерывание, когда сигнал меняется с высокого на низкий или наоборот. Выполняется один раз при каждой смене сигнала.
  • RISING — однократное выполнение прерывания при изменении сигнала с LOW на HIGH.
  • ПАДЕНИЕ — однократное прерывание при изменении сигнала с ВЫСОКИЙ на НИЗКИЙ

Важные замечания

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

  • Функция менеджера не должна занимать слишком много времени. Дело в том, что Arduino не может обрабатывать несколько прерываний одновременно. При выполнении функции обработчика все другие прерывания будут игнорироваться, и вы можете пропустить важные события. Если вам нужно сделать что-то масштабное, просто передайте обработку событий в основной цикл (). В обработчике вы можете установить только флаг события, а в цикле вы можете проверить флаг и обработать его.
  • Вы должны быть очень осторожны с переменными. Интеллектуальный компилятор C ++ может «повторно оптимизировать» вашу программу — удалить переменные, которые, по его мнению, не нужны. Компилятор просто не увидит, что вы устанавливаете какие-то переменные в одной части, а используете в другой. Чтобы исключить эту возможность в случае базовых типов данных, вы можете использовать ключевое слово volatile, например: volatile boolean state = 0. Но этот метод не будет работать со сложными структурами данных. Так что вы всегда должны быть начеку.
  • Не рекомендуется использовать большое количество прерываний (старайтесь не использовать больше 6-8). Большое количество различных событий требует серьезного усложнения кода и, следовательно, приводит к ошибкам. Также нужно понимать, что в системах с большим количеством прерываний речи не идет — вы никогда не поймете, какой именно интервал между вызовами важных для вас команд.
  • Delay () нельзя использовать в обработчиках. Механизм определения интервала задержки использует таймеры, а также они работают с прерываниями, которые блокирует обработчик. В итоге все будут ждать всех и программа вылетит. По той же причине нельзя использовать протоколы связи на основе прерываний (например, i2c).

Произвольное значение частоты таймера

Библиотека позволяет активировать таймер с произвольной частотой.

Для этого вызовите функцию timer_init_ISR (1-й указатель, 2-й указатель, 3-й указатель), где:

  • 1-й индикатор — требуется ТС;
  • 2-й указатель — предделитель;
  • 3-й указатель — значение регистра счета.

Вместо первого указателя можно написать:

  1. TIMER_DEFAULT — указатель таймера задания по умолчанию.
  2. _TIMER1 или _TIMER1_8BIT — указатель на желаемый таймер.

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

Опции ПО УМОЛЧАНИЮ

Значение регистра счета указывается в формате 40000-1. Вычитание единицы в этом случае необходимо с учетом того, что учетная запись ведется с нуля.

Запуск и остановка таймера в динамике

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

Пуск и остановка

Особенности установки библиотеки

Есть быстрый способ загрузить библиотеку в программу, но он требует глубокого понимания операционных систем.

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

cd ~ / * папка установки среды программирования * / * папка с библиотеками * / git clone * ссылка на библиотеку со стороннего сайта*

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

После использования любого метода установки библиотеки в разделе «Файл», в записи «Примеры» появится шаблон с использованием его команд. На этом скетче показано, как работают встроенные функции. Также можно брать из него готовые части кода, чтобы не писать их самостоятельно, а программировать быстрее.

Читайте также: Распиновка Ардуино Про Мини: схема для программирования

Оцените статью
Блог про Arduino