Что такое аппаратные прерывания в Arduino. Как работают прерывания на платах Arduino Uno, Mega, Nano. Каковы особенности использования функции attachInterrupt(). Какие есть типы аппаратных прерываний в Arduino. Как реализовать обработку прерываний от кнопки и таймера.
Что такое аппаратные прерывания в Arduino
Аппаратные прерывания — это механизм, позволяющий микроконтроллеру Arduino реагировать на внешние события асинхронно, не затрагивая основной цикл программы. Прерывания позволяют обрабатывать важные события сразу при их возникновении, не тратя ресурсы на постоянный опрос.
Основные особенности аппаратных прерываний в Arduino:
- Возникают при изменении сигнала на определенных пинах платы
- Вызывают выполнение специальной функции-обработчика
- Приостанавливают выполнение основной программы на время обработки
- Позволяют реагировать на события без задержек
- Экономят ресурсы процессора по сравнению с постоянным опросом
Типы аппаратных прерываний в Arduino
В Arduino существует 4 основных типа аппаратных прерываний:
![](/800/600/https/ocw.cs.pub.ro/courses/_media/pm/prj2021/avaduva/proiect_pm_bloc_3.png)
- LOW — срабатывает, когда на пине низкий уровень сигнала
- CHANGE — срабатывает при любом изменении сигнала
- RISING — срабатывает при изменении сигнала с низкого на высокий
- FALLING — срабатывает при изменении сигнала с высокого на низкий
Выбор типа прерывания зависит от конкретной задачи и подключенного устройства. Например, для кнопки часто используют FALLING, а для энкодера — CHANGE.
Реализация прерываний на разных платах Arduino
Количество и расположение пинов для прерываний отличается на разных платах Arduino:
- Arduino Uno — 2 прерывания (пины 2 и 3)
- Arduino Mega — 6 прерываний (пины 2, 3, 18, 19, 20, 21)
- Arduino Nano — 2 прерывания (пины 2 и 3)
- Arduino Due — прерывания на всех цифровых пинах
На платах с малым количеством прерываний можно использовать режим Pin Change Interrupt для получения прерываний с любого пина, но это сложнее в реализации.
Использование функции attachInterrupt()
Для настройки прерываний в Arduino используется функция attachInterrupt(). Ее синтаксис:
![](/800/600/https/i.ytimg.com/vi/5xVY8OeRTss/maxresdefault.jpg)
attachInterrupt(interrupt, function, mode);
Где:
- interrupt — номер прерывания
- function — функция-обработчик прерывания
- mode — режим срабатывания (LOW, CHANGE, RISING, FALLING)
Важные особенности при использовании attachInterrupt():
- Функция-обработчик должна быть без параметров и возвращаемого значения
- В обработчике нельзя использовать delay() и другие блокирующие функции
- Обработчик должен быть максимально коротким
- Переменные, изменяемые в обработчике, нужно объявлять как volatile
Пример обработки прерывания от кнопки
Рассмотрим простой пример использования прерывания для обработки нажатия кнопки:
В этом примере:
![](/800/600/https/i.ytimg.com/vi/BPnNQwr18yg/maxresdefault.jpg)
- Прерывание настроено на пин 2 по спаду сигнала (FALLING)
- При нажатии кнопки вызывается обработчик buttonInterrupt()
- Обработчик просто устанавливает флаг buttonPressed
- Основной цикл проверяет флаг и при необходимости включает светодиод
Прерывания по таймеру в Arduino
Помимо внешних прерываний, в Arduino можно использовать прерывания по таймеру. Они позволяют выполнять действия через заданные промежутки времени.
Пример использования прерывания по таймеру:
«`cpp #includeВ этом примере:
- Используется библиотека TimerOne для настройки прерывания
- Прерывание настроено на срабатывание каждую секунду
- В обработчике происходит переключение состояния светодиода
Преимущества и недостатки использования прерываний
Преимущества использования прерываний в Arduino:
![](/800/600/https/cdn-learn.adafruit.com/assets/assets/000/021/334/original/components_interrupt.png)
- Мгновенная реакция на события
- Экономия ресурсов процессора
- Возможность обработки коротких импульсов
- Упрощение кода для некоторых задач
Недостатки и ограничения прерываний:
- Усложнение структуры программы
- Необходимость учитывать возможные конфликты между прерываниями
- Ограничения на код внутри обработчиков прерываний
- Возможные проблемы с дребезгом контактов
При разработке проекта на Arduino необходимо взвесить все за и против, чтобы решить, стоит ли использовать прерывания или можно обойтись простым опросом в основном цикле.
Заключение
Аппаратные прерывания — мощный инструмент в арсенале разработчика Arduino. Они позволяют создавать более эффективные и отзывчивые устройства. Однако использование прерываний требует глубокого понимания их работы и учета возможных подводных камней.
При правильном применении прерывания помогают решать такие задачи, как:
- Обработка сигналов от датчиков
- Точное измерение временных интервалов
- Реализация протоколов связи
- Управление двигателями и сервоприводами
- Создание многозадачных систем
Освоение техники работы с прерываниями открывает новые возможности в создании проектов на базе Arduino и позволяет разрабатывать более сложные и функциональные устройства.
![](/800/600/https/content.instructables.com/ORIG/F10/6XCF/JGSGFX7J/F106XCFJGSGFX7J.jpg)
Arduino прерывания по кнопке
- Уроки
- Базовые уроки Arduino
- Аппаратные прерывания
Аппаратные прерывания
Забавную картинку к этому уроку я найти не смог, нашёл только какую-то лекцию по программированию, и вот самое начало этой лекции отлично объясняет нам, что такое прерывание. Прерывание в Ардуино можно описать абсолютно точно так же: микроконтроллер “всё бросает”, переключается на выполнение блока функций в обработчике прерывания, выполняет их, а затем возвращается ровно к тому месту основного кода, в котором остановился.
Прерывания бывают разные, то есть не сами прерывания, а их причины: прерывание может вызвать аналогово-цифровой преобразователь, таймер-счётчик или буквально пин микроконтроллера. Такие прерывания называются внешними аппаратными, и именно о них мы сегодня поговорим.
External hardware interrupt – это прерывание, вызванное изменением напряжения на пине микроконтроллера. Основная суть состоит в том, что микроконтроллер (вычислительное ядро) не занимается опросом пина и не тратит на это время, пином занимается другая “железка”. Как только напряжение на пине изменяется (имеется в виду цифровой сигнал, +5 подали/+5 убрали) – микроконтроллер получает сигнал, бросает все дела, обрабатывает прерывание, и возвращается к работе. Зачем это нужно? Чаще всего прерывания используются для детектирования коротких событий – импульсов, или даже для подсчёта их количества, не нагружая основной код. Аппаратное прерывание может поймать короткое нажатие кнопки или срабатывание датчика во время сложных долгих вычислений или задержек в коде, т.е. грубо говоря – пин опрашивается параллельно основному коду. Также прерывания могут будить микроконтроллер из режимов энергосбережения, когда вообще практически вся периферия отключена. Посмотрим, как работать с аппаратными прерываниями в среде Arduino IDE.
Прерывания в Arduino
Начнём с того, что не все пины “могут” в прерывания. Да, есть такая штука, как pinChangeInterrupts, но о ней мы поговорим в продвинутых уроках. Сейчас нужно понять, что аппаратные прерывания могут генерировать только определённые пины:
INT 0 | INT 1 | INT 2 | INT 3 | INT 4 | INT 5 | |
ATmega 328/168 (Nano, UNO, Mini) | D2 | D3 | – | – | – | – |
ATmega 32U4 (Leonardo, Micro) | D3 | D2 | D0 | D1 | D7 | – |
ATmega 2560 (Mega) | D2 | D3 | D21 | D20 | D19 | D18 |
Как вы поняли из таблицы, прерывания имеют свой номер, который отличается от номера пина. Есть кстати удобная функция digitalPinToInterrupt(pin), которая принимает номер пина и возвращает номер прерывания. Скормив этой функции цифру 3 на Ардуино нано, мы получим 1. Всё по таблице выше, функция для ленивых.
Подключается прерывание при помощи функции attachInterrupt(pin, handler, mode):
- pin – номер прерывания
- handler – имя функции-обработчика прерывания (её нужно создать самому)
- mode – “режим” работы прерывания:
- LOW (низкий) – срабатывает при сигнале LOW на пине
- RISING (рост) – срабатывает при изменении сигнала на пине с LOW на HIGH
- FALLING (падение) – срабатывает при изменении сигнала на пине с HIGH на LOW
- CHANGE (изменение) – срабатывает при изменении сигнала (с LOW на HIGH и наоборот)
Также прерывание можно отключить при помощи функции detachInterrupt(pin), где pin – опять же номер прерывания.
А ещё можно глобально запретить прерывания функцией noInterrupts() и снова разрешить их при помощи interrupts(). Аккуратнее с ними! noInterrupts() остановит также прерывания таймеров, и у вас “сломаются” все функции времени и генерация ШИМ.
Давайте рассмотрим пример, в котором в прерывании считаются нажатия кнопки, а в основном цикле они выводятся с задержкой в 1 секунду. Работая с кнопкой в обычном режиме, совместить такой грубый вывод с задержкой – невозможно:
Итак, наш код считает нажатия даже во время задержки! Здорово. Но что такое volatile? Мы объявили глобальную переменную counter, которая будет хранить количество нажатий на кнопку. Если значение переменной будет изменяться в прерывании, нужно сообщить об этом микроконтроллеру при помощи спецификатора volatile, который пишется перед указанием типа данных переменной, иначе работа будет некорректной. Это просто нужно запомнить: если переменная меняется в прерывании – делайте её volatile.
Ещё несколько важных моментов:
- Переменные, изменяемые в прерывании, должны быть объявлены как volatile
- В прерывании не работают задержки типа delay()
- В прерывании не меняет своё значение millis() и micros()
- В прерывании некорректно работает вывод в порт (Serial.print()), также не стоит там его использовать – это нагружает ядро
- В прерывании нужно стараться делать как можно меньше вычислений и вообще “долгих” действий – это будет тормозить работу МК при частых прерываниях! Что же делать? Читайте ниже.
Если прерывание отлавливает какое-то событие, которое необязательно обрабатывать сразу, то лучше использовать следующий алгоритм работы с прерыванием:
- В обработчике прерывания просто поднимаем флаг
- В основном цикле программы проверяем флаг, если поднят – сбрасываем его и выполняем нужные действия
Это в принципе всё, что нужно знать о прерываниях, более конкретные случаи мы разберём в продвинутых уроках.
Видео
- Уроки
- Базовые уроки Arduino
- Аппаратные прерывания
Аппаратные прерывания
Забавную картинку к этому уроку я найти не смог, нашёл только какую-то лекцию по программированию, и вот самое начало этой лекции отлично объясняет нам, что такое прерывание. Прерывание в Ардуино можно описать абсолютно точно так же: микроконтроллер “всё бросает”, переключается на выполнение блока функций в обработчике прерывания, выполняет их, а затем возвращается ровно к тому месту основного кода, в котором остановился.
Прерывания бывают разные, то есть не сами прерывания, а их причины: прерывание может вызвать аналогово-цифровой преобразователь, таймер-счётчик или буквально пин микроконтроллера. Такие прерывания называются внешними аппаратными, и именно о них мы сегодня поговорим.
External hardware interrupt – это прерывание, вызванное изменением напряжения на пине микроконтроллера. Основная суть состоит в том, что микроконтроллер (вычислительное ядро) не занимается опросом пина и не тратит на это время, пином занимается другая “железка”. Как только напряжение на пине изменяется (имеется в виду цифровой сигнал, +5 подали/+5 убрали) – микроконтроллер получает сигнал, бросает все дела, обрабатывает прерывание, и возвращается к работе. Зачем это нужно? Чаще всего прерывания используются для детектирования коротких событий – импульсов, или даже для подсчёта их количества, не нагружая основной код. Аппаратное прерывание может поймать короткое нажатие кнопки или срабатывание датчика во время сложных долгих вычислений или задержек в коде, т.е. грубо говоря – пин опрашивается параллельно основному коду. Также прерывания могут будить микроконтроллер из режимов энергосбережения, когда вообще практически вся периферия отключена. Посмотрим, как работать с аппаратными прерываниями в среде Arduino IDE.
Прерывания в Arduino
Начнём с того, что не все пины “могут” в прерывания. Да, есть такая штука, как pinChangeInterrupts, но о ней мы поговорим в продвинутых уроках. Сейчас нужно понять, что аппаратные прерывания могут генерировать только определённые пины:
INT 0 | INT 1 | INT 2 | INT 3 | INT 4 | INT 5 | |
ATmega 328/168 (Nano, UNO, Mini) | D2 | D3 | – | – | – | – |
ATmega 32U4 (Leonardo, Micro) | D3 | D2 | D0 | D1 | D7 | – |
ATmega 2560 (Mega) | D2 | D3 | D21 | D20 | D19 | D18 |
Как вы поняли из таблицы, прерывания имеют свой номер, который отличается от номера пина. Есть кстати удобная функция digitalPinToInterrupt(pin), которая принимает номер пина и возвращает номер прерывания. Скормив этой функции цифру 3 на Ардуино нано, мы получим 1. Всё по таблице выше, функция для ленивых.
Подключается прерывание при помощи функции attachInterrupt(pin, handler, mode):
- pin – номер прерывания
- handler – имя функции-обработчика прерывания (её нужно создать самому)
- mode – “режим” работы прерывания:
- LOW (низкий) – срабатывает при сигнале LOW на пине
- RISING (рост) – срабатывает при изменении сигнала на пине с LOW на HIGH
- FALLING (падение) – срабатывает при изменении сигнала на пине с HIGH на LOW
- CHANGE (изменение) – срабатывает при изменении сигнала (с LOW на HIGH и наоборот)
Также прерывание можно отключить при помощи функции detachInterrupt(pin), где pin – опять же номер прерывания.
А ещё можно глобально запретить прерывания функцией noInterrupts() и снова разрешить их при помощи interrupts(). Аккуратнее с ними! noInterrupts() остановит также прерывания таймеров, и у вас “сломаются” все функции времени и генерация ШИМ.
Давайте рассмотрим пример, в котором в прерывании считаются нажатия кнопки, а в основном цикле они выводятся с задержкой в 1 секунду. Работая с кнопкой в обычном режиме, совместить такой грубый вывод с задержкой – невозможно:
Итак, наш код считает нажатия даже во время задержки! Здорово. Но что такое volatile? Мы объявили глобальную переменную counter, которая будет хранить количество нажатий на кнопку. Если значение переменной будет изменяться в прерывании, нужно сообщить об этом микроконтроллеру при помощи спецификатора volatile, который пишется перед указанием типа данных переменной, иначе работа будет некорректной. Это просто нужно запомнить: если переменная меняется в прерывании – делайте её volatile.
Ещё несколько важных моментов:
- Переменные, изменяемые в прерывании, должны быть объявлены как volatile
- В прерывании не работают задержки типа delay()
- В прерывании не меняет своё значение millis() и micros()
- В прерывании некорректно работает вывод в порт (Serial.print()), также не стоит там его использовать – это нагружает ядро
- В прерывании нужно стараться делать как можно меньше вычислений и вообще “долгих” действий – это будет тормозить работу МК при частых прерываниях! Что же делать? Читайте ниже.
Если прерывание отлавливает какое-то событие, которое необязательно обрабатывать сразу, то лучше использовать следующий алгоритм работы с прерыванием:
- В обработчике прерывания просто поднимаем флаг
- В основном цикле программы проверяем флаг, если поднят – сбрасываем его и выполняем нужные действия
Это в принципе всё, что нужно знать о прерываниях, более конкретные случаи мы разберём в продвинутых уроках.
Видео
Прерывания – очень важный механизм Arduino, позволяющий внешним устройствам взаимодействовать с контроллером при возникновении разных событий. Установив обработчик аппаратных прерываний в скетче, мы сможем реагировать на включение или выключение кнопки, нажатие клавиатуры, мышки, тики таймера RTC, получение новых данных по UART, I2C или SPI. В этой статье мы узнаем, как работают прерывания на платах Ардуино Uno, Mega или Nano и приведем пример использования функции Arduino attachInterrupt().
Прерывания в Ардуино
Прерывание – это сигнал, который сообщает процессору о наступлении какого-либо события, которое требует незамедлительного внимания. Процессор должен отреагировать на этот сигнал, прервав выполнение текущих инструкций и передав управление обработчику прерывания (ISR, Interrupt Service Routine). Обработчик – это обычная функция, которую мы пишем сами и помещаем туда тот код, который должен отреагировать на событие.
После обслуживания прерывания ISR функция завершает свою работу и процессор с удовольствием возвращается к прерванным занятиям – продолжает выполнять код с того места, в котором остановился. Все это происходит автоматически, поэтому наша задача заключается только в том, чтобы написать обработчик прерывания, ничего при этом не сломав и не заставляя процессор слишком часто отвлекаться на нас. Понадобится понимание схемы, принципов работы подключаемых устройств и представление о том, как часто может вызываться прерывание, каковы особенности его возникновения. Все это и составляет основную сложность работы с прерываниями.
Аппаратные и программные прерывания
Прерывания в Ардуино можно разделить на несколько видов:
- Аппаратные прерывания. Прерывание на уровне микропроцессорной архитектуры. Самое событие может произойти в производительный момент от внешнего устройства – например, нажатие кнопки на клавиатуре, движение компьютерной мыши и т.п.
- Программные прерывания. Запускаются внутри программы с помощью специальной инструкции. Используются для того, чтобы вызвать обработчик прерываний.
- Внутренние (синхронные) прерывания. Внутреннее прерывание возникает в результате изменения или нарушения в исполнении программы (например, при обращении к недопустимому адресу, недопустимый код операции и другие).
Зачем нужны аппаратные прерывания
Аппаратные прерывания возникают в ответ на внешнее событие и исходят от внешнего аппаратного устройства. В Ардуино представлены 4 типа аппаратных прерываний. Все они различаются сигналом на контакте прерывания:
- Контакт притянут к земле. Обработчик прерывания исполняется до тех пор, пока на пине прерывания будет сигнал LOW.
- Изменение сигнала на контакте. В таком случае Ардуино выполняет обработчик прерывания, когда на пине прерывания происходит изменение сигнала.
- Изменение сигнала от LOW к HIGH на контакте – при изменении с низкого сигнала на высокий будет исполняться обработчик прерывания.
- Изменение сигнала от HIGH к LOW на контакте – при изменении с высокого сигнала на низкий будет исполняться обработчик прерывания.
Прерывания полезны в программах Ардуино, так как помогают решать проблемы синхронизации. Например, при работе с UART прерывания позволяют не отслеживать поступление каждого символа. Внешнее аппаратное устройство подает сигнал прерывания, процессор сразу же вызывает обработчик прерывания, который вовремя захватывает символ. Это позволяет экономить процессорное время, которое без прерываний тратилось бы на проверку статуса UART, вместо этого все необходимые действия выполняются обработчиком прерывания, не затрагивая главную программу. Особых возможностей от аппаратного устройства не требуется.
Основными причинами, по которым необходимо вызвать прерывание, являются:
- Определение изменения состояния вывода;
- Прерывание по таймеру;
- Прерывания данных по SPI, I2C, USART;
- Аналогово-цифровое преобразование;
- Готовность использовать EEPROM, флеш-память.
Как реализуются прерывания в Ардуино
При поступлении сигнала прерывания работа в цикле loop() приостанавливается. Начинается выполнение функции, которая объявляется на выполнение при прерывании. Объявленная функция не может принимать входные значения и возвращать значения при завершении работы. На сам код в основном цикле программы прерывание не влияет. Для работы с прерываниями в Ардуино используется стандартная функция attachInterrupt().
Отличие реализации прерываний в разных платах Ардуино
В зависимости от аппаратной реализации конкретной модели микроконтроллера есть несколько прерываний. Плата Arduino Uno имеет 2 прерывания на втором и третьем пине, но если требуется более двух выходов, плата поддерживает специальный режим «pin-change». Этот режим работает по изменению входа для всех пинов. Отличие режима прерывания по изменению входа заключается в том, что прерывания могут генерироваться на любом из восьми контактов. Обработка в таком случае будет сложнее и дольше, так как придется отслеживать последнее состояние на каждом из контактов.
На других платах число прерываний выше. Например, плата Ардуино Мега 2560 имеет 6 пинов, которые могут обрабатывать внешние прерывания. Для всех плат Ардуино при работе с функцией attachInterrupt (interrupt, function, mode) аргумент Inerrupt 0 связан с цифровым пином 2.
Прерывания в языке Arduino
Теперь давайте перейдем к практике и поговорим о том, как использовать прерывания в своих проектах.
Функция attachInterrupt используется для работы с прерываниями. Она служит для соединения внешнего прерывания с обработчиком.
Синтаксис вызова: attachInterrupt(interrupt, function, mode)
- interrupt – номер вызываемого прерывания (стандартно 0 – для 2-го пина, для платы Ардуино Уно 1 – для 3-го пина),
- function – название вызываемой функции при прерывании(важно – функция не должна ни принимать, ни возвращать какие-либо значения),
- mode – условие срабатывания прерывания.
Возможна установка следующих вариантов условий срабатывания:
- LOW – выполняется по низкому уровню сигнала, когда на контакте нулевое значение. Прерывание может циклично повторяться – например, при нажатой кнопке.
- CHANGE – по фронту, прерывание происходит при изменении сигнала с высокого на низкий или наоборот. Выполняется один раз при любой смене сигнала.
- RISING – выполнение прерывания один раз при изменении сигнала от LOW к HIGH.
- FALLING – выполнение прерывания один раз при изменении сигнала от HIGH к LOW.4
Важные замечания
При работе с прерываниями нужно обязательно учитывать следующие важные ограничения:
- Функция – обработчик не должна выполняться слишком долго. Все дело в том, что Ардуино не может обрабатывать несколько прерываний одновременно. Пока выполняется ваша функция-обработчик, все остальные прерывания останутся без внимания и вы можете пропустить важные события. Если надо делать что-то большое – просто передавайте обработку событий в основном цикле loop(). В обработчике вы можете лишь устанавливать флаг события, а в loop – проверять флаг и обрабатывать его.
- Нужно быть очень аккуратными с переменными. Интеллектуальный компилятор C++ может “пере оптимизировать” вашу программу – убрать не нужные, на его взгляд, переменные. Компилятор просто не увидит, что вы устанавливаете какие-то переменные в одной части, а используете – в другой. Для устранения такой вероятности в случае с базовыми типами данных можно использовать ключевое слово volatile, например так: volatile boolean state = 0. Но этот метод не сработает со сложными структурами данных. Так что надо быть всегда на чеку.
- Не рекомендуется использовать большое количество прерываний (старайтесь не использовать более 6-8). Большое количество разнообразных событий требует серьезного усложнения кода, а, значит, ведет к ошибкам. К тому же надо понимать, что ни о какой временной точности исполнения в системах с большим количеством прерываний речи быть не может – вы никогда точно не поймете, каков промежуток между вызовами важных для вас команд.
- В обработчиках категорически нельзя использовать delay(). Механизм определения интервала задержки использует таймеры, а они тоже работают на прерываниях, которые заблокирует ваш обработчик. В итоге все будут ждать всех и программа зависнет. По этой же причине нельзя использовать протоколы связи, основанные на прерываниях (например, i2c).
Примеры использования attachInterrupt
Давайте приступим к практике и рассмотрим простейший пример использования прерываний. В примере мы определяем функцию-обработчик, которая при изменении сигнала на 2 пине Arduino Uno переключит состояние пина 13, к которому мы традиционно подключим светодиод.
Давайте рассмотрим несколько примеров более сложных прерываний и их обработчиков: для таймера и кнопок.
Прерывания по нажатию кнопки с антидребезгом
При прерывании по нажатию кнопки возникает проблема дребезга – перед тем, как контакты плотно соприкоснутся при нажатии кнопки, они будут колебаться, порождая несколько срабатываний. Бороться с дребезгом можно двумя способами – аппаратно, то есть, припаивая к кнопке конденсатора, и программно.
Избавиться от дребезга можно при помощи функции millis – она позволяет засечь время, прошедшее от первого срабатывания кнопки.
Этот код позволяет удалить дребезг и не блокирует исполнение программы, как в случае с функцией delay, которая недопустима в прерываниях.
Прерывания по таймеру
Таймером называется счетчик, который производит счет с некоторой частотой, получаемой из процессорных 16 МГц. Можно произвести конфигурацию делителя частоты для получения нужного режима счета. Также можно настроить счетчик для генерации прерываний при достижении заданного значения.
Таймер и прерывание по таймеру позволяет выполнять прерывание один раз в миллисекунду. В Ардуино имеется 3 таймера – Timer0, Timer1 и Timer2. Timer0 используется для генерации прерываний один раз в миллисекунду, при этом происходит обновление счетчика, который передается в функцию millis (). Этот таймер является восьмибитным и считает от 0 до 255. Прерывание генерируется при достижении значения 255. По умолчанию используется тактовый делитель на 65, чтобы получить частоту, близкую к 1 кГц.
Для сравнения состояния на таймере и сохраненных данных используются регистры сравнения. В данном примере код будет генерировать прерывание при достижении значения 0xAF на счетчике.
Требуется определить обработчик прерывания для вектора прерывания по таймеру. Вектором прерывания называется указатель на адрес расположения команды, которая будет выполняться при вызове прерывания. Несколько векторов прерывания объединяются в таблицу векторов прерываний. Таймер в данном случае будет иметь название TIMER0_COMPA_vect. В этом обработчике будут производиться те же действия, что и в loop ().
Подведение итогов
Прерывание в Ардуино – довольно сложная тема, потому что приходится думать сразу обо всей архитектуре проекта, представлять как выполняется код, какие возможны события, что происходит, когда основной код прерывается. Мы не ставили задачу раскрыть все особенности работы с этой конструкцией языка, главная цель была познакомить с основными вариантами использования. В следующих статьях мы продолжим разговор о прерываниях более подробне.
инструменты и методы технического волшебства
Аппаратные прерывания являются альтернативой опроса состояния входов в цикле loop(). Они не лучше и не хуже, всегда есть выбор между ними. При проектировании системы необходимо учитывать все факторы и выбрать вариант, наиболее подходящий для вашего приложения. Далее рассмотрим основные различия между опросом входов и прерываниями, чтобы понять, что лучше подойдет для конкретного проекта.
12.2.1. Программная реализация
Благодаря встроенному языку программирования Arduino программировать внешние прерывания сравнительно просто. Однако организовать опрос контактов в цикле еще проще, все, что требуется — это вызов команды digitalRead(). Если нет безусловной необходимости в аппаратных прерываниях, то лучше их не применять, т. к. код программы усложнится.
12.2.2. Аппаратная реализация
С точки зрения аппаратной реализации между опросом контакта в цикле и прерыванием нет разницы, т. к. в обоих случаях считывается состояние входа. Тем не менее, при наличии дребезга ( см. главу 2) возникает серьезная проблема: процедура обработки прерывания может быть вызвана несколько раз. Самое неприятное, что в процедуре обработки прерывания нельзя задействовать функцию программного устранения дребезга, потому что невозможен вызов функции ctelay(). Поэтому, если вы хотите использовать прерывание для входа с дребезгом, необходимо устранить дребезг аппаратно.
12.2.3. Многозадачность
Одна из причин использования прерываний — предоставление псевдомногозадачности. С помощью Arduino никогда нельзя обеспечить реальную многозадачность, т. к. на плате только один микроконтроллер, который за один такт может выполнить только одну команду. Однако, поскольку микроконтроллер выполняет команды очень быстро, можно прибегнугь к прерываниям, чтобы выполнять разные задачи почти одновременно. Например, с помощью прерывания можно в про-
— 256 —
цессе уменьшения яркости светодиодов реагировать на нажатие кнопки, которая регулирует скорость или цвет. В то время как при опросе контакта в цикле можно прочитать значение входа кнопки командой dig i talRead() только один раз и имеющиеся в цикле loop() «медленные» операции снижают эффективность контроля входа кнопки.
12.2.4. Точность сбора данных
Для некоторых задач, где требуется быстрый сбор данных, прерывания являются необходимостью. Один из примеров — энкодер, смонтированный на двигателе постоянного тока, отправляющий в микроконтроллер импульс при определенном числе оборотов вала. Так осуществляется следящая обратная связь за скоростью вращения двигателя постоянного тока. Это позволяет динамически регулировать скорость в зависимости от нагрузки или отслеживать поворот вала двигателя. Но в такой системе исключительно важно быть уверенным, что плата Arduino получает каждый импульс. Поскольку импульсы очень короткие (намного короче импульса при нажатии кнопки), то при опросе в цикле loop() их можно пропустить. Если энкодер посылает импульс два раза за оборот вала двигателя, то из-за пропуска одного импульса измеренная частота вращения окажется вдвое меньше истинной. Поэтому в данном случае без аппаратного прерывания не обойтись.
12.2.5. Реализация аппаратного прерывания в Arduino
В большинстве плат Arduino для аппаратных прерываний выделены специальные контакты. Прерывания обозначаются с помощью идентификационного номера, которому сопоставлен определенный контакт (табл. 12.1). Исключение составляет плата Due, у которой для прерываний можно задействовать любой контакт, и номер прерывания совпадает с номером контакта.
Таблица 12.1. Аппаратные прерывания на различных платах Arduino
Плата
INTO
INT1
INT2
INT3
INT4
INT5
UNO,
Ethernet
Pin2
Pin3
—
—
—
—
Mega2560
Pin2
Pin3
Pin21
Pin20
Pin19
Pin18
Leonardo
Pin2
Pin0
Pin1
—
—
Для вызова прерывания существует встроенная функция attachInterrupt(). Ее первый аргумент — это идентификатор прерывания (для плат из табл. 12.1) или номер контакта Arduino (для платы Due). Если на плате Arduino Uno вы хотите назначить прерывание физическому контакту 2, то первый аргумент функции attachInterrupt() будет 0. Arduino Uno (и другие платы на базе ATmega328) поддерживает всего два внешних прерывания, платы Mega и Leonardo больше (см. табл. 12.1).
— 257 —
Аппаратные прерывания осуществляют переход к выполненшо определенных функций. Второй аргумент функции attach_interrupt() — имя выполняемой функции. Если вы хотите переключать состояние логической переменной при каждом прерывании, то функция обработки прерывания будет выглядеть так:
void toggleLed()
{
var = !var;
}
При вызове этой функции переменная var переключается в состояние, противоположное предыдущему, и происходит возврат в основную программу. Последний аргумент функции attachInterrupt() — режим запуска прерывания. Существуют режимы LOW, CHANGE, RISING и FALLING (для платы Due также есть режим HIGH).
Режимы CHANGE, RISING и FALLING наиболее популярны, потому что прерывание выполняется только один раз при изменении состояния входа. Режимы HIGH и LOW встречаются реже, потому что будут вызывать процедуру обработки прерывания непрерывно, блокируя остальную часть программы.
Arduino прерывает для ввода кнопки
Надеюсь, я не опоздаю с этим решением «черной магии» 🙂
Прежде всего, чтобы прояснить ситуацию, то, что вам нужно, можно и не сложно достичь, но есть и хорошие, и плохие новости. Плохая новость заключается в том, что ваш выбор не может быть абсолютно произвольным, а хорошая новость заключается в том, что вы можете выбрать один из 24 дополнительных выводов (те, которые отмечены символом PCINTx в листе данных, PCINT0 полностью PCINT23)
Также плохая новость заключается в том, что некоторые из следующих действий могут сначала показаться немного туманными (в том случае, если вы не так много экспериментировали с микроконтроллерами), но хорошая новость заключается в том, что у вас будет гораздо лучшее представление о том, что вы делаете. с как только вы закончите работу 🙂
Несколько основных моментов по этому вопросу, о которых вы, вероятно, уже знаете или о которых слышали: PCINTx означает «Pin Change INTerrupt», и, если он включен, для определенного контакта он будет вызывать прерывание каждый раз, когда состояние этого контакта изменяется (с высокого до низкого / от низкого до высокого).
Во-вторых, ваш подход должен выглядеть примерно так:
- включить прерывание смены контактов на 6 нужных контактах
- включить глобальные прерывания
- когда вызывается прерывание, проверьте состояние ввода, чтобы определить изменение и сохранить состояние кнопки
Вам понадобится таблица данных, так что вот ярлык: http://www.atmel.com/dyn/resources/prod_documents/doc2549.PDF 🙂
для шага 1: см. регистр PCICR на стр. 115, это регистр управления прерываниями смены контактов, а также регистры PCMSK2, PCMSK1, PCMSK0 для точного указания, какие контакты активированы для этой специальной функции.
для шага 2: я почти уверен, что вы знаете, как это сделать, так как вы разместили этот вопрос 🙂 — если нет, позвоните: sei ()
для шага 3: это сложная часть. У вас есть 3 вектора прерывания (или вы можете назвать их обратными вызовами) по одному на каждый порт (каждый порт имеет 8 контактов). Если несколько контактов порта sam установлены как триггеры (из регистров маски PCMSKx, на шаге 1) будет вызываться один и тот же обратный вызов, поэтому обязательно проверьте регистр PINx, чтобы точно узнать, какой из них изменился.
Вот и все 🙂 еще несколько вещей: это также применимо для ArduinoUno (atMega328p). Это очень полезная функция — если учитывать энергопотребление, вы можете держать контроллер в спящем режиме и выполнять активацию по прерыванию. Я использовал эту функцию для чтения входных данных с RC-приемника, и вы можете получить действительно хорошие тайминги (управляемые прерываниями, так что: P)
Вот ссылка с БОЛЬШОЙ ИНФОРМАЦИЕЙ по этому вопросу, вероятно, следовало бы начать отсюда: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=71109
Я сам всегда предпочитаю программное решение, а не аппаратное решение, обычно оно более гибкое, и в большинстве случаев предоставляемые результаты дешевле и быстрее достигаются, чем аппаратные изменения (также менее грязные) :). Но имейте в виду, что все, что является аппаратным, НАМНОГО гораздо НАМНОГО быстрее (что оправдывает затраты, беспорядок и отсутствие гибкости). Однако в данном случае я не думаю, что вам нужна такая скорость, так что выбирайте SW 🙂
Надеюсь, я не опаздываю, но на всякий случай, надеюсь, это будет полезно, может быть, в другой день 🙂 Вы можете найти хорошую реализацию того, что, как я считаю, вам нужно, на второй ссылке (той, что от avrfreaks)
Это ссылка, которую я взял в другом потоке на stackexchange, довольно хорошо суммирует всю идею http://www.me.ucsb.edu/~me170c/Code/How_to_Enable_Interrupts_on_ANY_pin.pdf
Ура, Дэн
Обработка большого количества кнопок на одном прерывании — Полезная информация — AVR project.ru
Используя в проектах большое количество кнопок, постоянно сталкиваюсь с проблемой нехватки количества внешних прерываний. Вроде выбрал подходящий по нафаршированности камень, есть все что надо — АЦП, 2 юарта, много флэша, а вот прерываний нехватает…
Или чаще наоборот, небольшой проект, на который с лихвой хватит ресурсов tiny2313, и нужно обрабатывать много внешних событий (таких как нажатие на кнопки). Брать камень крупнее не спортивно, да и жалко когда ресурсы будут низачто простаивать :), поэтому был найден простой способ как, использовав всего один вход прерывания, обработать практически неограниченное количество кнопок.Суть метода в том, чтобы одним прерыванием фиксировать нажатие любой кнопки. А уже в обработчике прерывания просканировать и узнать какая именно кнопка была нажата.
Для примера вот небольшая схемка:
Диоды D1-D4 предназначены для того чтобы разделить кнопки между собой. Резисторы можно ставить номиналом по 4,7-10 кОм.
$regfile = «attiny2313.dat»
$crystal = 1000000
$baud = 1200
Dim W As Byte ‘переменная с номером нажатой кнопки
‘кнопки
Config Portb.0 = Input
Config Portb.1 = Input
Config Portb.2 = Input
Config Portb.3 = Input
Config Portd.6 = Output ‘сюда подключается светодиод индикации
Portd.6 = 0
Config Int0 = Falling ‘прерывание по нисходящему фронту
On Int0 Button
Enable Interrupts ‘разрешаем прерывания
Enable Int0
‘Основной цикл программы
Do
Print W ‘печатаем номер нажатой кнопки
W = 0
Idle ‘и засыпаем
Loop
End
‘обработчик прерывания
Button:
‘здесь мы в цикле сканируем все подключенные кнопки
Do
If Pinb.3 = 0 Then
W = 1
End If
If Pinb.2 = 0 Then
W = 2
End If
If Pinb.1 = 0 Then
W = 3
End If
If Pinb.0 = 0 Then
W = 4
End If
Pulseout Portd , 6 , 2500 ‘мигнем светодиодом
Loop Until W <> 0 ‘если дребезг помешал вычислению нажатой кнопки, повторяем
Waitms 10
Gifr = 64 ‘сброс флага прерывания
Return
Светодиод на схеме не показан, из программы думаю ясно, что он подключается к ножке PortD.6
Номер кнопки в примере печатается в терминал на скорости 1200 бод.
Как видно это очень простой способ, который подойдет под различные задачи. А поменяв немного алгоритм сканирования портов, можно организовать обработку одновременно нескольких кнопок.
Найдёшь друга – обретёшь сокровище!
Добрый день, уважаемые господа Тудэевцы! Долго не писал сюда ничего так как не находил информации достойной вашего внимания. Сегодняшний мой рассказ о домашней метеостанции.
Часть первая.
«Почему у тебя так мало друзей? — Потому что я дружу лишь с настоящими…»/м/ф «Ёжик в тумане»/
Есть у меня, господа Тудэевцы, настоящий друг – Серёга. Мы с ним уже «пенсюки», и сидим по своим хатам, а когда-то, целых сорок лет трудились вместе на благо энергетики, а всё свободное время, занимались «радиолюбительством». Сейчас это называется «электроникой», а раньше, «энтузазист» с паяльником, умевший починить не только отвалившийся носик у чайника, но и радиоприёмник, гордо назывался «Радиолюбитель». (Не путайте с «любителем радио»). И хотя увлечения у нас были и остаются разные – у него: приёмники, передатчики, приборы для их настройки, а у меня – авиамоделизм, микроконтроллеры и программирование, но всегда было то, что нас связывало, а именно – общие проекты. Начинались они обычно с того, что он колхозил для себя какую-нибудь железяку или паял очередную схему, а то и притаскивал что-то интересное и показывал мне, типа – вот хочу сделать-переделать. Я, из-за своего дурацкого неуёмного любопытства, «втыкал» что он там хочет сделать, кумекал, что надо бы попробовать «вот эдак», отодвигал все свои проекты в сторону и со словами «Да фига ли тут делать то!» начинал клепать его «хотелку». И затягивалось это чаще всего не на один день и даже бывало не на одну неделю, потому что делать «абы как» и «лишь бы заработало» я не умею. Так, к примеру, появились синтезаторы частоты для его трансивера и радиостанции «Ангара» его брательника.
Вот и с этим проектом вышла та же песня. Приносит он экранчик. Глянь-ка, говорит, Шурик, какая занятная фиговина. Ну, взял я его, 3,5 дюйма, ничего особенного, выводов только что-то маловато, всего четыре. Ага, гэнэдэ, эрыкс, тэикс и питалово. — Ну и чё? — А ты подключи. — Скока? — Пять вольт. Подключил. И вот тут я, господа Тудэевцы, конкретно офигел. Вы, наверное, догадались, что это был экран NEXTION, и по включению пошла работать их фирменная демка. Для многих из вас этот девайс – обыденность, а я смотрел на него в первый раз, тыкал в сенсорный экран, а в голове носилась мысль – «это что, он всё делает сам, БЕЗ АРДУИНЫ!?».- Ну как, хорошая штучка? — ЗНАМЕНИТО! — Для него ещё и среда разработки есть. Там и картинки можно сразу в него грузить и кнопки делать и ещё куча всякого вплоть до вычислений. – И чё на нём делать то собираешься? – Да я тебе как-то говорил, что давно хочу метеостанцию сделать, вот это к ней экран с али и заказал. – А купить готовую не проще было? Их вон полно сейчас всяко-разных. – Да нет, мне надо с выносным блоком, не с буржуйскими надписями, и чтобы давление отслеживать, температуру, ну и графики хотелось бы, чтобы знать, как что меняется. Жена у меня очень метеочувствительная. Ей это очень важно. – Понятно…
А понятно мне стало, что всё своё опять в сторону, и буду я делать другану моему метеостанцию, потому что этот «змей болотный» знал, что я теперь эту игрушку из рук не выпущу пока не оближу её со всех сторон. Вот так и родился этот проект, который я вам и представляю.
Часть вторая.
«Не печалься, ступай себе с богом, будет вам новое корыто» /А.С.Пушкин/
Итак, метеостанция. Что тут особо мудрить то? Внутренний блок с сенсорным экраном, и наружный, который просто передаёт где-нибудь раз в пять-десять минут показания «болтающейся в воздухе атмосферы», а потом дрыхнет для экономии заряда батареи. Раз уж есть такой продвинутый экран, то сделаем всё «покрасившэ».
Скачав Nextion Editor, описание команд, и «всосав» массу умного и полезного из инета, я погрузился в эксперименты и фотошопничество. В результате родился вот такой первый экран.
Программирование, борьба с кодировками, выводом русских букв, изображением объёмных кнопок на разноцветном заднем плане, всё это, конечно, весьма занимательно, но увы, «не для сюда».
Так как для часов я использовал модуль DS3231, в котором «полный компот», вплоть до двух будильников, то решил вывести на экран не только время, но и день недели, число и месяц. Температура в избе отображается там, где нарисован домик, а наружная – ниже.
Если с пиктограммами температуры и влажности сомнений не возникло, то с давлением пришлось помозговать. В самом деле, какой бы значок вы взяли для давления? Барометр? Но на маленьком экране это получился бы невразумительный кружочек. Манжетку измерения артериального давления? Палец, раздавливающий козявку? Манометр? Вот-вот… Поиск картинок выдаёт именно такую фигню. И тогда я решил, пусть будет гиря! Кто скажет, что гиря не давит, пусть предложит мне свой вариант.
Итак, с пиктограммами-кнопками я определился. Теперь – что тут для чего: солнышко с тучкой – установка даты, циферки текущего времени – естественно, установка времени, гиря – график давления, градусник – график температуры. Соответственно, вот какие экраны вызываются.
Установка даты. Тут, как говорится, «ноу коментс».
Установка времени. И тут всё просто, как трусы за рубль двадцать. После вызова — на экране текущее время. Кнопки слева – устанавливаем часы, справа – минуты. Нижние кнопки, понятно, в объяснениях не нуждаются. А как же корректировка по сигналам точного времени, спросите вы? А всё просто. Тычем на изображение времени, но не отпускаем. Происходит корректировка – до 30 минут – в минус, после – в плюс. Пропиликал шестой сигнал — отпускаем. В этот волшебный момент и вылетит птичка.
Пока я всем этим занимался, Сергей сделал плату наружного блока и заодно провёл дома «лабораторную работу». Цель лабы — сделать таймер на 555-ой мелкосхеме и выяснить, какую максимальную выдержку времени можно получить. Всё это для того, чтобы разбудить заснувший проц по внешнему прерыванию. Оказалось, что не более 50 секунд, а дальше всё, «сушите вёсла». И не помогает ни увеличение ёмкости, ни подбор резисторов. Если вы, господа Тудэевцы, знаете, как не слишком сложно и затратно сделать таймер на 10 минут, и чтобы он потреблял ну самую малость, то ткните меня носом, плиз.
Про графики. Для того, чтобы прикинуть, «что день грядущий нам готовит?», я решил рисовать графики давления и температуры с ретроспективой на сутки. После долгих проб и возгласов «Не, это чё-та опять стрёмно получилось», родились вот такие дизайнёристие решения.
Буквально ещё несколько слов о том, как формируются графики. Как я говорил, данные от наружного блока поступают примерно раз в 50 секунд (ну вот такова суровая правда жизни). Хранить такой массив данных за сутки (4 байта на одно измерение) в дохлецкой оперативке наны — нереально. А так как давление и температура меняются весьма медленно, то я просто раз в 10 минут беру последние пришедшие значения и сохраняю их в массив. Таким образом, на сутки потребовалось всего 24*6=144 байта для каждого измерения (я привёл float к byte). Среднее арифметическое очередных 6 элементов массива дают одну точку на графике, что соответствует одному часу. Для контроля получения данных от наружного блока я сделал еще один служебный экран. Кстати, он мне помог выяснить почему периодически пропадают телеизмерения. Оказалось, всё просто – надо было поднять мощность передатчика наружного блока. Переход на этот экран – нажимаем на домик.
В принципе, на этом можно было бы и закончить, и идти моделировать корпуса, но вот представьте, пошли вы среди ночи «привязать коня» или с инспекторской проверкой — а не заточил ли кто из домашних котлетки, оставшиеся с вечера в холодильнике, а тут во всю дурь этот агрегат светит так, что хоть дискотеку устраивай. Это же натуральное палево! Выход какой? Надо сделать ночной экран. Сделал.
Кстати, обратите внимание на циферки часов. Они ПРОЗРАЧНЫЕ! Это надо произносить тоном улитки из мультика про Алису: «Если его хорошенько стукнуть, он станет — ФЫОЛЭТОВЫЙ!» Сквозь циферки видно звёздочки! В 10 вечера и в 6 утра идёт переключение день/ночь.
Часть третья.
«Мы строили, строили, и наконец, построили!»/Чебурашка/
В моём любимом скетчапе спроектировал корпус и основание, которое есть сразу и задняя крышка. Печатал без поддержек филаментом PETG, приобретённом в Wildberries. Нормальный, кстати, филамент, печатает без проблем. С цветом пластика не вымудрялся, потому как впереди светит шкуринг и красинг, иначе товарного вида не будет. Из основания «выдавлены» пеньки для монтажа компонентов схемы.
Кстати, делюсь с вами моей ноухавой. Если вам потребуются обрезиненные ножки для вашей самоделки, то их можно сделать из поршней шприцов. В основании делаем крестовые отверстия и вставляем в них отрезки поршней. Посадить можно на клей, или даже просто раздавть паяльником. Ценно то, что шприцы по размерам разные, и можно выбрать подходящие для вашей конструкции размеры.
После печати схему с монтажки перенёс «на натуру».
Пришлось покоцать всю иллюминацию, а то всё сверкало как очаг у папы Карло.
Термодатчик вынес наружу через отверстие в задней крышке.
Внешний блок состоит тоже из двух частей – корпуса и крышки.
Крышка задвигается в пазы корпуса и фиксируется шурупом.
Плату с контроллером зарядя-разряда и акк расположил внутри на «пеньках» и зажимах. На наклонную крышу корпуса соплемётом приклеил солнечную батарею. Вот, собсно, и всё, но…
Часть четвёртая.
«Не надо делать мне как лучше, оставьте мне как хорошо» /Одесское/
К сожалению, (или к счастью?), нет предела совершенству, когда в руки попадает что-то интересное, и надо бы уже остановиться и отдать железяку заказчику, но в голову приходят новые идеи, и опять начинаешь уже готовую конструкцию дорабатывать и дорабатывать. Приветствие вот другану сделал, чтобы как включил агрегат, так меня и вспоминал разными словами.
А последняя придумка посетила меня, когда я опять же ночью зашел в комнату и увидел экран. «А зачем же и для кого он палит, если все дрыхнут? А днём то ведь тоже экран можно гасить, если в комнате никого нет!» В результате на заднюю стенку был приклеен микроволновый датчик движения RCWL-0516 и доработан скетч на предмет «наличия отсутствия движения». Если оно есть, то так уж и быть, нехай отображает что надо, а если движухи нет, то отображается последний экран, на котором при большом желании тоже можно кое-что увидеть, если замереть неподвижно на минуту-другую.
Вот теперь действительно всё. Спасибо всем дочитавшим до конца моего повествования. Интересных вам проектов, и по традиции, хорошей адгезии!
attachInterrupt () — Ссылка на Arduino
Описание
Цифровые выводы с прерываниями
Первый параметр в attachInterrupt ()
— это номер прерывания. Обычно вы должны использовать digitalPinToInterrupt (pin)
для преобразования фактического цифрового вывода в конкретный номер прерывания. Например, если вы подключаетесь к контакту 3, используйте digitalPinToInterrupt (3)
в качестве первого параметра для attachInterrupt ()
.
Доска | Цифровые выводы, используемые для прерываний |
---|---|
Uno, Nano, Mini, другие 328 на основе | 2, 3 |
Uno WiFi Rev.2, нано каждые | все цифровые контакты |
Mega, Mega2560, MegaADK | 2, 3, 18, 19, 20, 21 ( контактов 20 и 21 не могут использоваться для прерываний, пока они используются для связи I2C) |
Micro, Leonardo, другие на базе 32u4 | 0, 1, 2, 3, 7 |
Ноль | все цифровые контакты, кроме 4 |
Платы семейства MKR | 0, 1, 4, 5, 6, 7, 8, 9, A1, A2 |
Нано 33 IoT | 2, 3, 9, 10, 11, 13, A1, A5, A7 |
Nano 33 BLE, Nano 33 BLE Sense | все контакты |
Срок погашения | все цифровые контакты |
101 | все цифровые контакты (только контакты 2, 5, 7, 8, 10, 11, 12, 13 работают с CHANGE ) |
Примечания и предупреждения
Note
Внутри присоединенной функции delay ()
не будет работать, а значение, возвращаемое функцией millis ()
, не будет увеличиваться.Последовательные данные, полученные при использовании функции, могут быть потеряны. Вы должны объявить как volatile
любые переменные, которые вы изменяете в присоединенной функции. См. Раздел ISR ниже для получения дополнительной информации.
Использование прерываний
Прерыванияполезны для автоматического выполнения задач в программах микроконтроллера и могут помочь решить проблемы синхронизации. Хорошие задачи для использования прерывания могут включать чтение поворотного энкодера или мониторинг пользовательского ввода.
Если вы хотите убедиться, что программа всегда улавливает импульсы от поворотного энкодера, чтобы она никогда не пропускала импульс, было бы очень сложно написать программу, которая бы делала что-то еще, потому что программе нужно было бы постоянно опрашивать сенсорные линии для энкодера, чтобы улавливать импульсы, когда они возникают.Другие датчики также имеют аналогичную динамику интерфейса, например, попытку прочитать звуковой датчик, который пытается поймать щелчок, или инфракрасный щелевой датчик (фотопрерыватель), пытающийся поймать каплю монеты. Во всех этих ситуациях использование прерывания может освободить микроконтроллер для выполнения другой работы, не пропуская ввода.
О процедурах обслуживания прерывания
ISR— это особые виды функций, которые имеют некоторые уникальные ограничения, которых нет у большинства других функций. ISR не может иметь никаких параметров и не должен ничего возвращать.
Как правило, ISR должна быть как можно более короткой и быстрой. Если в вашем скетче используется несколько ISR, одновременно может выполняться только одна, остальные прерывания будут выполняться после завершения текущего в порядке, зависящем от их приоритета. millis ()
полагается на прерывания для подсчета, поэтому он никогда не будет увеличиваться внутри ISR. Поскольку delay ()
требует для работы прерываний, он не будет работать, если вызывается внутри ISR. micros ()
работает изначально, но через 1-2 мс начнет работать нестабильно. delayMicroseconds ()
не использует счетчик, поэтому он будет работать в обычном режиме.
Обычно глобальные переменные используются для передачи данных между ISR и основной программой. Чтобы убедиться, что переменные, совместно используемые ISR и основной программой, обновляются правильно, объявите их как volatile
.
Синтаксис
attachInterrupt (digitalPinToInterrupt (контакт), ISR, режим)
(рекомендуется)
attachInterrupt (прерывание, ISR, режим)
(не рекомендуется)
attachInterrupt (контакт, ISR, режим)
(не рекомендуется.Кроме того, этот синтаксис работает только на платах Arduino SAMD, Uno WiFi Rev2, Due и 101.)
Параметры
прерывание
: номер прерывания. Допустимые типы данных: int
.
pin
: номер контакта Arduino.
ISR
: ISR для вызова при возникновении прерывания; эта функция не должна принимать никаких параметров и ничего не возвращать. Эту функцию иногда называют процедурой обслуживания прерывания.
режим
: определяет, когда должно срабатывать прерывание.Четыре константы предопределены как допустимые значения:
LOW для запуска прерывания всякий раз, когда на выводе низкий уровень,
CHANGE для запуска прерывания всякий раз, когда вывод изменяет значение
RISING для срабатывания при переходе пина от низкого к высокому,
ПАДЕНИЕ , когда штифт переходит от высокого к низкому.
Платы Due, Zero и MKR1000 также позволяют:
Возвращает
Кнопочный переключательс использованием внешнего прерывания
Кнопочный переключатель, управляемый прерыванием,
Если вы новичок в идее подключения кнопочных переключателей и подключения простой схемы, то см. Учебное пособие «Общие сведения о кнопочных переключателях и их использовании». прежде чем перейти к рассмотрению примера реализации с внешним прерыванием.И наоборот, если вы знаете все, что нужно знать о кнопочных переключателях, их подключении, присущих проблемах и внешних прерываниях, вы также можете найти этот конкретный вклад, представляющий интерес, поскольку он представляет другой метод связывания и обработки кнопочных переключателей и их соответствующих прерываний.
Дизайн Соображения
Прежде чем мы рассмотрим предлагаемый метод, нам нужно определить нашу отправную точку, поскольку она имеет отношение к кодированному методу.
Цепь кнопочного выключателя — Цепь кнопочного переключателя сконфигурирована, как показано на Рисунке 1 (Цепь 1) ниже.Это очень распространенный способ подключения простой схемы переключателя. Схема гарантирует, что цифровой входной вывод, который мы объявляем и используем в качестве вывода прерывания, поддерживается на уровне 0 В, когда переключатель разомкнут (выключен), тем самым удаляя ложные входные сигналы, возникающие из-за помех, которые могли бы привести к ложному срабатыванию прерывания. Когда переключатель замкнут (включен), цифровой вывод поднимается до +5 В и запускает прерывание, как нам и требуется (см. Следующий раздел).
Режим прерывания — Далее нам нужно определить режим или тип триггера прерывания, к которому цифровой вывод будет чувствителен при срабатывании прерывания.Поскольку схема вызывает повышение напряжения с 0 В до + 5 В, когда переключатель замкнут, то очевидным выбором режима и соответствующего параметра для подключения прерывания является «RISING». Например, attachInterrupt (…, … ,, RISING).
Стиль переключения — Кнопочные переключатели — это переключатели мгновенного действия, под которыми я подразумеваю, что нормальное состояние переключателя выключено до нажатия, когда он включен, до тех пор, пока его состояние не возвращается обратно в выключенное состояние. Таким образом, переключатель включен только до тех пор, пока он нажат.Очевидно, да? Конечно. Однако природа механических кнопочных переключателей означает, что переключение должно пройти цикл включения и выключения, прежде чем можно будет сказать, что он был полностью нажат. Также обратите внимание, что время, в течение которого она удерживается нажатой, тоже может меняться — я могу удерживать палец на кнопке столько, сколько захочу.
Если мы также добавим, что переключатели не являются совершенными цифровыми устройствами, они неизменно будут генерировать шум, который может привести к ложному срабатыванию. Хорошая новость заключается в том, что такой шум можно устранить с помощью техники, известной как «противодействие».Действительно, предлагаемый эскиз действительно использует эту технику.
Чтобы понять, что происходит, на рисунке 2 представлена упрощенная диаграмма типичного цикла переключения кнопок. Он показывает пример шума от момента нажатия переключателя (точка A) до его полного включения (точка B) и с момента его отпускания (точка C) до полного выключения (точка D). Время, в течение которого переключатель может быть надежно включен, составляет от B до C, и это функция от того, как долго переключатель удерживается нажатым. Но, по правде говоря, мы должны учитывать ложные показания, которые могут возникнуть из-за шума в любой точке между A и D.Итак, все может быть немного запутанным — прерывание переключения может быть вызвано в любое время, и мы не можем зарегистрировать, что переключатель был нажат, пока мы не дойдем до точки D как можно скорее. Вполне рецепт требований!
Вместе с тем существует множество примеров, которые эффективно выполняют свою работу. Однако предлагаемый здесь метод прост, логичен, краток и работает — продолжайте читать.
И решение …
Пример решения представляет собой набросок, в котором рассматриваются все вышеперечисленные соображения и требования простым, лаконичным и элегантным образом.Следует отметить и основополагающее для его дизайна то, что метод разделяет инициирование переключения (процесс прерывания) и завершение переключения (то есть ожидание освобождения и управление устранением дребезга).
Также стоит упомянуть, что процесс чтения переключателя является неисключительным (неблокирующим) как при тестировании цифрового входа, так и при обработке дребезга. Такой подход позволяет скетчу делать другие вещи, даже когда переключатель может находиться в переходном состоянии.
Посмотрите на скетч, загрузите его и попробуйте.
Дальнейшее исследованиеЕсли вас устраивает эскиз и то, как он работает, почему бы не посмотреть, какие изменения могут потребоваться, если вы будете использовать другую схему переключателя? Например, тот, для которого не требуется резистор. Схема будет выглядеть, как показано на рисунке 3 ниже.
Как нужно изменить эскиз?
Подсказка: цифровой вывод считывания должен быть на + 5В (ВЫСОКИЙ), поскольку кнопочный переключатель будет вызывать протекание тока от цифрового вывода к земле при нажатии, что приведет к срабатыванию прерывания (переключатель будет подключен согласно circuit_C2, выше).Кроме того, в setup () для этого потребуется вызов переключателя pinMode с использованием параметра INPUTPULLUP, а не INPUT, и вызов attachinterrupt с использованием параметра «FALLING», а не «RISING».
Это все? Не совсем так, потому что в условиях разомкнутой цепи цифровой вывод будет читать HIGH, что означает, что переключатель открыт, и LOW, когда переключатель закрыт, — наоборот. Посмотрите, сможете ли вы с этим справиться, но если нет, ознакомьтесь с руководством по кнопочным переключателям ниже, которое должно помочь.
Больше изощренности Если вам понравилась эта статья и работа с ней, то посмотрите, как мы можем использовать единую процедуру обслуживания прерывания (ISR) для обработки любого количества переключателей виртуально, без каких-либо дополнительных проводов, превышающих количество переключатели, которые мы хотим настроить. Статья называется «Несколько переключателей, одно прерывание», и в ней используется библиотека ez_switch_lib
(см. Ниже, Дополнительная литература). Метод легко расширяется для использования любого количества переключателей, кнопок или переключателей и подключается по любой общей схеме подключения.
Вы также можете найти эти статьи того же автора интересными и полезными:
- Понимание и использование кнопочных переключателей, ОСНОВНЫЕ НАПРАВЛЕНИЯ — кнопочные переключатели, простой, но зачастую сложный элемент набора. Учебное пособие содержит подробные сведения о реализации простого кнопочного переключателя с возможностью гибкого изучения различий в конструкции схемы, различных методов чтения и устранения неполадок.
- Внешние прерывания, общая структура, поддерживающая одновременные множественные асинхронные прерывания.Настройте несколько внешних прерываний с разными характеристиками и добавьте код для обеспечения асинхронной обработки после прерывания.
Другие онлайн-ресурсы
Цифровые выводы
Обзор прерываний
наслаждайтесь!
Прерывания смены контактов Arduino Учебное пособие ISR
Полное руководство по управлению прерыванием смены контактов Arduino UNO ISR. Мы увидим регистры, которые нам нужно установить раньше, каковы векторы ISR и как выполнять прерывания.Это, например, позволит нам иметь обрывы на всех выводах на платах на базе Atmega328P. Но подождите, у Arduinos только 2 контакта прерывания , верно? Ну нет. Это контакты аппаратного прерывания. Мы ничего не говорим о контактах PCINT . В этом посте мы увидим, что такое прерывания смены пина (PCINT) и как они работают, прерывания отличаются от обычных прерываний (INT), к которым мы привыкли.
Часть 1 — Контакты ATmega328p-PU
Плата Arduino UNO использует микроконтроллер ATmega328p-PU.Эта ИС имеет 28 контактов и имеет корпус DIP. Но контакты IC не маркированы так же, как контакты платы Arduino UNO. Например, вывод D13 Arduino подключен к выводу 19 микросхемы Atmega328p. В любом случае, каждый из цифровых контактов связан с портом, а у нас их 3: PortB, PortC и PortD. Каждый порт управляется 8-битными регистрами, поэтому каждый порт может управлять 8 цифровыми выводами, поэтому каждый вывод помечен как от PB0 до PB7, как и от порта B 0 до порта B 7. Кроме того, как вы можете видеть ниже, каждый из этих выводов Цифровые контакты также связаны с другой меткой с именем PCINT , и это идет от PCINT1 до PCINT23. Итак, помните, что с каждым цифровым выводом будет связан бит PCINT. Но что это за PCINT?
Часть 2 — Что такое PCINT
С Arduino у нас есть двух типов прерываний, INT для внешнего аппаратного прерывания и PCINT для прерывания смены вывода. Сегодня мы рассмотрим эти последние, прерывания при смене контактов, а аппаратные прерывания оставим для будущего руководства.Аппаратные прерывания очень ограничены, например, на Arduino UNO только контакты 2 и 3 могут вызвать аппаратное прерывание . С другой стороны, прерывания PCINT действуют не только на один вывод, а на группу выводов, более известную как порт . Итак, помните из прошлого руководства, что Arduino UNO использует микроконтроллер ATmega328, и, как вы помните, ниже была его распиновка, и у нас было 3 порта, порт B, C и D. У нас есть несколько регистров, которые контролируют прерывания этих портов. .PCINT также имеет некоторые недостатки по сравнению с обычным INT.
Во-первых, если у нас есть единственный связанный вывод в каждом PCINT, мы можем легко определить, на какой вывод воздействовало прерывание. Но с PCINT у нас будет более одного вывода (порт ann может запускать ISR), и нам нужно будет выполнить последующий запрос и определить, какой контакт запускает ISR.
Во-вторых, в отличие от прерываний INT , которые позволяют настраивать триггеры CHANGE, FALLING, RISING, LOW и HIGH, прерывания INT распознают только события CHANGE.И, наконец, по этой причине они немного медленнее, чем прерывания INT. Но в целом это не то, что должно нас беспокоить, это несущественная разница, за исключением очень крайних случаев.
Если мы хотим обнаружить нарастающие или спадающие фронты, мы должны сохранить состояние регистра в переменной и провести сравнение с предыдущим состоянием в ISR.
Часть 3.1 — Но что такое прерывание?
Вы уже должны знать, что код Arduino — , последовательный , запускающий в серии , что означает, что пока одна инструкция не закончится, мы не сможем выполнить следующее прерывание.Например, в приведенном ниже коде мы запускаем 3 функции (1, 2 и 3) и считываем данные, вводимые с некоторых кнопок. Первый считывает температуру с термопары. Вторая функция вычисляет некоторые значения ПИД, а третья функция применяет результат ПИД к некоторым аналоговым выходам для управления нагревателем. Между функциями мы читаем состояние двух контактов, подключенных к некоторым кнопкам. Поскольку код Arduino является последовательным, очевидно, что функция 2 не будет работать, пока не завершится функция 1, а функция 3 не будет выполняться, пока не завершатся функции 1 и 2.Более того, если мы нажмем кнопку, пока функция 1 все еще работает, с приведенными ниже строками кода, мы не обнаружим, что кнопка была нажата, потому что цифровое чтение не будет выполняться до тех пор, пока не будут выполнены функции 1 и 2. Итак, как мы можем изменить переменную, используемую, например, в функции 3, когда мы все еще выполняем функцию 1. Для этого мы используем прерываний .
Часть 3.2 — Прерывание
Когда срабатывает прерывание, это приостанавливает выполнение кода в тот самый момент и переводит его в вектор прерывания.Здесь мы запускаем код прерывания, которым может быть что угодно, и когда это заканчивается, мы возвращаемся к коду и продолжаем работать с того же самого момента. С PCINT, если он активирован, каждый раз, когда INPUT изменяет свое значение с HIGH на LOW или с LOW на HIGH, будет срабатывать прерывание.
Часть 4 — Как использовать PCINT
Есть несколько регистров, задействованных в активации и использовании прерываний смены вывода.Мы рассмотрим процесс шаг за шагом, используя Atmega 328p в качестве эталона, поскольку он наиболее часто используется в Arduino Uno и Nano. Во-первых, давайте посмотрим, как включить или отключить PCINT для каждого контакта.
Часть 4.1 Включение / отключение PCINT
Во-первых, мы можем активировать или деактивировать PCINT, связанный с группой контактов с регистром PCICR (регистр управления прерыванием смены контактов). Здесь у нас есть 3 бита, которые управляют активацией или деактивацией PCINT для каждой группы контактов.Мы используем первые 3 бита этого регистра, где бит 0 предназначен для PCIE0, бит 1 — для PCIE1, а бит 2 — для PCIE2.
Бит 7 | Бит 6 | Бит 5 | Бит 4 | Бит 3 | Бит 2 | Бит 1 | Бит 0 |
PCIE2 | PCIE1 | PCIE0 |
Пример кода
void setup () {
PCICR | = B00000100; // Bit2 = 1 -> "PCIE2" включен (от PCINT16 до PCINT23)
}
void loop () {
// здесь ваш код...
}
Эти биты PCIE представляют бит разрешения прерывания при смене вывода, поэтому, если мы устанавливаем бит в 1, прерывания для этой группы активируются, если мы устанавливаем его в 0, ну, прерывания отключены. PCIE0 управляет группой контактов от PCINT0 до PCINT7. Если мы посмотрим на карту портов Arduino, мы увидим, что эти контакты прерывания подключены к контактам от цифрового вывода D8 до D13, которые являются битами от 0 до 5 порта B. PCIE1 управляет группой контактов для PCINT8 до PCINT14 и тех. соответствуют аналоговым контактам Arduino от A0 до A5.Наконец, PCIE2 управляет группой контактов для PCINT16 — PCINT23, и они соответствуют цифровым контактам Arduino D0 — D7.
Часть 4.2 Включить ИЛИ Отключить для вывода
Как только PCINT активируется для группы контактов, мы должны сказать, какие контакты этой группы могут вызвать прерывание. Для этого у нас есть регистры PCMSK0, PCMSK1 и PCMSK2 (маска изменения вывода), в которых каждый бит указывает, запускает ли вывод PCINT.Теперь установка бита PCINT в 1 означает, что вывод вызовет прерывание. Установка на 0 означает, что вывод не будет вызывать прерывание при смене вывода. ниже у вас есть регистры и биты каждого из них, чтобы выбрать любой из битов PCINT. См. Также пример кода ниже.
PCMSK0
БИТ | Бит 7 | Бит 6 | Бит 5 | Бит 4 | Бит 3 | Бит 2 | Бит 1 | Бит 0 |
PCINT | PCINT7 | PCINT6 | PCINT5 | PCINT4 | PCINT3 | PCINT2 | PCINT1 | PCINT0 |
Штырь Arduino | Cristal2 | Cristal1 | D13 | D12 | D11 | D10 | D9 | D8 |
PCMSK1
БИТ | Бит 7 | Бит 6 | Бит 5 | Бит 4 | Бит 3 | Бит 2 | Бит 1 | Бит 0 |
PCINT | – | PCINT14 | PCINT13 | PCINT12 | PCINT11 | PCINT10 | PCINT9 | PCINT8 |
Штырь Arduino | – | Сброс | A5 | A4 | A3 | A2 | A1 | A0 |
PCMSK2
БИТ | Бит 7 | Бит 6 | Бит 5 | Бит 4 | Бит 3 | Бит 2 | Бит 1 | Бит 0 |
PCINT | PCINT23 | PCINT22 | PCINT21 | PCINT20 | PCINT19 | PCINT18 | PCINT17 | PCINT16 |
Штырь Arduino | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
Пример кода
Хорошо, как вы можете видеть ниже, сначала, как в примере перед активацией PCINT для группы PCIE2 с первой строкой кода.Но затем во второй строке кода мы делаем цифровой вывод D5, чтобы иметь возможность запускать прерывание. Мы устанавливаем бит 5 регистра PCMSK2 в 1, поэтому PCINT21 включен и представляет собой цифровой вывод D5, как вы можете видеть в таблицах выше.
void setup () {
PCICR | = B00000100; // Bit2 = 1 -> "PCIE2" включен (от PCINT16 до PCINT23)
PCMSK2 | = B00100000; // Bit5 = 1 -> "PCINT21" включен -> D5 вызовет прерывание
}
void loop () {
// здесь ваш код...
}
Часть 4.3 Очистить флаг прерывания
С другой стороны, у нас есть регистр PCIFR (регистр флага прерывания смены вывода). Биты этого регистра активируются каждый раз, когда происходит изменение вывода группы. Чтобы сбросить флаг bhis, мы должны поставить «1» в соответствующий регистр. Флаги автоматически сбрасываются при срабатывании связанной ISR. Так, например, если D5 вызывает прерывание, флаг для PCIF2 сбрасывает 0, потому что вывод D5 от PCMSK2.
PCIFR
БИТ | Бит 7 | Бит 6 | Бит 5 | Бит 4 | Бит 3 | Бит 2 | Бит 1 | Бит 0 |
PCINT | – | – | – | – | – | PCIF2 | PCIF1 | PCIF0 |
ПОРТ Arduino | – | – | – | – | – | ПОРТ B | ПОРТ C | ПОРТ D |
Часть 4.4 Определите ISR
Хорошо, теперь мы знаем, как установить контакты, чтобы иметь возможность вызывать прерывания. Но, как вы помните, при срабатывании прерывания мы приостанавливаем выполнение основного кода и переходим к вектору прерывания, где выполняем код для этого прерывания. Так что же это за вектор прерывания. Итак, каждая из 3 групп контактов имеет ISR или процедуру обслуживания прерывания . Это цикл в коде, который будет выполняться при срабатывании флага прерывания.Для этого в коде мы определяем ISR, а затем добавляем вектор. У нас есть 3 вектора: вектор PCINT0 для выводов от D8 до D13, вектор PCINT1 для выводов от A0 до A5 и вектор PCINT2 для выводов от D0 до D7.
• ISR (PCINT0_vect) для группы контактов от D8 до D13
• ISR (PCINT1_vect) для группы контактов от A0 до A5
• ISR (PCINT2_vect) для группы выводов от D0 до D7
Теперь у нас есть все элементы, необходимые для объяснения того, как работают прерывания при смене вывода. Подводя итог всему вышесказанному, в предыдущем примере мы установили цифровой вывод D5 для запуска прерывания.Итак, мы должны добавить код для ISR PCINT2_vect . Итак, в коде после или до цикла void мы добавляем следующие строки. Это цикл прерывания для порта D. Между скобками мы добавляем наш код прерывания. После выполнения этих строк флаг прерывания возвращается к «1», и эти строки кода не будут выполняться снова, пока не сработает другое прерывание вывода D5.
Пример кода
ISR (PCINT2_vect)
{
// Для PCINT контактов D0 и D7
}
Часть 5 — Пример полного ISR
Мы хотим, чтобы вывод D5 запускал прерывание при смене вывода.В приведенном ниже коде с первой строкой в настройке void мы включаем PCIE2, потому что D5 соответствует этой группе. Во второй строке мы указываем, что PCINT21 вызовет прерывание, потому что D5 представлен группой taht. Все настроено, и нам нужно определить вектор ISR. К выводу D5, который поступает из порта D, соответствует ISR вектор 2. Поэтому мы определяем ISR PCINT2_vect. Между этими скобками мы определяем код нашего прерывания.
Пример кода
void setup () {
PCICR | = B00000100; // Bit2 = 1 -> "PCIE2" включен (от PCINT16 до PCINT23)
PCMSK2 | = B00100000; // Bit5 = 1 -> "PCINT21" включен -> D5 вызовет прерывание
}
void loop () {
// здесь ваш код...
}
ISR (PCINT2_vect)
{
// Для PCINT контактов D0 и D7
}
Часть 6.1 — Имейте в виду (2 PCINT из одного порта)
Хорошо, теперь кое-что нужно иметь в виду. Если вы установите, например, контакты 4 и 5, которые относятся к тому же порту , , для запуска прерываний, без консультации с тем, какой контакт создал прерывание, вы, возможно, не сможете узнать, какой из двух контактов инициировал ISR.Если вывод 4 произвел прерывание, мы переходим к ISR вектора 2. Если вывод 5 произвел прерывание, , мы также переходим к ISR вектора 2 . Вот почему при использовании прерываний ПК одного и того же порта мы всегда должны проверять, какой вывод изменил свое значение. Чтобы определить, что мы должны сохранить предыдущее значение, используя глобальную переменную, и каждый раз сравнивать это значение. Мы должны сделать то же самое, если хотим обнаруживать нарастающие или падающие фронты входных данных. Зная предыдущее и фактическое состояние пина, мы можем определить, когда он перешел от высокого к низкому или от низкого к высокому.
Пример кода
bool D4_state = LOW;
bool D5_state = LOW;
void setup () {
PCICR | = B00000100; // Bit2 = 1 -> "PCIE2" включен (от PCINT16 до PCINT23)
PCMSK2 | = B00110000; // D4 и D5 вызовут прерывание
}
void loop () {
// ваш код здесь ...
}
ISR (PCINT2_vect)
{
if (digitalRead (4) && D4_state) {
D4_state = ВЫСОКИЙ;
// Вывод D4 вызвал ISR
}
else if (digitalRead (4) &&! D4_state) {
D4_state = НИЗКИЙ;
}
if (digitalRead (5) && D5_state) {
D5_state = ВЫСОКИЙ;
// Вывод D5 вызвал ISR
}
else if (digitalRead (5) &&! D5_state) {
D5_state = НИЗКИЙ;
}
}
Часть 6.2 — Имейте в виду (2 PCINT из одного порта)
Еще одна вещь, о которой нужно помнить. Когда мы находимся внутри прерывания, остальные прерывания ставятся на паузу. Это означает, что если один вывод вызывает прерывание, а всего через несколько мгновений другой вывод вызывает другое прерывание, в то время как мы все еще выполняем первую процедуру прерывания, второе прерывание не сработает.
В заключение, мы должны сделать процедуру ISR как можно быстрее. Поэтому я рекомендую вам просто изменить значения переменных в подпрограмме ISR, а затем позволить всем остальным вычислениям, решениям и т. Д. Выполняться в цикле void.Таким образом, прерывание происходит как можно быстрее. По той же причине, если прерывание слишком долгое, помните, что во время прерывания остальная часть кода находится в режиме паузы. Так что, если вы контролируете положение шагового двигателя. Если прерывание слишком долгое, возможно, двигатель достиг конца своего пути, но вы не можете остановить его вращение, пока прерывание не закончится, так что это приведет к чему-то плохому.
Часть 6.3 — Имейте в виду (миллис и микрометры)
Другое дело, что во время выполнения прерывания Ардуино не обновляет значение миллис и микросхемы функции .Таким образом, время выполнения ISR не учитывается, и у Arduino есть временная задержка. Для подсчета времени между двумя прерываниями можно использовать функцию «миллис» и «микросхема». Но во время прерывания время не обновляется. Я хочу сказать, что вы можете использовать, например, функцию millis внутри ISR. Но его значением будет то значение, которое оно имело во время срабатывания прерывания. Как следствие, функция задержки не работает, потому что ее работа основана на функции millis. Функция микросхемы обновляет свое значение в пределах ISR, но начинает давать неточные измерения времени за пределами диапазона 500 мкс.В результате функция delayMicroseconds работает в этом временном диапазоне, хотя нам следует избегать ее использования, потому что мы не должны вводить задержки в ISR.
, часть 7 — см. Видео
Итак, теперь вы знаете, как настроить прерывания при смене вывода. Пожалуйста, просмотрите все примеры в этом посте для получения более подробной информации и сверьтесь с таблицей данных микросхемы ATmega. Следите за новостями, чтобы увидеть больше видео об Arduino 101 в ближайшее время. Я надеюсь, что вы узнали что-то новое. Если да, то, возможно, поставьте лайк на видео ниже и подумайте о подписке.Если мои видео вам помогут, подумайте о поддержке моей работы над PATREON или о пожертвовании через PayPal. Еще раз спасибо и увидимся позже, ребята.
Контакты внешних прерываний ESP32 в Arduino
В этом руководстве вы узнаете о выводах внешних прерываний ESP32 в Arduino Core. Как использовать прерывания и написать свою процедуру обслуживания прерываний (ISR) для внешних контактов прерывания GPIO.Это очень полезная функция для уведомления ЦП ESP32 о наступлении определенного события и немедленного ответа на это событие.
Затем мы перейдем к библиотекам Arduino Core, которые реализуют драйверы для контактов прерывания ESP32 и способы использования его функций API, таких как attachInterrupt (). Без лишних слов, давайте перейдем к делу!
Требования для этого учебника
Предварительные знания
Программные инструменты
Аппаратные компоненты
Вы можете получить полный комплект курсов для этой серии учебных пособий, используя ссылку ниже.Или просто обратитесь к таблице, где указаны точные компоненты, которые будут использоваться в практических лабораториях только для этого конкретного руководства.
Контакты внешних прерываний (IRQ)
В большинстве микроконтроллеров есть несколько выделенных контактов GPIO, которые могут генерировать события прерывания. Обычно их называют выводами IRQ или выводами внешнего прерывания.
Когда логическое состояние вывода внешнего прерывания изменяется, он посылает сигнал прерывания в ЦП. Таким образом, ЦП приостанавливает выполнение основной программы и переходит к обработке определенной процедуры (или функции), обычно называемой программой обслуживания прерывания (ISR).
ISR всегда должна быть короткой с минимальными логическими операциями и вычислениями, потому что это будет происходить часто, поэтому выполнение основной программы будет приостановлено на более длительные периоды времени. Что потенциально может повредить временному поведению вашей системы.
Пример использования контактов внешнего прерывания
Мы можем использовать контакты внешнего прерывания в различных ситуациях, начиная от простого уведомления, когда датчик PIR обнаруживает движение кого-то в комнате. И вплоть до выполнения некоторых измерений и вычислений, таких как измерение частоты цифрового датчика, такого как «Оптический энкодер» для измерения скорости двигателя (об / мин).
Как вы можете видеть на диаграмме, показанной выше, вращение двигателя заставляет оптический кодировщик генерировать прямоугольный сигнал. Считывая (измеряя) частоту этого сигнала, мы можем определить скорость двигателя (об / мин).
Цифровой сигнал измеряется в этом примере приложения с помощью внешнего вывода прерывания + модуля таймера. По первому нарастающему фронту происходит прерывание, поэтому ЦП приостанавливает выполнение основной программы и запускает модуль таймера, а затем возобновляет выполнение основной программы.
При следующем нарастающем фронте срабатывает прерывание, ЦП приостанавливает выполнение основной программы и останавливает таймер. Теперь счетчик таймера может сказать нам общее время (T) или период сигнала. Чтобы получить частоту, мы сделаем (F = 1 / T), и все готово.
Мы реализуем именно эту систему в будущем руководстве, поэтому время от времени проверяйте эту серию руководств.
Контакты внешних прерываний ESP32
Прерывания ESP32
В матрице прерываний ESP32 так много разных источников прерываний.Матрица прерываний, встроенная в ESP32, независимо распределяет периферийные источники прерываний для периферийных прерываний двух ЦП.
Он принимает 71 периферийный источник прерываний в качестве входных данных. И он генерирует 26 периферийных источников прерываний на каждый ЦП на выходе (всего 52).
Прерывания в ESP32 подразделяются на аппаратные прерывания и программные прерывания.
- Аппаратные прерывания — прерывания, которые инициируются аппаратными периферийными устройствами или источниками.Это могут быть: Внутренний или Внешний . Примером внутренних аппаратных прерываний может быть что-то вроде прерывания аппаратного таймера или WDT. Примером внешнего аппаратного прерывания являются прерывания от внешних выводов GPIO (тема этого руководства).
- Программные прерывания — прерывания, которые запускаются пользователем, программистами. Вручную вставляется в определенные части кода, чтобы указать что-то или выполнить запрос ввода-вывода или что-то в этом роде.
Выводы GPIO прерывания ESP32
Все выводы GPIO ESP32 являются выводами, способными обрабатывать прерывания.Вы можете включить функцию прерывания для любого входного контакта GPIO, используя эту функцию из ядра Arduino.
attachInterrupt (GPIO_pin, ISR, событие); |
См. Эту распиновку платы разработчика ESP32.
(если не ясно, щелкните правой кнопкой мыши и откройте его в новой вкладке для увеличения)
ESP32 События запуска внешнего прерывания
Существует 5 различных событий, запускающих прерывание для каждого вывода внешнего прерывания.Вы можете программно выбрать событие, при котором будет срабатывать прерывание, в соответствии с приложением. Это следующие события:
RISING | Прерывание запускается на каждом Rising Edge |
FALLING | Прерывание запускается на каждом Falling Edge |
HIGH | Прерывание срабатывает всякий раз, когда на выводе находится ВЫСОКИЙ |
НИЗКИЙ | Прерывание запускается всякий раз, когда на выводе НИЗКОЕ значение |
ИЗМЕНЕНИЕ | Прерывание запускается при изменении состояния вывода с высокого на низкое. или с НИЗКОГО на ВЫСОКИЙ |
ESP32 Отключение внешнего прерывания
Конечно, вы можете отключить функцию внешнего прерывания для любого вывода прерывания, когда захотите в вашем коде.Используя эту функцию из Arduino Core, вы можете отключить любой внешний вывод прерывания.
detachInterrupt (GPIO_pin); |
ESP32 Внешнее прерывание ISR
Как мы заявляли ранее, ISR (процедура обслуживания прерывания) — это специальная функция, которую ЦП начинает выполнять в ответ на событие прерывания. ЦП приостанавливает выполнение основной программы для обработки ISR, поэтому это должен быть легкий фрагмент кода.
Чтобы определить функцию ISR, вы должны использовать следующий формат:
void IRAM_ATTR Ext_INT1_ISR () { // Ваш код … } |
Идентификатор IRAM_ATTR рекомендуется Espressif для размещения этого фрагмента кода во внутренней оперативной памяти, а не во флеш-памяти. Таким образом, он будет выполняться намного быстрее и приведет к очень быстрому переключению контекста и обслуживанию прерывания.Мы также измерим это к концу этого урока.
Код внешних прерываний ESP32 (в Arduino)
В этом разделе я дам вам пошаговый подход к тому, что делать, чтобы настроить и инициализировать внешний вывод прерывания и назначить его в функцию обработчика ISR.
Step1 — Выберите входной вывод GPIO внешнего прерывания, который вы собираетесь использовать.
Step2 — Определите событие запуска прерывания, которое вам необходимо.(RISING — FALLING — HIGH — LOW — CHANGE)
Step3 — Инициализируйте этот входной контакт GPIO и присоедините к нему прерывание в функции настройки
void setup () { pinMode (GPIO_pin ВХОД); attachInterrupt (GPIO_pin, Ext_INT1_ISR, RISING); } |
Step4 — Теперь напишите свою собственную функцию ISR. Что вы хотите сделать, когда этот входной контакт имеет нарастающий фронт?
void IRAM_ATTR Ext_INT1_ISR () { // Что-нибудь сделать… } |
И все!
Давайте сделаем несколько практических примеров LAB, чтобы проверить это.
Компоненты для лабораторий этого руководства
* Раскрытие информации для аффилированных лиц: когда вы нажимаете на ссылки в этом разделе и совершаете покупку, это может привести к тому, что этот сайт получит комиссию. Партнерские программы и присоединения включают, помимо прочего, партнерскую сеть eBay (EPN) и Amazon.com, Banggood.com. Это может быть одним из способов поддержки этой бесплатной платформы при получении ваших обычных заказов на электронные компоненты, как обычно, без каких-либо дополнительных затрат для вас.