digitalPinToInterrupt()
digitalPinToInterrupt() преобразует номер цифрового вывода в номер прерывания для attachInterrupt() — это делает код переносимым между разными платами Arduino.
Полная статья
Описание
digitalPinToInterrupt() принимает номер цифрового вывода и возвращает соответствующий ему номер внешнего прерывания — тот, который нужно передавать в attachInterrupt() и detachInterrupt().
Дело в том, что в Arduino-ядре номера прерываний и номера выводов — это разные вещи. На одних платах они совпадают, на других нет. Классический пример: на Arduino UNO вывод 2 — это interrupt 0, а вывод 3 — interrupt 1. Если написать номер прерывания вручную, код перестанет работать на другой плате, где нумерация другая. Поэтому рекомендуемый способ — всегда обращаться к digitalPinToInterrupt(pin) и не думать о внутренней нумерации ядра.
Если указанный вывод вообще не умеет обрабатывать внешние прерывания, функция вернёт NOT_AN_INTERRUPT (обычно это -1). Например, digitalPinToInterrupt(4) на Arduino UNO вернёт именно это значение, потому что четвёртый вывод там прерывания не поддерживает.
Полный список выводов с поддержкой прерываний для разных плат приведён на странице attachInterrupt().
Синтаксис
digitalPinToInterrupt(pin)
Параметры
pin— номер цифрового вывода Arduino, который планируется использовать для внешнего прерывания.
Возвращает
Номер прерывания, соответствующий указанному выводу. Если вывод не поддерживает внешние прерывания — возвращается NOT_AN_INTERRUPT.
Тип данных: int.
Пример кода
В примере ниже скетч сначала проверяет, поддерживает ли выбранный вывод внешнее прерывание, и только затем вызывает attachInterrupt():
const byte interruptPin = 2;
volatile bool triggered = false;
void setup() {
Serial.begin(9600);
pinMode(interruptPin, INPUT_PULLUP);
int interruptNumber = digitalPinToInterrupt(interruptPin);
if (interruptNumber == NOT_AN_INTERRUPT) {
Serial.println("This pin does not support external interrupts");
} else {
attachInterrupt(interruptNumber, handleInterrupt, FALLING);
}
}
void loop() {
if (triggered) {
triggered = false;
Serial.println("Interrupt fired");
}
}
void handleInterrupt() {
triggered = true;
}
Где применяется
- Подключение прерываний — самый распространённый случай:
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode)— именно в такой форме рекомендуется вызыватьattachInterrupt(). - Переносимость кода — один и тот же скетч без изменений будет корректно работать на UNO, Mega, Leonardo, Nano Every, Due, Zero, MKR и других платах, где внутренняя нумерация прерываний различается.
- Проверка вывода перед использованием — если номер вывода задаётся пользователем или приходит из настроек, удобно проверить результат на
NOT_AN_INTERRUPTпрежде чем что-то настраивать. - Разработка библиотек — если библиотека принимает номер пина как аргумент, она может безопасно преобразовать его через
digitalPinToInterrupt()внутри своего кода.
Практические замечания
- Всегда передавайте в
attachInterrupt()результатdigitalPinToInterrupt(pin), а не номер прерывания вручную — это единственный способ написать переносимый код. - Проверяйте возвращаемое значение на
NOT_AN_INTERRUPTвезде, где вывод может оказаться неподходящим: в библиотеках, в скетчах с настраиваемыми пинами, при портировании на другую плату. - На Arduino UNO внешние прерывания доступны только на выводах 2 и 3; на Mega 2560 — на выводах 2, 3, 18, 19, 20 и 21; на многих современных платах почти каждый цифровой вывод поддерживает прерывания.
- Сама по себе функция ничего не настраивает в железе. Она только вычисляет правильный номер прерывания — всю реальную работу по привязке обработчика делает
attachInterrupt(). - Если нужно отладить выбор вывода, выведите результат
digitalPinToInterrupt(pin)в Serial Monitor до вызоваattachInterrupt(): сразу будет видно, вернулось ли корректное число илиNOT_AN_INTERRUPT.
Примечания и предупреждения
Если digitalPinToInterrupt(pin) вернула NOT_AN_INTERRUPT, вызывать attachInterrupt() для этого вывода бессмысленно — обработчик не заработает. Выберите другой вывод или сверьтесь с таблицей поддерживаемых прерываний для вашей платы.