Tym razem będzie o przerwaniu PCINT, które występuję w niektórych mikrokontrolerach rodziny AVR firmy ATMEL. Dzięki nim możliwe jest wykorzystanie każdego wyjścia jako źródło przerwania zewnętrznego. Różnica między przerwaniami PCINT a dobrze znanymi przerwaniami INT jest taka, że te pierwsze występują zawsze przy zmianie stanu (jest brak możliwości wyboru typu reakcji na stan wejścia) a przerwania INT można skonfigurować na 1 z 4 sposobów:
- Stan niski;
- Zmianę stanu;
- Na zbocze opadające;
- Na zbocze narastające;
Brak możliwości wyboru typu reakcji nie jest aż tak dużym utrudnieniem – można to rozwiązać programowo. Przedstawię to w dalszej części artykułu, lecz jeszcze trochę wyjaśnienia dot. działania przerwania PCINT. Otóż możliwe jest skonfigurowanie każdego wyjścia w ten sposób, aby generowało przerwania PCINT, lecz nie generuje on przerwania konkretnie dla danego wyjścia, lecz dla pewnej grupy – jeden wektor przerwania dla kilku wyjść. W zależności od ilości wyjść w mikrokotrolerze występuje odpowiednia ilość grup. Jest to ściśle związane z ilością portów – ile portów tyle grup przerwań PCINT. Przykładowo dla atmegi328 występują trzy takie grupy – na poniższym rysunku piny należące do tej samej grupy zostały oznaczone tym samym kolorem.

Piny portu B są w tej samej grupie, więc wektor przerwania dla tych pinów jest taki sam. Aktywację przerwania dokonuje się poprzez aktywowanie danej grupy przerwań (rejestr PICCR bity PCIE0, PCIE1, PCIE2), oraz zamaskowane (aktywację) pinu dla którego przerwanie ma wystąpić (odpowiednio rejestry PCMSK0, PCMSK1, PCMSK2). Możliwe jest wykonanie przerwania dla kilku pinów tej samej grupy.
//inicjalizacja PCINT8, oraz PCINT9
PCICR |= (1<<PCIE1); //aktywowanie przerwania od pcint
PCMSK1 |= (1<<PCINT8) | (1<<PCINT9); //dla tego pinu przerwanie będzie wykonywane przerwanie
Wektory przerwań przybierają następującą postać:
PCINT0_vect
PCINT1_vect
PCINT2_vect
W przypadku gdy chcemy, aby przerwanie wykonywane było dla kilku pinów tej samej grupy, ale reakcje były podejmowane w zależności od pinu, który wywołał to przerwanie, należy obsłużyć je programowo (dla przypomnienia – przerwanie występuje przy każdej zmianie stanu jednego z wybranych pinów). Np tak:
ISR(PCINT1_vect){
if( (PINC & (1 << PC0)) )
LED1_TOGGLE;
if( (PINC & (1<<PC1)) )
LED2_TOGGLE;
}
Zmiana stanu odpowiedniej diody będzie następowała po doprowadzeniu sygnału na odpowiedni pin. Jest to jeden ze sposobów – jeżeli macie jakiś inny to podzielcie się nim w komentarzach.
Jak widać obsługa tego przerwania jest bardzo prosta, a możliwości jakie nam to daje są ogromne. Zachęcam do stosowania nie tylko przerwań INT, ale również tu przedstawionych PCINT.
Dla przykładu pokażę kod wykorzystujący przerwanie PCINT. Będzie on powodował zmianę stanu diody LED w zależności od stanu na porcie wykorzystującym przerwanie PCINT. Sygnał zegarowy będzie pochodzić z układu RTC i występować będzie co 1 Hz (biblioteki dla zegara PCF8563p znajdują się w tym artykule).
#include <avr/io.h>
#include <avr/interrupt.h>
#include "I2C_TWI/i2c_twi.h"
#include "DS_PCF8563p/pcf8563p.h"
#define LED_TOGGLE PORTC ^= (1<<PC3)
//przerwanie od zegara RTC
ISR(PCINT1_vect){
if( (PINC & (1<<PC0)) )
LED_TOGGLE;
}
int main(void){
//********** inicjalizacja wyjścia - dioda LED
DDRC |= (1<<PC3);
i2cSetBitrate(200);
//********** inicjalizacja pcf8563p
register_twi_start_pcf(TWI_start);
register_twi_stop_pcf(TWI_stop);
register_twi_read_pcf(TWI_read);
register_twi_write_pcf(TWI_write);
//inicjalizacja wyjścia clkout na 1Hz
pcf8563p_set_clkout(CLKOUT_1HZ);
//inicjalizacja PCINT8
PCICR |= (1<<PCIE1); //aktywowanie przerwania od pcint
PCMSK1 |= (1<<PCINT8); //dla tego pinu przerwanie będzie wykonywane
sei();
while(1){
//jakiś program
}
}
I to byłoby na tyle o przerwaniach PCINT. Starałem się to opisać krótko, prosto i zrozumiale. W razie pytań, wątpliwości, ewentualnych błędów piszcie w komentarzach.Po więcej szczegółowych informacji zapraszam do not katalogowych.