Ардуино прерывания по кнопке. Аппаратные прерывания в Arduino: использование и примеры

Что такое аппаратные прерывания в Arduino. Как работают прерывания на платах Arduino Uno, Mega, Nano. Каковы особенности использования функции attachInterrupt(). Какие есть типы аппаратных прерываний в Arduino. Как реализовать обработку прерываний от кнопки и таймера.

Содержание

Что такое аппаратные прерывания в Arduino

Аппаратные прерывания — это механизм, позволяющий микроконтроллеру Arduino реагировать на внешние события асинхронно, не затрагивая основной цикл программы. Прерывания позволяют обрабатывать важные события сразу при их возникновении, не тратя ресурсы на постоянный опрос.

Основные особенности аппаратных прерываний в Arduino:

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

Типы аппаратных прерываний в Arduino

В Arduino существует 4 основных типа аппаратных прерываний:


  1. LOW — срабатывает, когда на пине низкий уровень сигнала
  2. CHANGE — срабатывает при любом изменении сигнала
  3. RISING — срабатывает при изменении сигнала с низкого на высокий
  4. 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(). Ее синтаксис:


attachInterrupt(interrupt, function, mode);

Где:

  • interrupt — номер прерывания
  • function — функция-обработчик прерывания
  • mode — режим срабатывания (LOW, CHANGE, RISING, FALLING)

Важные особенности при использовании attachInterrupt():

  • Функция-обработчик должна быть без параметров и возвращаемого значения
  • В обработчике нельзя использовать delay() и другие блокирующие функции
  • Обработчик должен быть максимально коротким
  • Переменные, изменяемые в обработчике, нужно объявлять как volatile

Пример обработки прерывания от кнопки

Рассмотрим простой пример использования прерывания для обработки нажатия кнопки:

«`cpp const int buttonPin = 2; const int ledPin = 13; volatile bool buttonPressed = false; void setup() { pinMode(ledPin, OUTPUT); pinMode(buttonPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(buttonPin), buttonInterrupt, FALLING); } void loop() { if (buttonPressed) { digitalWrite(ledPin, HIGH); delay(1000); digitalWrite(ledPin, LOW); buttonPressed = false; } } void buttonInterrupt() { buttonPressed = true; } «`

В этом примере:


  • Прерывание настроено на пин 2 по спаду сигнала (FALLING)
  • При нажатии кнопки вызывается обработчик buttonInterrupt()
  • Обработчик просто устанавливает флаг buttonPressed
  • Основной цикл проверяет флаг и при необходимости включает светодиод

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

Помимо внешних прерываний, в Arduino можно использовать прерывания по таймеру. Они позволяют выполнять действия через заданные промежутки времени.

Пример использования прерывания по таймеру:

«`cpp #include const int ledPin = 13; void setup() { pinMode(ledPin, OUTPUT); Timer1.initialize(1000000); // 1 секунда Timer1.attachInterrupt(timerInterrupt); } void loop() { // Основной код программы } void timerInterrupt() { static bool ledState = false; ledState = !ledState; digitalWrite(ledPin, ledState); } «`

В этом примере:

  • Используется библиотека TimerOne для настройки прерывания
  • Прерывание настроено на срабатывание каждую секунду
  • В обработчике происходит переключение состояния светодиода

Преимущества и недостатки использования прерываний

Преимущества использования прерываний в Arduino:


  • Мгновенная реакция на события
  • Экономия ресурсов процессора
  • Возможность обработки коротких импульсов
  • Упрощение кода для некоторых задач

Недостатки и ограничения прерываний:

  • Усложнение структуры программы
  • Необходимость учитывать возможные конфликты между прерываниями
  • Ограничения на код внутри обработчиков прерываний
  • Возможные проблемы с дребезгом контактов

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

Заключение

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

При правильном применении прерывания помогают решать такие задачи, как:

  • Обработка сигналов от датчиков
  • Точное измерение временных интервалов
  • Реализация протоколов связи
  • Управление двигателями и сервоприводами
  • Создание многозадачных систем

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



Arduino прерывания по кнопке

  • Уроки
  • Базовые уроки Arduino
  • Аппаратные прерывания

Аппаратные прерывания

Забавную картинку к этому уроку я найти не смог, нашёл только какую-то лекцию по программированию, и вот самое начало этой лекции отлично объясняет нам, что такое прерывание. Прерывание в Ардуино можно описать абсолютно точно так же: микроконтроллер “всё бросает”, переключается на выполнение блока функций в обработчике прерывания, выполняет их, а затем возвращается ровно к тому месту основного кода, в котором остановился.

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

External hardware interrupt – это прерывание, вызванное изменением напряжения на пине микроконтроллера. Основная суть состоит в том, что микроконтроллер (вычислительное ядро) не занимается опросом пина и не тратит на это время, пином занимается другая “железка”. Как только напряжение на пине изменяется (имеется в виду цифровой сигнал, +5 подали/+5 убрали) – микроконтроллер получает сигнал, бросает все дела, обрабатывает прерывание, и возвращается к работе. Зачем это нужно? Чаще всего прерывания используются для детектирования коротких событий – импульсов, или даже для подсчёта их количества, не нагружая основной код. Аппаратное прерывание может поймать короткое нажатие кнопки или срабатывание датчика во время сложных долгих вычислений или задержек в коде, т.е. грубо говоря – пин опрашивается параллельно основному коду. Также прерывания могут будить микроконтроллер из режимов энергосбережения, когда вообще практически вся периферия отключена. Посмотрим, как работать с аппаратными прерываниями в среде Arduino IDE.

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

Начнём с того, что не все пины “могут” в прерывания. Да, есть такая штука, как pinChangeInterrupts, но о ней мы поговорим в продвинутых уроках. Сейчас нужно понять, что аппаратные прерывания могут генерировать только определённые пины:

МК / номер прерывания
INT 0INT 1INT 2INT 3INT 4INT 5
ATmega 328/168 (Nano, UNO, Mini)D2D3
ATmega 32U4 (Leonardo, Micro)D3D2D0D1D7
ATmega 2560 (Mega)D2D3D21D20D19D18

Как вы поняли из таблицы, прерывания имеют свой номер, который отличается от номера пина. Есть кстати удобная функция 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 0INT 1INT 2INT 3INT 4INT 5
ATmega 328/168 (Nano, UNO, Mini)D2D3
ATmega 32U4 (Leonardo, Micro)D3D2D0D1D7
ATmega 2560 (Mega)D2D3D21D20D19D18

Как вы поняли из таблицы, прерывания имеют свой номер, который отличается от номера пина. Есть кстати удобная функция 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

Pin3

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», и, если он включен, для определенного контакта он будет вызывать прерывание каждый раз, когда состояние этого контакта изменяется (с высокого до низкого / от низкого до высокого).

Во-вторых, ваш подход должен выглядеть примерно так:

  1. включить прерывание смены контактов на 6 нужных контактах
  2. включить глобальные прерывания
  3. когда вызывается прерывание, проверьте состояние ввода, чтобы определить изменение и сохранить состояние кнопки

Вам понадобится таблица данных, так что вот ярлык: 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

 В программе организован спящий режим микроконтроллера, из которого его можно вывести прижав вывод INT0 к земле. Это делается нажатием любой кнопки. В обработчике прерывания происходит сканирование портов МК к которым подключены кнопки и если на одном из них ноль — значит нажата эта самая кнопка. Дальше присваиваем некой переменной значение соответствующее нажатой кнопки, мигаем светодиодом и уходим в основной цикл, где печатаем номер кнопки и снова даем команду микроконтроллеру «уснуть».

 Номер кнопки в примере печатается в терминал на скорости 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. Это может быть одним из способов поддержки этой бесплатной платформы при получении ваших обычных заказов на электронные компоненты, как обычно, без каких-либо дополнительных затрат для вас.


ESP32 Пример внешнего прерывания Переключить GPIO — LAB

13 9036 GPIO Pins Определите выходной контакт (для светодиода)
  • Определите входной контакт и прикрепите к нему прерывание
  • Напишите функцию ISR для переключения вывода светодиода на каждом Восходящем крае
  • Схема подключения

    Внешние контакты прерывания ESP32 — Код Пример

    В приведенном ниже примере кода выполняется следующее: Мы начинаем с определения вывода светодиода GPIO (GPIO5), входного вывода для внешнего прерывания (GPIO35) и прикрепляем к нему прерывание ().Затем мы переключим вывод светодиода в программе обработчика ISR.

    Полный листинг кодов

    Номер LAB 12
    Имя LAB ESP32 Внешнее прерывание

    1

    2

    3

    4

    5

    6

    7

    8

    9

    100004 13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    9007

    900

    * LAB: 12 ​​

    * Имя: ESP32 External Interrupts

    * Автор: Khaled Magdy

    * Для получения дополнительной информации посетите: www.DeepBlueMbedded.com

    * /

    #define Btn1_GPIO 35

    #define LED1_GPIO 5

    void IRAM_ATTR Ext_INT1_ISR ()

    LED1_ISR ()

    //

    LEDIO ));

    }

    void setup ()

    {

    pinMode (LED1_GPIO, OUTPUT);

    pinMode (Btn1_GPIO, INPUT);

    attachInterrupt (Btn1_GPIO, Ext_INT1_ISR, RISING);

    }

    void loop ()

    {

    // Ничего не делать…

    }

    Выберите плату, COM-порт, удерживайте кнопку BOOT, нажмите кнопку загрузки и удерживайте палец на кнопке BOOT. Когда IDE Arduino начнет отправлять код, вы можете отпустить кнопку и дождаться завершения процесса перепрошивки. Теперь на ESP32 установлена ​​новая прошивка.

    Демо-видео для результата

    Обратите внимание, что вывод светодиода иногда будет переключаться случайным образом из-за проблемы с подпрыгиванием кнопки.Это можно решить, добавив небольшой RC-фильтр или схему устранения дребезга триггера Шмитта. Любое аппаратное решение будет работать так же хорошо.

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


    Измерение задержки прерывания ESP32 — LAB

    Номер LAB 13
    Имя LAB ESP32

    00 Измерение задержки прерывания 929 Задержка — время, необходимое ЦП для ответа на определенный сигнал прерывания.Это мера времени отклика на прерывание, и желательно, чтобы оно было как можно меньше. После приема сигнала прерывания ЦП приостанавливает выполнение текущего основного кода, сохраняет контекст, переключает контекст на ISR, выполняет код ISR, переключает контекст обратно на основной и, наконец, возобновляет выполнение основного кода.

    Это займет некоторое время, и желательно, чтобы оно было как можно меньше. Время между сигналом аппаратного прерывания и началом выполнения ISR (задержка прерывания) — это то, что мы собираемся измерить в этой лаборатории.

    Измерение задержки прерывания ESP32 — пример кода

    То же, что и предыдущая LAB.

    Снимок экрана с результатом

    Это примерно 1,8 мкс. Это действительно довольно быстро, процессору потребовалось всего 1,8 мкс, чтобы отреагировать на прерывание от внешней кнопки ввода и изменить состояние вывода светодиода GPIO. Обратите внимание, что этот тест проводился с процессором, работающим на частоте 240 МГц. Работа на более низкой частоте процессора определенно увеличит время, необходимое для ответа на сигнал прерывания.


    Приложения внешних прерываний ESP32

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

    Связанные руководства на основе контактов внешних прерываний ESP32

    • ESP32 + Измерение оборотов двигателя с оптическим энкодером
    • Обнаружение движения датчиков ESP32 и PIR
    • 9000 SR5 ESP12 Ultrason32 и HC-902 Подробнее…

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


    Считаете ли вы это полезным? Если да, пожалуйста, поддержите эту работу и поделитесь этими уроками!

    Следите за новостями о предстоящих уроках и не забудьте ПОДЕЛИТЬСЯ этими уроками. И подумайте о ПОДДЕРЖКЕ этой работы, чтобы продолжать публиковать бесплатный контент именно так!

    Нравится:

    Нравится Загрузка…

    Связанные

    ESE205 Wiki

    Добро пожаловать на вики-страницу ESE205!

    Введение в инженерное проектирование [1] — это курс, где группы из двух или трех студентов творчески решают одну задачу в течение семестра, используя инструменты из области электротехники и системотехники. Каждая группа выбирает собственное расписание и работает вместе с ассистентом преподавателя.

    Это веб-страница, на которой мы делимся своими проектами и результатами.Начни творить!

    Новости

    • 19 апреля: Демонстрационная и стендовая сессия.
    • 14 января: Первый класс
    • 14 января: Требуется первоначальное обследование

    Общая информация

    Среда, 23 января, до 15:00 Элементарная идея проекта
    Срок подачи запроса на учетную запись Wiki
    Пятница, 25 января, до 20:00 Определения групп и вики-страница проекта
    Пятница, 1 февраля Учебники для различных групп
    Проект предложения на Wiki до 15:00
    Среда, 13 февраля Предложение завершено в Wiki к 18:00
    Пятница, 15 и 22 февраля: 15-е: Busybear, Cocktail Maker, Harp, Matchmaking, Smarter Blind
    22-е: Headband Helper, Hoverbear, Nest, Smarter Door
    Пятница, 1, 8, 29 марта БЕЗ УРОКА В 15:00, но продолжайте еженедельные собрания
    Среднесрочная самооценка, Принесите на неделю собрания группы 4 марта
    Пятница, 5 апреля Черновик раздела «Дизайн и решения» финального проекта на вики.
    КЛАСС: Плакат и подготовка демонстрации.
    Пятница, 19 апреля Доступен черновик плаката для ТА и инструктора
    Пятница, 9 апреля 1380 19 26 с 14:30 до 16:00 Демонстрация и стендовая сессия — ДАТА ИЗМЕНЕНА
    Понедельник, 29 апреля, полдень Окончательная версия wiki due (включает все записи журнала, окончательный отчет, руководство)
    Среда, 1 мая Wiki заблокирована, срок возмещения, окончательная самооценка
    Пятница, 3 мая Окончательная проверка от ТА
    • Лаборатория : Урбауэр Холл 015.Поднимитесь по северной лестнице Урбауэра в подвал и поверните направо. Затем идите налево. Принесите свою карту-ключ WUSTL для доступа.

    Список литературы

    Внешние прерывания ATmega328P — Arxterra

    Чтение

    Микроконтроллер AVR и встроенные системы с использованием сборки и C
    Мухаммеда Али Мазиди, Сармада Наими и Сепера Наими

    Разделы: 10.3, 10.5

    Внешние прерывания

    • Обзор прерываний ATmega328P Примечания к лекциям стр. 4 «Основы работы с прерываниями»
    • Внешние прерывания запускаются выводами INT0 и INT1 или любым из PCINT23..0 штифты
    • 23 прерывания при смене контакта сопоставлены с 23 контактами порта ввода-вывода общего назначения:
    Группа портов B PCINT7 (PB7) PCINT0 (PB0)
    Порт C Группа PCINT15 (PC7) PCINT14 (PC6) PCINT8 (PC0)
    Порт D Группа PCINT23 (PD7) PCINT16 (PD0)

    Рисунок 1: Распиновка ATmega328P

    Таблица векторов прерываний ATmega328P

    Вектор No Программный адрес Источник Определение прерывания Arduino / C ++ ISR () Имя вектора макроса
    1 0x0000 СБРОС Сброс
    2 0x0002 INT0 Внешний запрос прерывания 0 (вывод D2) (INT0_vect)
    3 0x0004 ИНТ1 Внешний запрос прерывания 1 (вывод D3) (INT1_vect)
    4 0x0006 PCINT0 Запрос прерывания изменения контакта 0 (контакты D8 — D13) (PCINT0_vect)
    5 0x0008 PCINT1 Запрос прерывания смены контакта 1 (контакты A0 — A5) (PCINT1_vect)
    6 0x000A PCINT2 Запрос прерывания смены контакта 2 (контакты D0 — D7) (PCINT2_vect)
    7 0x000C WDT Прерывание тайм-аута сторожевого таймера (WDT_vect)
    8 0x000E ТАЙМЕР2 КОМПА Таймер / счетчик2 Сравнить совпадение A (TIMER2_COMPA_vect)
    9 0x0010 ТАЙМЕР2 КОМПБ Таймер / счетчик2 Сравнить совпадение B (TIMER2_COMPB_vect)
    10 0x0012 ТАЙМЕР2 OVF Переполнение таймера / счетчика 2 (TIMER2_OVF_vect)
    11 0x0014 ТАЙМЕР1 КАПТ Таймер / счетчик1 захват события (TIMER1_CAPT_vect)
    12 0x0016 ТАЙМЕР1 КОМПА Таймер / Счетчик1 Сравнить совпадение A (TIMER1_COMPA_vect)
    13 0x0018 ТАЙМЕР1 КОМПБ Таймер / Счетчик1 Сравнить совпадение B (TIMER1_COMPB_vect)
    14 0x001A ТАЙМЕР1 OVF Таймер / Счетчик1 Переполнение (TIMER1_OVF_vect)
    15 0x001C ТАЙМЕР0 КОМПА Таймер / Счетчик 0 Сравнить совпадение A (TIMER0_COMPA_vect)
    16 0x001E ТАЙМЕР0 КОМПБ Таймер / Счетчик 0 Сравнить совпадение B (TIMER0_COMPB_vect)
    17 0x0020 ТАЙМЕР0 OVF Таймер / Счетчик 0 Переполнение (TIMER0_OVF_vect)
    18 0x0022 SPI, STC Последовательная передача SPI завершена (SPI_STC_vect)
    19 0x0024 USART, RX USART, Rx Complete (USART_RX_vect)
    20 0x0026 USART, UDRE USART, регистр данных пуст (USART_UDRE_vect)
    21 0x0028 USART, Техас USART, Tx Complete (USART_TX_vect)
    22 0x002A АЦП Преобразование АЦП завершено (ADC_vect)
    23 0x002C EE ГОТОВ EEPROM готов (EE_READY_vect)
    24 0x002E АНАЛОГОВЫЙ КОМП Аналоговый компаратор (ANALOG_COMP_vect)
    25 0x0030 TWI 2-проводный последовательный интерфейс (I2C) (TWI_vect)
    26 0x0032 SPM ГОТОВ Сохранение памяти программ готово (SPM_READY_vect)

    ATmega328P Контроль внешнего прерывания

    • Прерывания INT0 и INT1 могут быть вызваны низким логическим уровнем, изменением логики и спадающим или нарастающим фронтом.

      Рисунок 2: Регистр управления внешним прерыванием A

    • Он настроен, как указано в спецификации для регистра управления внешним прерыванием A — EICRA, как определено в разделе 12.2.1 EICRA таблицы данных. Число «n» может быть 0 или 1.
    ISCn1 ISCn0 Режим Arduino Описание
    0 0 НИЗКИЙ Низкий уровень INTn генерирует запрос прерывания
    0 1 ИЗМЕНИТЬ Любое логическое изменение в INTn генерирует и прерывает запрос
    1 0 ПАДЕНИЕ Задний фронт INT0 генерирует запрос прерывания
    1 1 ПОДЪЕМ Нарастающий фронт INT0 генерирует запрос прерывания

    ATmega328P Разрешение внешнего прерывания

    • Всем прерываниям назначаются отдельные биты разрешения, которые должны быть записаны в логическую единицу вместе с битом разрешения глобального прерывания в регистре состояния (SREG), чтобы разрешить прерывание.

      Рисунок 3: Регистр состояния

    • ATmega 328P поддерживает два внешних прерывания, которые индивидуально разрешаются установкой битов INT1 и INT0 в регистре маски внешнего прерывания (раздел 12.2.2 EIMSK).

      Рисунок 4: Регистр маски внешнего прерывания

    • Давайте посмотрим на пример. Когда изменение фронта или логики на выводе INT0 вызывает запрос прерывания, INTF0 становится установленным (единица). Если бит I в SREG и бит INT0 в EIMSK установлены (единица), MCU перейдет к соответствующему вектору прерывания.Флаг сбрасывается при выполнении процедуры прерывания.

      Рисунок 5: Регистр флага внешнего прерывания

    • В качестве альтернативы, флаг можно сбросить, записав в него логическую единицу. Регистр EIFR находится в пределах диапазона адресов ввода-вывода (от 0x00 до 0x1F) инструкции установки бита в регистре ввода-вывода (SBI). Этот флаг всегда сбрасывается, если INT0 сконфигурирован как прерывание по уровню.

    Когда будут срабатывать внешние прерывания?

    Когда прерывания INT0 или INT1 разрешены и сконфигурированы как запускаемые по низкому уровню (Тип 2), прерывания будут срабатывать до тех пор, пока…

    1. Штифт удерживается низко.
    2. Низкий уровень сохраняется до завершения текущей выполняемой инструкции.
    3. Уровень удерживается достаточно долго, чтобы MCU полностью проснулся (при условии, что он спал).
      — Прерывания низкого уровня на INT0 и INT1 обнаруживаются асинхронно (часы не требуются). Тактовая частота ввода-вывода останавливается во всех режимах ожидания, кроме режима ожидания. Следовательно, прерывания низкого уровня могут использоваться для выхода из всех спящих режимов.
    4. Среди других приложений, прерывания низкого уровня могут использоваться для реализации протокола установления связи.

    Когда прерывания INT0 или INT1 разрешены и сконфигурированы как запускаемые по фронту или изменению логики (переключение), (Тип 11) прерывания будут срабатывать до тех пор, пока…

    1. Тактовая частота ввода / вывода присутствует.
      — Это означает, что эти прерывания не могут использоваться для пробуждения части из спящих режимов, кроме режима ожидания.
    2. Импульс длится дольше одного периода тактового сигнала ввода-вывода. Более короткие импульсы не гарантируют создания прерывания.

    Прерывания для смены PIN-кода

    • В дополнение к нашим двум (2) внешним прерываниям, двадцать три (23) контакта могут быть запрограммированы на запуск прерывания при изменении состояния контакта.
    • Эти 23 контакта, в свою очередь, разделены на три (3) группы прерываний (PCI 2: 0), соответствующие трем портам GPIO B, C и D
    • Каждой из групп назначен один бит флага прерывания смены вывода (PCIF) (2: 0).
    • Флаг прерывания смены вывода будет установлен, если прерывание разрешено (см. Как включить прерывание смены вывода), и любой вывод, назначенный группе, изменит состояние (переключается).

    Рисунок 6: Регистр прерывания смены вывода

    Как работает прерывание при смене PIN-кода

    Вот как это работает…

    Как разрешить прерывание при смене PIN-кода

    В дополнение к нашим двум (2) внешним прерываниям, двадцать три (23) контакта PCINT 23:16, 14: 0 могут быть запрограммированы на запуск прерывания при изменении состояния контакта.Эти 23 контакта разделены на три (3) группы прерываний (PCI 2: 0) из восьми (8), семи (7) и (8). Следовательно, для разрешения и прерывания изменения отдельного вывода 3 бита маски прерывания должны быть установлены в единицу (1).

    1. Бит разрешения глобального прерывания SREG I
    2. Бит разрешения прерывания при смене вывода (PCIE 2: 0) назначается контакту. В частности, прерывание смены вывода PCI2 сработает, если какой-либо активированный вывод PCINT23..16 переключается. Прерывание смены вывода PCI1 сработает, если включен какой-либо PCINT14..8-контактные переключатели. Прерывание смены вывода PCI0 сработает, если переключится любой из включенных выводов PCINT7..0.

      Регистр управления прерыванием изменения контакта

    3. Устанавливается бит маски разрешения прерывания изменения отдельного вывода, назначенный выводу (PCINT 23: 0). Эти биты маски расположены в трех регистрах маски смены выводов, назначенных каждой группе.

      Регистр маски изменения вывода 2


      Регистр маски изменения вывода 1


      Регистр маски изменения вывода 0

    Обработка прерываний ATmega328P (ОБЗОР)

    Программирование Arduino для обработки внешних прерываний

    • Остановить оптимизацию компилятором переменных в ISR, добавив квалификатор volatile.Это сохраняет текущее значение в SRAM до тех пор, пока оно не понадобится.

    константный байт pin = 8; // зеленый светодиод 0
    volatile int state = LOW;

    • Добавьте переходы из процедуры IVT в процедуру ISR, настройте регистр управления внешним прерыванием A (EICRA) и включите локальные и глобальные биты флага прерывания.
    • Процедура обслуживания прерывания записи (ISR)

    пусто мигает ()
    {

    состояние =! Состояние;

    }

    Чтобы отключить прерывания глобально (очистить бит I в SREG), вызовите функцию noInterrupts ().Чтобы снова разрешить прерывания (установить бит I в SREG), вызовите функцию interrupts ().

    Программирование Arduino для обработки прерываний

    • В среде AVR-GCC, на которой построен язык Arduino, таблица векторов прерываний (IVT) предопределена так, чтобы указывать на подпрограммы прерывания с предопределенными именами (см. «Таблица векторов прерываний ATmega328P» на стр. 6).
    • ISR создается с помощью макроса ISR () и этих имен.

    #include

    ISR (ADC_vect)
    {
    // здесь код пользователя
    }

    • Теперь, когда вы определили ISR, вам необходимо включить его локально и глобально. Вот соответствующие ссылки, чтобы узнать, как заполнить определение ISR.

    Практические задачи

    Пример конструкции

    — Switch Debounce

    • Когда вы нажимаете кнопку, ее контакты размыкаются и замыкаются много раз, прежде чем они наконец останутся на месте. Это известно как отскок контакта.
    • В зависимости от конструкции переключателя этот дребезг механического контакта может длиться до 10 или 20 миллисекунд. Это не проблема для ламп, дверных звонков и аудиосхем, но нанесет ущерб нашей схеме прерывания, запускаемой по фронту.

      Переключатель Bounce

    • Что касается формы волны, приведенной выше, необходимо разработать решение по устранению дребезга переключателя, чтобы отфильтровать эти переходы.
    Switch Debounce Solutions

    Итак, как мы можем разработать «схему устранения дребезга», чтобы отфильтровать эти переходы.

    1. Самое дешевое решение не требует оборудования. В частности, мы отключаем внешнее прерывание во время дребезга переключателя. Это решение было реализовано для Arduino Ником Гаммоном с кодом Arduino, представленным здесь в разделе «Пример кода таймера насоса».
    2. Некоторые простые электрические решения можно найти на сайте http://www.patchn.com/Debounce.htm.
    3. Для нашего решения я добавил D-триггер, который синхронизируется с частотой менее 50 Гц (T p = 20 миллисекунд).Эта цифровая схема действует как фильтр нижних частот, блокирующий схему прерывания AVR от реакции на любой из этих дополнительных фронтов.
    Switch Debounce Circuit — простой цифровой фильтр нижних частот

    Из предварительной лаборатории

    Приложение

    Как я разработал схему устранения дребезга

    Вот реальная проблема, которую я рассмотрел при разработке моей схемы Debounce.

    Логические уровни

    Между логическим 0 и логической 1 находится неопределенная область.На рисунке ниже показаны уровни входного и выходного напряжения TTL, соответствующие логическим 1 и 0 (источник: Theory of TTL Logic Family).
    Рекомендуемые значения: уровни напряжения логического сигнала

    Логические уровни на основе сигнала напряжения

    Время нарастания и спада (скорость нарастания)

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

    График скорости нарастания

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

    Задержка распространения и скорость нарастания для каждого семейства цифровых логических схем

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

    Выходной сигнал искажен из-за более низкой скорости нарастания

    Входные цепи МОП-устройств, таких как наш микроконтроллер AVR, могут быть охарактеризованы как емкостные по своей природе (могут быть смоделированы до первого порядка с помощью конденсатора). Для некоторых входов эта емкость может достигать 10 пФ (пико = 10 -12 ). Теперь предположим, что внешний подтягивающий резистор 10 кОм. Учитывая эту информацию, мы получаем расчетную постоянную времени (RC), равную 100 нс.

    Ясно, что у нас проблема.Я решил эту проблему, добавив устройство TTL между переключателем и микроконтроллером. Вход 74ALS74 можно охарактеризовать как резистивный по своей природе (может быть смоделирован резистором). В сочетании с повышающим сопротивлением (10 кОм) проблема с входом решается.

    Выход устройства 74ALS74 TTL идет непосредственно на вход микроконтроллера AVR, решая нашу проблему скорости нарастания напряжения. Однако эта новая более быстрая схема создает свои собственные проблемы, которые обсуждаются в следующем разделе.

    Исследование прерываний на Arduino

    #include

    #define FAN_PIN 14

    #define FAN_LED 23

    #define ANEMOMETER_PIN 15

    #define ANEMOMETER_LED 22

    // прерывание всех глобальных переменных, используемых в 9 энергозависимых переменных, которые используются в качестве

    временных переменных int fanCount = 0;

    энергозависимый байт fanState = LOW;

    энергозависимый байт anemometerState = LOW;

    volatile int anemometerCount = 0;

    volatile unsigned long lastAnemometerMillis = 0;

    // время дребезга язычкового переключателя, держите его как можно меньше

    // установите достаточно долго, чтобы не давать ложных показаний

    volatile unsigned long anemometerTimeoutMillis = 10;

    логическое isrMonitorON = true;

    int fanRPM = 0;

    внутренний анемометр RPM = 0;

    беззнаковый длинный lastMillis = 0;

    const int anemometerRadius = 70; // в мм расстояние от центра анемометра до середины чашки

    // процедура прерывания работы вентилятора (ISR)

    void rpmFan () {

    if (isrMonitorON == false) {

    возврат;

    }

    fanCount ++;

    fanState =! (FanState);

    }

    // процедура обслуживания прерывания анемометра (ISR)

    void rpmAnemometer () {

    if (isrMonitorON == false) {

    return;

    }

    // геркон анемометра дает довольно грубый сигнал, поэтому мы игнорируем дальнейшие прерывания

    // для следующего анемометраTimeoutMillis — исправление дребезга переключателя в программном обеспечении

    if (millis () — lastAnemometerMillis> anemometerTimeoutMillis) {

    anemometerCount ++;

    anemometerState =! (Состояние анемометра);

    lastAnemometerMillis = миллис ();

    }

    }

    // преобразовать обороты в м / с

    float calcMetersPerSecond (int rpm) {

    float r = (float) anemometerRadius / 1000; // конвертируем в метры

    float n = (float) rpm;

    возврат (2 * M_PI * r * n) / 60;

    }

    void setup () {

    delay (1000);

    Серийный.begin (9600);

    Serial.println («готово»);

    pinMode (FAN_PIN, INPUT);

    attachInterrupt (digitalPinToInterrupt (FAN_PIN), rpmFan, RISING);

    pinMode (FAN_LED, ВЫХОД);

    digitalWrite (FAN_LED, LOW);

    pinMode (ANEMOMETER_PIN, INPUT);

    attachInterrupt (digitalPinToInterrupt (ANEMOMETER_PIN), rpmAnemometer, RISING);

    pinMode (ANEMOMETER_LED, ВЫХОД);

    digitalWrite (ANEMOMETER_LED, LOW);

    }

    void loop () {

    digitalWrite (FAN_LED, fanState);

    digitalWrite (ANEMOMETER_LED, anemometerState);

    if (millis () — lastMillis> = 1000) {

    isrMonitorON = false; // прекращаем обновление счетчиков при вычислении и отображении

    fanRPM = fanCount * 60; // преобразовываем частоту в об / мин.

    анемометрRPM = anemometerCount * 60;

    Serial.print («вентилятор:»);

    Последовательная печать (fanRPM);

    Serial.

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

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