Сколько контактов прерывания может обрабатывать Uno?

16

Я смотрю на использование 7-канального RC-ресивера с Arduino Uno R3. В документации упоминается максимум о 2 выводах прерываний, тогда как в некоторых других блогах я упоминал об использовании до 20 выводов в качестве прерываний с библиотекой PinChangeInt. Итак, сколько прерываний может обработать Arduino изначально? И отличается ли это от того, сколько можно обработать с помощью программной поддержки, такой как PinChangeInt?

asheeshr
источник

Ответы:

13

Существует два типа прерываний типа «смена контактов». Внешние прерывания, которых на Uno два. Они называются 0 и 1, однако они относятся к цифровым контактам 2 и 3 на плате. Они могут быть настроены на обнаружение подъема, падения, изменения (подъем или падение) или НИЗКОГО.

В дополнение к этому есть прерывания «смена контактов», которые обнаруживают изменение состояния контактов на любом из 20 контактов (от A0 до A5 и от D0 до D13). Эти прерывания смены контактов также являются аппаратными, поэтому сами по себе будут такими же быстрыми, как и внешние прерывания.

Оба типа немного сложны для использования на уровне регистров, но стандартная среда IDE включает в себя attachInterrupt (n) и detachInterrupt (n), что упрощает интерфейс для внешних прерываний. Вы также можете использовать библиотеку смены контактов, чтобы упростить прерывания смены контактов.

Однако, не обращая внимания на библиотеку на минуту, мы можем установить, что прерывания смены контактов могут быть такими же быстрыми или быстрыми, как внешние прерывания. Во-первых, хотя смена выводов прерывает работу с пакетами выводов, вам не нужно включать весь пакет. Например, если вы хотите обнаружить изменения на выводе D4, этого будет достаточно:

Пример эскиза:

ISR (PCINT2_vect)
 {
 // handle pin change interrupt for D0 to D7 here
 if (PIND & bit (4))  // if it was high
   PORTD |= bit (5);  // turn on D5
 else
   PORTD &= ~bit (5); // turn off D5
 }  // end of PCINT2_vect

void setup ()
  { 
  // pin change interrupt (example for D4)
  PCMSK2 |= bit (PCINT20);  // want pin 4
  PCIFR  |= bit (PCIF2);    // clear any outstanding interrupts
  PCICR  |= bit (PCIE2);    // enable pin change interrupts for D0 to D7
  pinMode (4, INPUT_PULLUP);
  pinMode (5, OUTPUT);
  }  // end of setup

void loop ()
  {
  }

Мои тесты показывают, что потребовалось 1,6 мкс для «тестового» контакта (контакт 5), чтобы среагировать на изменение на контакте прерывания (контакт 4).


Теперь, если вы используете простой (ленивый?) Подход и используете attachInterrupt (), вы обнаружите, что результаты медленнее, а не быстрее.

Пример кода:

void myInterrupt ()
 {
 if (PIND & bit (2))  // if it was high
   PORTD |= bit (5);  // turn on D5
 else
   PORTD &= ~bit (5); // turn off D5
 }  // end of myInterrupt

void setup ()
  { 
  attachInterrupt (0, myInterrupt, CHANGE);
  pinMode (2, INPUT_PULLUP);
  pinMode (5, OUTPUT);
  }  // end of setup

void loop ()
  {
  }

Для смены контрольного штифта требуется 3,7 мкс, что намного больше, чем 1,6 мкс выше. Почему? Поскольку код, который должен сгенерировать компилятор для «универсального» обработчика прерываний, должен сохранять каждый возможный регистр (выдвигать их) при входе в ISR, а затем восстанавливать их (извлекать их) перед возвратом. Плюс накладные расходы при вызове другой функции.


Теперь мы можем обойти это, избегая attachInterrupt () и делая это сами:

ISR (INT0_vect)
 {
 if (PIND & bit (2))  // if it was high
   PORTD |= bit (5);  // turn on D5
 else
   PORTD &= ~bit (5); // turn off D5
 }  // end of INT0_vect

void setup ()
  { 
  // activate external interrupt 0

  EICRA &= ~(bit(ISC00) | bit (ISC01));  // clear existing flags
  EICRA |=  bit (ISC00);    // set wanted flags (any change interrupt)
  EIFR   =  bit (INTF0);    // clear flag for interrupt 0
  EIMSK |=  bit (INT0);     // enable it

  pinMode (2, INPUT_PULLUP);
  pinMode (5, OUTPUT);
  }  // end of setup

void loop ()
  {
  }

Это самый быстрый из них при 1,52 мкс - похоже, где-то был сохранен один такт.


Однако есть одно предупреждение для прерываний смены булавок. Они являются пакетными, поэтому, если вы хотите, чтобы прерывания были на большом количестве выводов, вам нужно проверить внутри прерывания, какое из них изменилось. Вы можете сделать это, сохранив предыдущее состояние контакта и сравнив его с новым статусом контакта. Это не обязательно особенно медленно, но чем больше пинов вам нужно проверить, тем медленнее это будет.

Пакеты являются:

  • От A0 до A5
  • От D0 до D7
  • От D8 до D13

Если вы просто хотите еще пару контактов прерывания, вы можете избежать любого тестирования, просто выбрав использование контактов из разных партий (например, D4 и D8).


Более подробная информация на http://www.gammon.com.au/interrupts

Ник Гаммон
источник
9

Есть два типа прерываний. Что сказал Arduino Playground :

Процессор, лежащий в основе любого Arduino, имеет два разных типа прерываний: «внешние» и «смена контактов». На ATmega168 / 328 есть только два внешних контакта прерывания (т. Е. В Arduino Uno / Nano / Duemilanove), INT0 и INT1, и они сопоставлены с выводами 2 и 3 Arduino. Эти прерывания могут быть установлены для запуска при RISING или Падение сигнала по краям или на низком уровне. Триггеры интерпретируются аппаратно, и прерывание очень быстрое. В Arduino Mega доступно еще несколько внешних выводов прерываний.

С другой стороны, прерывания смены контактов могут быть включены на многих других контактах. Для Arduinos на базе ATmega168 / 328 их можно включить на любом или на всех 20 сигнальных выводах Arduino; на Arduinos на базе ATmega их можно включить на 24 выводах. Они запускаются в равной степени на фронтах сигнала RISING или FALLING, поэтому именно код прерывания устанавливает надлежащие выводы для получения прерываний, определяет, что произошло (какой вывод? ... сигнал повышался или падал?), И обращаться с этим правильно. Кроме того, прерывания смены контактов сгруппированы в 3 «порта» на MCU, поэтому для всего тела контактов есть только 3 вектора прерываний (подпрограммы). Это делает работу по разрешению действия на одном прерывании еще более сложной.

По сути, внешние прерывания очень быстрые, поскольку все они аппаратные. Тем не менее, есть также прерывания смены контактов, но они кажутся намного медленнее, потому что они в основном программные.

tl; dr: 20 контактов прерывания вместе намного медленнее. 2 контакта прерывания самые быстрые и эффективные.


РЕДАКТИРОВАТЬ: Я только что посмотрел таблицу данных, и она говорит, что прерывание смены выводов запускается для любого из выбранных выводов без указания того, какой вывод был изменен (хотя он разделен на три вектора прерываний).

  • Для внешних прерываний он сообщит вам, что контакт 3 только что изменился
  • Для смены булавки вам сообщат, что булавка изменилась, что вы отслеживали!

Как вы можете видеть, прерывание смены штифта добавляет много служебной информации в ISR, которую вы должны обработать, сохраняя предыдущие состояния и проверяя, беспокоит ли вас этот штырь. Это может быть хорошо для состояния сна, но лучше использовать внешние прерывания.

Анонимный пингвин
источник