PCINT0…39 — это входы для внешнего прерывания которое срабатывает при изменении состояния на входах PCINT0..39.
Следует отметить, что плата LGT8F328P-LQFP32 MiniEVB содержит не все входы PCINT, так в ней установлен микроконтроллер в корпусе LQFP32, полный набор входов PCINT содержит микроконтроллер выполненный в корпусе LQFP48.
За внешние прерывания отвечают несколько регистров:
Регистр PCICR — определяет какую группу входов использовать в качестве источника прерывания:
Группа PCIE4 отвечает за входы PCINT[32:39], PCIE3 за PCINT[24:31], PCIE2 за PCINT[16:23], PCIE1 за PCINT[8:15], PCIE0 за PCINT[0:7].
Пример использования:
PCICR |= (1 << PCIE0); // определяет группу входов PCIE0 PCINT0…7
Далее используются при необходимости пять регистров PCMSKn, каждый регистр отвечает за вход PCINTn в своей группе:
PCMSK0
PCMSK1
PCMSK2
PCMSK3
PCMSK4
Установка какого-нибудь бита из PCINT0…39 разрешает соответствующему выводу работать в качестве источника прерывания.
Одновременно можно задействовать несколько входов, которые будут работать как источник прерывания.
Пример использования:
PCMSK0 |= (1 << PCINT0); // использовать PCINT0 в группе PCIE0
PCIFR — регистр флагов
При смене логического уровня на любом из выводов PCINT0…39 происходит вызов прерывания, при этом устанавливается соответствующий флаг прерывания PCIF0…4 (на одну группу один флаг). Этот флаг очищается аппаратно после выхода из подпрограммы обработки прерывания.
Обработчики прерывания PCINTx_vect, каждый для своей группы.
Пример использования:
ISR(PCINT0_vect){ // — код — //} — при возникновении прерывания исполняется // — код — //
ISR(PCINT1_vect){ // — код — //} — при возникновении прерывания исполняется // — код — //
ISR(PCINT2_vect){ // — код — //} — при возникновении прерывания исполняется // — код — //
ISR(PCINT3_vect){ // — код — //} — при возникновении прерывания исполняется // — код — //
ISR(PCINT4_vect){ // — код — //} — при возникновении прерывания исполняется // — код — //
Пример:
int i; void setup() { DDRB |= (1 << PB5);// выход светодиода D13 (PB5) на плате Arduino DDRB &= ~(1 << 0); PORTB |= (1 << 0); // выход PCINT0 (D8) как выход, подтягивающий резистор включить PCICR |= (1 << PCIE0); // определяет группу входов PCIE0 PCINT0...7 PCMSK0 |= (1 << PCINT0); // использовать PCINT0 в группе PCIE0 } void loop() { PORTB |= (1 << PB5); // PB5 выход 1 if (i == 1)delay(5000); i = 0; // как сработает прерывание подождать 5 секунд } ISR(PCINT0_vect) { PORTB &= ~(1 << PB5); // погасить светодиод на D13 i = 1; }
Светодиод на плате Arduino Uno который подключен к PB5 горит всегда, если кратковременно замкнуть вход PCINT0 на GND, светодиод погаснет на 5 секунд и загорится вновь.
Пояснение работы кода:
Команда PORTB |= (1 << PB5) в loop() всегда устанавливает на выходе PB5 высокий уровень. Если кратковременно замкнуть вход PCINT0 на GND, то сработает обработчик прерывания PCINT0_vect, в котом находится команда PORTB &= ~(1 << PB5) которая переводит выход PB5 в низкий уровень, тем самым Мы видим как гаснет светодиод демонстрирующий работы прерывания. Далее в обработчике прерывания используется переменная i , которая становится равной 1. Эта переменная нужна чтобы сработало условие:
if (i == 1)delay(5000); i = 0;
После того как сработает условие следует пауза в 5 секунд, переменная i становится равной 0, тем самым запрещая выполнение условия. Пауза в 5 секунд необходима для демонстрации работы внешнего прерывания, так как без паузы после того как погаснет от прерывания светодиод, он тут же снова загорится, так как команда PORTB |= (1 << PB5) в loop() всегда устанавливает на выходе PB5 высокий уровень.