Функция attachInterrupt()

arduino-logo

Описание функции attachInterrupt

Функция attachinterrupt() задает функцию внешнего прерывания, режим обработки и контакт ардуины, на котором это прерывание отслеживать. Другими словами, определяет функцию, которая будет выполняться при генерации внешнего прерывания. Стоит отметить, что если до этого была задана другая функция обработки прерывания, то назначается новая.

Таблица ниже показывает, какие контакты каких плат поддерживают внешние прерывания.

ПлатаЦифровые контакты для внешних прерываний
Uno, Nano, Mini и другие, на базе ATmega328p2, 3
Uno WiFi Rev.2, Nano EveryВсе цифровые контакты
Mega, Mega2560, MegaADK2, 3, 18, 19, 20, 21
Micro, Leonardo и другие на базе ATmega32u40, 1, 2, 3, 7
ZeroВсе цифровые контакты, кроме 4
DueВсе цифровые контакты

Кроме того, в функции-обработчике внешнего прерывания не будет работать функция delay(), а также значение, которое возвращает функция millis(), не будет увеличиваться.

Синтаксис

void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)

Для преобразования цифрового контакта в номер прерывания необходимо использовать функцию digitalPinToInterrupt(). Например, для ардуино на основе ATmega328 код

attachInterrupt(0, testFunc, CHANGE);

будет равносильным коду

attachInterrupt(digitalPinToInterrupt(2), testFunc, CHANGE);

Параметры

  • interruptNum — номер прерывания
  • userFunc — функция, которая будет вызываться прерыванием. Передаваемая функция должна быть без параметров и не возвращать значений.
  • mode — режим обработки прерывания. Доступны следующие режимы:
    • LOW — вызывает прерывание, когда на контакте низкий логический уровень LOW;
    • CHANGE — вызывает прерывание, когда на контакте сменилось значение с LOW на HIGH или наоборот.
    • RISING — вызывает прерывание, когда на контакте сменилось значение с LOW на HIGH.
    • FALLING — вызывает прерывание, когда на контакте сменилось значение с HIGH на LOW.

Что возвращает

Ничего

Пример использования функции attachInterrupt

bool flagInterrupt0 = false, flagInterrupt1 = false;                    // Флаги для отслеживания внешних прерываний

void setup() {
  Serial.begin(9600);                                                   // Инициализация последовательного порта
  while(!Serial);                                                       // Ждем открытия порта
  Serial.println("Внешние прерывания на ардуино нано.");
  attachInterrupt(digitalPinToInterrupt(2), handlerInterrupt0, CHANGE); // Задаем прерыванию 0 (на 2 цифровом контакте) функцию-обработчик handlerInterrupt0 при любом изменении состояния порта (c LOW на HIGH либо с HIGH на LOW)
  attachInterrupt(digitalPinToInterrupt(3), handlerInterrupt1, RISING); // Задаем прерыванию 1 (на 3 цифровом контакте) функцию-обработчик handlerInterrupt1 при изменение на порте с LOW на HIGH
}

void loop() {
  /* Отслеживаем флаг внешнего прерывания 0. Если flagInterrupt0 = true, прерывание сработало */
  if( flagInterrupt0 ) {
    Serial.println("Сработало внешнее прерывание 0");                   // Выводим в порт
    flagInterrupt0 = false;                                             // сбрасываем флаг
  }
  /* Отслеживаем флаг внешнего прерывания 1. Если flagInterrupt1 = true, прерывание сработало */
  if( flagInterrupt1 ) {
    Serial.println("Сработало внешнее прерывание 1");                   // Выводим в порт
    flagInterrupt1 = false;                                             // сбрасываем флаг
  }
}

/* Функция-обработчик для прерывания 0 */
void handlerInterrupt0() {
  flagInterrupt0 = true;
}

/* Функция-обработчик для прерывания 1 */
void handlerInterrupt1() {
  flagInterrupt1 = true;
}
Функция attachInterrupt в arduino ide

Код функции attachinterrupt

(hardware/arduino/avr/cores/arduino/WInterrupts.c 1.8.10)

void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
  if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
    intFunc[interruptNum] = userFunc;
      
    switch (interruptNum) {
#if defined(__AVR_ATmega32U4__)
    case 0:
	EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
	EIMSK |= (1 << INT0);
	break;
    case 1:
	EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
	EIMSK |= (1 << INT1);
	break;	
    case 2:
        EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
        EIMSK |= (1 << INT2);
        break;
    case 3:
        EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
        EIMSK |= (1 << INT3);
        break;
    case 4:
        EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60);
        EIMSK |= (1 << INT6);
        break;
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
    case 2:
      EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
      EIMSK |= (1 << INT0);
      break;
    case 3:
      EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
      EIMSK |= (1 << INT1);
      break;
    case 4:
      EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
      EIMSK |= (1 << INT2);
      break;
    case 5:
      EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
      EIMSK |= (1 << INT3);
      break;
    case 0:
      EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40);
      EIMSK |= (1 << INT4);
      break;
    case 1:
      EICRB = (EICRB & ~((1 << ISC50) | (1 << ISC51))) | (mode << ISC50);
      EIMSK |= (1 << INT5);
      break;
    case 6:
      EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60);
      EIMSK |= (1 << INT6);
      break;
    case 7:
      EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70);
      EIMSK |= (1 << INT7);
      break;
#else		
    case 0:
    #if defined(EICRA) && defined(ISC00) && defined(EIMSK)
      EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
      EIMSK |= (1 << INT0);
    #elif defined(MCUCR) && defined(ISC00) && defined(GICR)
      MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
      GICR |= (1 << INT0);
    #elif defined(MCUCR) && defined(ISC00) && defined(GIMSK)
      MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
      GIMSK |= (1 << INT0);
    #else
      #error attachInterrupt not finished for this CPU (case 0)
    #endif
      break;

    case 1:
    #if defined(EICRA) && defined(ISC10) && defined(ISC11) && defined(EIMSK)
      EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
      EIMSK |= (1 << INT1);
    #elif defined(MCUCR) && defined(ISC10) && defined(ISC11) && defined(GICR)
      MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
      GICR |= (1 << INT1);
    #elif defined(MCUCR) && defined(ISC10) && defined(GIMSK) && defined(GIMSK)
      MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
      GIMSK |= (1 << INT1);
    #else
      #warning attachInterrupt may need some more work for this cpu (case 1)
    #endif
      break;
    
    case 2:
    #if defined(EICRA) && defined(ISC20) && defined(ISC21) && defined(EIMSK)
      EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
      EIMSK |= (1 << INT2);
    #elif defined(MCUCR) && defined(ISC20) && defined(ISC21) && defined(GICR)
      MCUCR = (MCUCR & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
      GICR |= (1 << INT2);
    #elif defined(MCUCR) && defined(ISC20) && defined(GIMSK) && defined(GIMSK)
      MCUCR = (MCUCR & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
      GIMSK |= (1 << INT2);
    #endif
      break;
#endif
    }
  }
1 1 голос
Рейтинг статьи
Подписаться
Уведомить о
guest
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии