Arduino Polska Forum
Przerwania od wszystkich pinów. - Wersja do druku

+- Arduino Polska Forum (https://forum.arduinopolska.pl)
+-- Dział: Inne (https://forum.arduinopolska.pl/dzial-inne)
+--- Dział: Poradniki (https://forum.arduinopolska.pl/dzial-poradniki)
+--- Wątek: Przerwania od wszystkich pinów. (/watek-przerwania-od-wszystkich-pin%C3%B3w)



Przerwania od wszystkich pinów. - Robson Kerman - 02-09-2018

Część pierwsza:
WPROWADZENIE

Czasami, budując jakieś urządzenie, na przykład z dużą ilością przycisków, z klawiaturą matrycową, lub co tam sobie wymyślicie,
dochodzi to sytuacji, gdy potrzebowali byśmy większej ilości przerwań zewnętrzych niż tylko INT0 oraz INT1.
Nie mam pojęcia dla czego twórcy "języka" Arduino uszczęśliwili nas jedynie dostępem do INT0 i INT1, ale wiem że pisząc aplikację w języku C dla AVR, takich ograniczeń nie ma.
Czytając notę katalogową Atmega328 rozdział 17, zatytułowany "EXINT - External Interrupts", możemy przeczytać takie zdanie:
"The External Interrupts are triggered by the INT pins or any of the PCINT pins."
Co oznacza, że przerwania zewnętrzne wyzwalane są przez piny INT, oraz piny PCINT.
Są pewne różnice między obydwoma typami przerwań, na przyklad przerwanie INT może wybudzać procesor z trybów uśpienia innych niż IDLE, czyli z zatrzymanym zegarem, oraz może być wyzwalane poziomem.
PCIN wyzwalane jest zmianą stanu, nie ma możliwości określenia jaka to zmiana.

W uC zastosowanym w Aruino Uno, wszystkie piny oznaczone są jako PCINT.

[Obrazek: yGr18tC.jpg]

Mamy doczynienia z trzema przerwaniami od portu. Rządanie przerwania 0, czyli PCI0, wyzwalane jest pinami oznaczonymi jako PCINT0 do PCINT7.
PCI1 pinami PCINT8 do PCINT14, a PCI2 pinami PCINT16 do PCINT23.
Dwadzieścia trzy piny z przerwaniem to już coś, to znaczy dla Uno będzie ich 20.
Włączenie rządania przerwania od wszystkich pinów daje nam dostęp do trzech wektorów obsługi przerwań.
Oznacza to, że jeśli na przykład przerwanie nadejdzie z któregoś pinu z zakresu PCINT(7:0) uruchomi się rządanie przerwania 0, dla PCINT(14:8) rządanie przerwania 1 itd.
Włączenie obsługi przerwań i zmiany stanu pinów jest ustawiane w rejestrze zwanym Pin Change Interrupt Control Register, czyli w skrócie PCICR.
Posiada on trzy bity kontrolne PCIE0, PCIE1 oraz PCIE2. Każdy z tych bitów odpowiada za włączenie obsługi przerwań PCI0, PCI1 oraz PCI2, o których wspomniałem wcześniej.
Jeśli chcemy włączyć obsługę przerwania dla wszystkich portów, musimy napisać:

Kod:
PCICR |= (1<<PCIE0)|(1<<PCIE1)|(1<<PCIE2);


Dla portu PORTD, czyli w Uno będą to piny cyfrowe od 0 do 7, będzie to wyglądać tak:

Kod:
PCICR |= 1<<PCIE2;


Jeśli chcemy uruchomić przerwanie od powiedzmy pinu 7, czyli PCINT23, musimy napisać:


Kod:
PCICR |= 1<<PCIE2; // rejestr PCICR skanuje PORTD
  //Aby rozpoznać od jakiego pinu nadeszło przerwanie, stosuje się maskę PCMSKx,
  //gdzie x oznacza numer przerwania (2:0).
PCMSK2 |= 1<<PCINT23; // sprawdź na rysunku "Arduino Uno pinout diagram" numery
                                      //przerwań dla pinów w Arduino.

/*Obsługa przerwania wygląda tak:*/

ISR (PCINT2_vect)
{
    /* wpisz kod obsługi przerwania */
}


Przerwanie wywoływane jest zmianą stanu pinu.
Kod powyżej będzie w takim razie dla CHANGE.
Dla sprawdzenia jaka jest to zmiana:


Kod:
ISR (PCINT2_vect)
{
    if( (PIND & (1 << PIND7)) == 1 )
    {
      // tutaj mamy RISING
    }
    else
    {
      // a tutaj mamy FALLING
    }
}


Obsługiwany jest tylko jeden wektor dla całego portu, więc gdy napiszemy na przykład:

Kod PHP:
PCMSK2 |= (1<<PCINT20)|(1<<PCINT21)|(1<<PCINT22)|(1<<PCINT23); 

 
to i tak wykonamy kod dla wektora PCINT2_vect dla każdego z powyższych przerwań.

Nie jest to oczywiście żaden problem, ponieważ w następnej części napiszemy funkcję obsługi przerwań dla każdego pinu oraz typu wyzwalania.
Wszystko władujemy do pliku nagłówkowego, który będziemy dołączać do naszych projektów.
Udostępnimy ję na jakimś githubie (chyba nasze forum nie posiada oficjalnego GITa?), może być na moim.

Oczekujcie drugiej części niebawem.
(Czyli pewnie w następny weekend)


RE: Przerwania od wszystkich pinów. - es2 - 02-09-2018

(02-09-2018, 16:00)Robson Kerman napisał(a): Obsługiwany jest tylko jeden wektor dla całego portu, więc gdy napiszemy na przykład:

Kod PHP:
PCMSK2 |= (1<<PCINT20)|(1<<PCINT21)|(1<<PCINT22)|(1<<PCINT23); 

 
to i tak wykonamy kod dla wektora PCINT2_vect dla każdego z powyższych przerwań.

Nie jest to oczywiście żaden problem, ponieważ w następnej części napiszemy funkcję obsługi przerwań dla każdego pinu oraz typu wyzwalania.

Czasem, zwłaszcza z bibliotekami Arduino, nie będzie możliwe określenie, które GPIO wywołało przerwanie.


RE: Przerwania od wszystkich pinów. - Robson Kerman - 06-09-2018

Miałem właśnie wkleić następną część artykułu o wiele mówiącym tytule:

TEORIA
Ale coś mnie natchnęło.

Zazwyczaj, gdy chodzi o produkty Atmela(to znaczy Microchipa, ale serię Atmega), pracuję w Atmel Studio, więc nie mam dostępu do takich dobrodziejstw, do jakich mają rasowi arduinowcy, czyli do zarządzania bibliotekami.
Ale wszystko się zmieniło, gdy zainstalowałem sobie VisualMicro, ponieważ tam mam możliwość przeszukiwania internetu i ściągania bibliotek wszelkiej maści.
Pobrałem więc bibliotekę o nazwie PinChangeInterrupt.
A tam mamy możliwości dokładnie takie same, jakie daje nam funkcja AttachInterrupt, z tą różnicą, że zamiast numeru przerwania wpisujemy numer pinu.
Zdajmy sobie sprawę, że ten sposób obsługi przerwań jest bardziej czasochłonny od obsługi INT0, oraz INT1, ale jest to kilka cykli zegarowych i dla potrzeb amatorskich (bo nie oszukujmy się, profesjonaliści nie bawią się w Arduino) jest to wystarczające.

Jeśli jest na forum ktoś, kto chciał by poznać teorię traktującą o przerwaniach, pracy z portami, obsłudze zdarzeń i innych sprawach dotyczących sprzętu, to proszę się nie krępować, jestem do Waszej dyspozycji.
A cha, mam też swoją bibliotekę, tylko dla Atmega328 i pochodnych. Jak ktoś chce, to mogę wstawić.

Pozdrawiam.