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

attachInterrupt()

Description

Digital Pins With Interrupts

The first parameter to attachInterrupt() is an interrupt number. Normally you should use digitalPinToInterrupt(pin) to translate the actual digital pin to the specific interrupt number. For example, if you connect to pin 3, use digitalPinToInterrupt(3) as the first parameter to attachInterrupt() .

Uno, Nano, Mini, other 328-based

Uno WiFi Rev.2, Nano Every

all digital pins

Mega, Mega2560, MegaADK

2, 3, 18, 19, 20, 21 (pins 20 & 21 are not available to use for interrupts while they are used for I2C communication)

Micro, Leonardo, other 32u4-based

all digital pins, except 4

MKR Family boards

0, 1, 4, 5, 6, 7, 8, 9, A1, A2

2, 3, 9, 10, 11, 13, A1, A5, A7

Nano 33 BLE, Nano 33 BLE Sense

all digital pins

all digital pins (Only pins 2, 5, 7, 8, 10, 11, 12, 13 work with CHANGE)

Notes and Warnings

Note
Inside the attached function, delay() won’t work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function. See the section on ISRs below for more information.

Using Interrupts

Interrupts are useful for making things happen automatically in microcontroller programs and can help solve timing problems. Good tasks for using an interrupt may include reading a rotary encoder, or monitoring user input.

If you wanted to ensure that a program always caught the pulses from a rotary encoder, so that it never misses a pulse, it would make it very tricky to write a program to do anything else, because the program would need to constantly poll the sensor lines for the encoder, in order to catch pulses when they occurred. Other sensors have a similar interface dynamic too, such as trying to read a sound sensor that is trying to catch a click, or an infrared slot sensor (photo-interrupter) trying to catch a coin drop. In all of these situations, using an interrupt can free the microcontroller to get some other work done while not missing the input.

About Interrupt Service Routines

ISRs are special kinds of functions that have some unique limitations most other functions do not have. An ISR cannot have any parameters, and they shouldn’t return anything.

Generally, an ISR should be as short and fast as possible. If your sketch uses multiple ISRs, only one can run at a time, other interrupts will be executed after the current one finishes in an order that depends on the priority they have. millis() relies on interrupts to count, so it will never increment inside an ISR. Since delay() requires interrupts to work, it will not work if called inside an ISR. micros() works initially but will start behaving erratically after 1-2 ms. delayMicroseconds() does not use any counter, so it will work as normal.

Typically global variables are used to pass data between an ISR and the main program. To make sure variables shared between an ISR and the main program are updated correctly, declare them as volatile .

For more information on interrupts, see Nick Gammon’s notes.

Syntax

attachInterrupt(digitalPinToInterrupt(pin), ISR, mode) (recommended)
attachInterrupt(interrupt, ISR, mode) (not recommended)
attachInterrupt(pin, ISR, mode) (Not recommended. Additionally, this syntax only works on Arduino SAMD Boards, Uno WiFi Rev2, Due, and 101.)

Parameters

interrupt : the number of the interrupt. Allowed data types: int .
pin : the Arduino pin number.
ISR : the ISR to call when the interrupt occurs; this function must take no parameters and return nothing. This function is sometimes referred to as an interrupt service routine.
mode : defines when the interrupt should be triggered. Four constants are predefined as valid values:

LOW to trigger the interrupt whenever the pin is low,

CHANGE to trigger the interrupt whenever the pin changes value

RISING to trigger when the pin goes from low to high,

FALLING for when the pin goes from high to low.

The Due, Zero and MKR1000 boards allow also:

HIGH to trigger the interrupt whenever the pin is high.

Источник

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

Оптимизируйте ваши программы для Arduino с помощью прерываний – простого способа для реагирования на события в режиме реального времени!

Мы прерываем нашу передачу.

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

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

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

Начнем с простого примера: использования прерывания для отслеживания нажатия кнопки. Для начала, мы возьмем скетч, который вы, вероятно, уже видели: пример « Button », включенный в Arduino IDE (вы можете найти его в каталоге « Примеры », проверьте меню Файл → Примеры → 02. Digital → Button ).

В том, что вы видите здесь, нет ничего шокирующего и удивительного: всё, что программа делает снова и снова, это прохождение через цикл loop() и чтение значения buttonPin . Предположим на секунду, что вы хотели бы сделать в loop() что-то еще, что-то большее, чем просто чтение состояния вывода. Вот здесь и пригодится прерывание. Вместо того, чтобы постоянно наблюдать за состоянием вывода, мы можем поручить эту работу прерыванию и освободить loop() для выполнения в это время того, что нам необходимо! Новый код будет выглядеть следующим образом:

Циклы и режимы прерываний

Здесь вы заметите несколько изменений. Первым и самым очевидным из них является то, что loop() теперь не содержит никаких инструкций! Мы можем обойтись без них, так как вся работа, которая ранее выполнялась в операторе if/else , теперь выполняется в новой функции pin_ISR() . Этот тип функций называется обработчиком прерывания: его работа состоит в том, чтобы быстро запуститься, обработать прерывание и позволить процессору вернуться обратно к основной программе (то есть к содержимому loop() ). При написании обработчика прерывания следует учитывать несколько важных моментов, отражение которых вы можете увидеть в приведенном выше коде:

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

Вам, наверное, интересно: откуда мы знаем, когда запустится прерывание? Что его вызывает? Третья функция, вызываемая в функции setup() , устанавливает прерывание для всей системы. Данная функция, attachInterrupt() , принимает три аргумента:

  1. вектор прерывания, который определяет, какой вывод может генерировать прерывание. Это не сам номер вывода, а ссылка на место в памяти, за которым процессор Arduino должен наблюдать, чтобы увидеть, не произошло ли прерывание. Данное пространство в этом векторе соответствует конкретному внешнему выводу, и не все выводы могут генерировать прерывание! На Arduino Uno генерировать прерывания могут выводы 2 и 3 с векторами прерываний 0 и 1, соответственно. Для получения списка выводов, которые могут генерировать прерывания, смотрите документацию на функцию attachInterrupt для Arduino;
  2. имя функции обработчика прерывания: определяет код, который будет запущен при совпадении условия срабатывания прерывания;
  3. режим прерывания, который определяет, какое действие на выводе вызывает прерывание. Arduino Uno поддерживает четыре режима прерывания:
    • RISING – активирует прерывание по переднему фронту на выводе прерывания;
    • FALLING – активирует прерывание по спаду;
    • CHANGE – реагирует на любое изменение значения вывода прерывания;
    • LOW – вызывает всякий раз, когда на выводе низкий уровень.

И резюмируя, наша настройка attachInterrupt() соответствует отслеживанию вектора прерывания 0 (вывод 2), чтобы отреагировать на прерывание с помощью pin_ISR() , и вызвать pin_ISR() всякий раз, когда произойдет изменение состояния на выводе 2.

Volatile

Еще один момент, на который стоит указать: наш обработчик прерывания использует переменную buttonState для хранения состояния вывода. Проверьте определение buttonState : вместо типа int , мы определили его, как тип volatile int . В чем же здесь дело? volatile является ключевым словом языка C, которое применяется к переменным. Оно означает, что значение переменной находится не под полным контролем программы. То есть значение buttonState может измениться и измениться на что-то, что сама программа не может предсказать – в этом случае, пользовательский ввод.

Еще одна полезная вещь в ключевом слове volatile заключается в защите от любой случайной оптимизации. Компиляторы, как выясняется, выполняют еще несколько дополнительных задач при преобразовании исходного кода программы в машинный исполняемый код. Одной из этих задач является удаление неиспользуемых в исходном коде переменных из машинного кода. Так как переменная buttonState не используется или не вызывается напрямую в функциях loop() или setup() , существует риск того, что компилятор может удалить её, как неиспользуемую переменную. Очевидно, что это неправильно – нам необходима эта переменная! Ключевое слово volatile обладает побочным эффектом, сообщая компилятору, что эту переменную необходимо оставить в покое.

Удаление неиспользуемых переменных из кода – это функциональная особенность, а не баг компиляторов. Люди иногда оставляют в коде неиспользуемые переменные, которые занимают память. Это не такая большая проблема, если вы пишете программу на C для компьютера с гигабайтами оперативной памяти. Однако, на Arduino оперативная память ограничена, и вы не хотите тратить её впустую! Даже C компиляторы для компьютеров будут поступать точно так же, несмотря на массу доступной системной памяти. Зачем? По той же причине, по которой люди убирают за собой после пикника – это хорошая практика, не оставлять после себя мусор.

Подводя итоги

Прерывания – это простой способ заставить вашу систему быстрее реагировать на чувствительные к времени задачи. Они также обладают дополнительным преимуществом – освобождением главного цикла loop() , что позволяет сосредоточить в нем выполнение основной задачи системы (я считаю, что использование прерываний, как правило, позволяет сделать мой код немного более организованным: проще увидеть, для чего разработан основной кусок кода, и какие периодические события обрабатываются прерываниями). Пример, показанный здесь, – это самый базовый случай использования прерываний; вы можете использовать для чтения данных с I2C устройства, беспроводных передачи и приема данных, или даже для запуска или остановки двигателя.

Есть какие-нибудь крутые проекты с прерываниями? Оставляйте комментарии ниже!

Источник

Ардуино для начинающих. Урок 14. Прерывания.

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

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

В этом уроке используется:

Board Digital Pins Usable For Interrupts
Отличный набор для начинающих: Купить
Arduino Uno: Купить
Инфракрасный датчик расстояния: Купить
Инвертирующий триггер шмитта: Купить
Комплект конденсаторов 120 штук: Купить

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

В Arduino имеется 4 вида аппаратных прерываний. Отличаются они сигналом на контакте прерывания.

  • Контакт прерывания притянут к земле. Ардуино будет выполнять обработчик прерывания пока на пине прерывания будет сигнал LOW.
  • Изменение сигнала на контакте прерывания. Ардуино будет выполнять обработчик прерывания каждый раз когда на пине прерывания будет изменяться сигнал.
  • Изменение сигнала на контакте прерывания от LOW к HIGH. Обработчик прерывания исполняется только при изменении низкого сигнала на высокий.
  • Изменение сигнала на контакте прерывания от HIGH к LOW. Обработчик прерывания исполняется только при изменении высокого сигнала на низкий.

Если прерывание ожидает нажатия кнопки, то это может стать проблемой из-за дребезга контактов. В 6 уроке мы уже говорили о дребезге контактов. Тогда мы использовали функцию delay(), но в прерываниях данная функция не доступна. Поэтому нам придется подавить дребезг контактов немного усложнив схему подключения кнопки к пину прерывания. Для этого понадобится резистор на 10 КОм, конденсатор на 10 микрофарад,
и инвертирующий триггер шмитта. Подключается все по следующей схеме:

подключение кнопки прерывания ардуино

В Arduino Uno есть два пина, поддерживающие прерывания. Это цифровые пины 2 (int 0) и 3 (int 1). Один из них мы и будем использовать в нашей схеме.

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

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

Схема кажется сложной и запутанной, но это не так. Мы подключаем кнопку прерывания к пину Arduino D2, используя аппаратное подавление дребезга контактов. К аналоговому пину A0 мы подключаем инфракрасный дальномер. И к пинам D9, D10 и D11 мы подключаем светодиоды через резисторы на 150 Ом. Мы выбрали именно эти контакты для светодиодов, потому что они могут выдавать ШИМ сигнал.Теперь рассмотрим скетч:

Обратите внимание на следующие моменты: Необходимо использовать ключевое слово «volatile» перед объявлением переменной значение которой будет изменяться в обработчике прерывания. Так же я добавил переменную «nullLed» для того что бы программа на определенном шаге не меняла цвет ни одного из подключенных светодиодов. Строка «attachInterrupt(buttonInt, swap, RISING);» назначает обработчиком прерывания функцию swap. Подробнее об этой функции вы можете почитать здесь.

Функция swap просто переключает текущий светодиод на следующий. Остальной скетч должен быть вам понятен, если вы посмотрели все предыдущие уроки. Это последний обучающий урок. В следующих статьях я расскажу о подключении к Arduino популярных модулей.

Источник

Adblock
detector