Существует два типа прерываний типа «смена контактов». Внешние прерывания, которых на 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