attachInterrupt()
Использование прерываний
Прерывания помогают автоматизировать события в программах микроконтроллеров и могут помочь решить проблемы с синхронизацией. Хорошие задачи для использования прерываний включают чтение поворотного энкодера или мониторинг пользовательского ввода.
Если вы хотите гарантировать, что программа всегда улавливает импульсы от поворотного энкодера и никогда не пропускает ни одного, написать программу для выполнения других задач было бы очень сложно, потому что программа должна была бы постоянно опрашивать линии датчика энкодера, чтобы перехватывать импульсы в момент их появления. Другие датчики имеют аналогичную динамику интерфейса, например, попытка считать датчик звука, который обнаруживает щелчок, или инфракрасный щелевой датчик (фотопрерыватель), который обнаруживает падение монеты. Во всех этих ситуациях использование прерывания может освободить микроконтроллер для другой работы, при этом продолжая захватывать входные данные.
Синтаксис
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode)(рекомендуется)attachInterrupt(interrupt, ISR, mode)(не рекомендуется)attachInterrupt(pin, ISR, mode)(не рекомендуется. Кроме того, этот синтаксис работает только на платах Arduino SAMD, UNO WiFi Rev2, Due и 101.)
Параметры
interrupt: номер прерывания. Допустимые типы данных:int.pin: номер пина Arduino.ISR: функция обработки прерывания (ISR), вызываемая при возникновении прерывания; эта функция не должна принимать параметры и ничего не возвращать. Эту функцию иногда называют подпрограммой обслуживания прерывания.mode: определяет, когда должно срабатывать прерывание. Четыре константы предопределены как допустимые значения:LOW – срабатывает, когда на пине низкий уровень,
CHANGE – срабатывает, когда на пине меняется значение,
RISING – срабатывает, когда пин переходит с низкого на высокий уровень,
FALLING – срабатывает, когда пин переходит с высокого на низкий уровень.
Платы Due, Zero и MKR1000 также поддерживают:
HIGH – срабатывает, когда на пине высокий уровень.
Подпрограммы обслуживания прерываний (ISR)
ISR – это особый вид функций, имеющих уникальные ограничения, которые не разделяются большинством других функций. ISR не может иметь параметров и не должна ничего возвращать.
Как правило, ISR должна быть как можно короче и быстрее. Если ваш скетч использует несколько ISR, только одна может выполняться одновременно; другие прерывания будут выполнены после завершения текущего в порядке, зависящем от их приоритета.
millis() зависит от прерываний для подсчёта, поэтому внутри ISR её значение никогда не будет увеличиваться. Поскольку delay() требует прерываний для работы, она не будет функционировать при вызове внутри ISR. micros() изначально работает, но начинает вести себя хаотично через 1-2 мс. delayMicroseconds() не использует счётчик, поэтому будет работать как обычно.
Как правило, для передачи данных между ISR и основной программой используются глобальные переменные. Чтобы гарантировать корректное обновление переменных, общих для ISR и основной программы, объявляйте их как volatile.
Для получения дополнительной информации о прерываниях см. заметки Ника Гэммона.
Возвращаемое значение
Функция ничего не возвращает.
Пример кода
const byte ledPin = 13;
const byte interruptPin = 2; // входной пин, к которому подключено прерывание
volatile byte state = LOW; // переменная, обновляемая в ISR
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}
void loop() {
digitalWrite(ledPin, state);
}
void blink() {
state = !state;
}
Цифровые пины с прерываниями
Первым параметром attachInterrupt() является номер прерывания. Обычно следует использовать digitalPinToInterrupt(pin) для преобразования фактического цифрового пина в конкретный номер прерывания. Например, если вы подключаетесь к пину 3, используйте digitalPinToInterrupt(3) в качестве первого параметра attachInterrupt().
Плата |
Цифровые пины для прерываний |
Примечания |
|---|---|---|
UNO R3, Nano, Mini, другие на 328 |
2, 3 |
|
UNO R4 Minima, UNO R4 WiFi |
2, 3 |
|
UNO WiFi Rev2, Nano Every |
Все цифровые пины |
|
Mega, Mega 2560, Mega ADK |
2, 3, 18, 19, 20, 21 |
Пины 20 и 21 нельзя использовать для прерываний, если они используются для I2C; они также имеют внешние подтяжки, которые нельзя отключить |
Micro, Leonardo |
0, 1, 2, 3, 7 |
|
Zero |
0-3, 5-13, A0-A5 |
Пин 4 нельзя использовать как прерывание |
Платы семейства MKR |
0, 1, 4, 5, 6, 7, 8, 9, A1, A2 |
|
Nano 33 IoT |
2, 3, 9, 10, 11, 13, A1, A5, A7 |
|
Nano 33 BLE, Nano 33 BLE Sense (Rev 1 и 2) |
Все пины |
|
Nano RP2040 Connect |
0-13, A0-A5 |
|
Nano ESP32 |
Все пины |
|
GIGA R1 WiFi |
Все пины |
|
Due |
Все цифровые пины |
|
101 |
Все цифровые пины |
Только пины 2, 5, 7, 8, 10, 11, 12, 13 работают с CHANGE |
Номера прерываний
Обычно следует использовать digitalPinToInterrupt(pin) вместо указания номера прерывания непосредственно в скетче. Конкретные пины с прерываниями и их соответствие номерам прерываний различаются для каждого типа платы. Прямое использование номеров прерываний может показаться простым, но может вызвать проблемы совместимости при запуске скетча на другой плате.
Однако в старых скетчах часто используются прямые номера прерываний. Обычно использовались номер 0 (для цифрового пина 2) или номер 1 (для цифрового пина 3). В таблице ниже показаны доступные пины прерываний на различных платах.
Примечание
В таблице ниже номера прерываний относятся к числу, передаваемому в attachInterrupt(). По историческим причинам эта нумерация не всегда соответствует непосредственно нумерации прерываний на чипе ATmega (например, int.0 соответствует INT4 на чипе ATmega2560).
Плата |
int.0 |
int.1 |
int.2 |
int.3 |
int.4 |
int.5 |
|---|---|---|---|---|---|---|
UNO, Ethernet |
2 |
3 |
||||
Mega 2560 |
2 |
3 |
21 |
20 |
19 |
18 |
На базе 32u4 (Leonardo, Micro) |
3 |
2 |
0 |
1 |
7 |
Для UNO WiFi Rev2, Due, Zero, плат семейства MKR и 101 номер прерывания = номер пина.
Примечания и предупреждения
Предупреждение
Внутри подключённой функции delay() не будет работать, а значение, возвращаемое millis(), не будет увеличиваться. Последовательные данные, полученные во время работы функции, могут быть потеряны. Переменные, которые вы изменяете внутри подключённой функции, следует объявлять как volatile. Подробнее см. раздел об ISR выше.