Главная chevron_right Функции chevron_right Внешние прерывания chevron_right digitalPinToInterrupt()

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

Полезные материалы