attachInterrupt() / Arduino
Описание
Цифровые выводы с прерываниями
Первый параметр attachInterrupt()
– это номер прерывания. Как правило, вы должны использовать digitalPinToInterrupt(pin)
для перевода реального цифрового вывода в конкретный номер прерывания. Например, если вы подключаетесь к выводу 3, используйте digitalPinToInterrupt(3)
в качестве первого параметра attachInterrupt()
.
Плата | Цифровые выводы, используемые для прерываний |
---|---|
Uno, Nano, Mini, other 328-based | 2, 3 |
Uno WiFi Rev.2 | все цифровые выводы |
Mega, Mega2560, MegaADK | 2, 3, 18, 19, 20, 21 |
Micro, Leonardo, other 32u4-based | 0, 1, 2, 3, 7 |
Zero | все цифровые выводы, кроме 4 |
MKR Family boards | 0, 1, 4, 5, 6, 7, 8, 9, A1, A2 |
Due | все цифровые выводы |
101 | все цифровые выводы (Выводы 2, 5, 7, 8, 10, 11, 12, 13 работают только с CHANGE) |
Примечания и предупреждения
Внутри прикрепленной функции delay()
работать не будет, а значение, возвращаемое millis()
, не будет увеличиваться. Последовательные данные, принятые во время выполнения этой функции, могут быть потеряны. Вы должны объявлять как volatile
любые переменные, которые вы изменяете в прикрепленной функции. Дополнительную информацию смотрите в разделе об обработчиках прерываний ниже.
Использование прерываний
Прерывания полезны для того, чтобы всё в программах микроконтроллеров происходило автоматически, и могут помочь решить проблемы с синхронизацией. Подходящие задачи для использования прерываний включают в себя считывание поворотного энкодера или мониторинг пользовательского ввода данных.
Если вы хотите обеспечить, чтобы программа всегда будет захватывать импульсы от поворотного энкодера, так чтобы она никогда не пропускала их, было бы сложно написать последовательно выполняемую программу, которая делала бы что-либо еще, потому что программе необходимо было бы постоянно выполнять опрос линий датчика, идущих от энкодера, чтобы отлавливать импульсы при их появлении. Другие датчики также имеют аналогичную динамику интерфейса, например, попытка прочитать звуковой датчик, который пытается отловить щелчок, или инфракрасный датчик (фотопрерыватель), который пытается отследить падение монеты. Во всех этих ситуациях использование прерывания может освободить микроконтроллер для выполнения какой-либо другой работы, не пропуская ввода данных.
О функциях обработчиков прерываний (ISR)
ISR – это специальные виды функций, которые имеют некоторые уникальные ограничения, которых нет у большинства других функций. ISR не может иметь никаких параметров, и они не должны чего-либо возвращать.
Как правило, ISR должна быть как можно короче и быстрее. Если ваш скетч использует несколько ISR, одновременно может быть запущен только один обработчик, другие прерывания будут обрабатываться после того, как текущий будет завершен, в зависимости от своего приоритета. millis()
полагается на прерывания для счета, поэтому она никогда не будет инкрементироваться во время выполнения ISR. Поскольку delay()
требует для работы прерываний, эта функция не будет работать, если будет вызвана внутри ISR. Функция micros()
изначально работает, но начнет вести себя беспорядочно через 1-2 мс. Функция delayMicroseconds()
не использует счетчиков, поэтому будет работать нормально.
Обычно глобальные переменные используются для передачи данных между ISR и основной программой. Чтобы убедиться, что переменные, используемые ISR и основной программой, обновляются правильно, объявляйте их как volatile
(изменчивыми).
Синтаксис
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode); // рекомендуется
attachInterrupt(interrupt, ISR, mode); // не рекомендуется
attachInterrupt(pin, ISR, mode); // не рекомендуется, только для Arduino Due, Zero, MKR1000, 101
Параметры
interrupt
: номер прерывания (int
).
pin
: номер вывода (только для Arduino Due, Zero, MKR1000).
ISR
: функция обработчика прерывания, которая вызывается, когда происходит прерывание; данная функция должна не принимать никаких параметров и ничего не возвращать.
mode
: определяет, когда должно быть запущено прерывание. В качестве допустимых значений предопределены четыре константы:
LOW
, чтобы вызывать прерывание, когда на выводе низкий логический уровень;CHANGE
, чтобы вызывать прерывание всякий раз, когда меняется состояние на выводе;RISING
для запуска, когда состояние на выводе переходит от низкого к высокому;FALLING
, когда состояние на выводе переходит от высокого к низкому.
Платы Due, Zero и MKR1000 также поддерживают:
HIGH
, чтобы вызывать прерывание всякий раз, когда на выводе высокий логический уровень.
Возвращает
Ничего.
Пример кода
const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;
void setup()
{
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}
void loop()
{
digitalWrite(ledPin, state);
}
void blink()
{
state = !state;
}
Номера прерываний
Обычно вы должны использовать 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 | ||||
Mega2560 | 2 | 3 | 21 | 20 | 19 | 18 |
На базе 32u4 (например, Leonardo, Micro) | 3 | 2 | 0 | 1 | 7 |
Для плата Uno WiFiRev.2, Due, Zero, семейства MKR и 101 номер прерывания = номер вывода.