czwartek, 10 marca 2016

Ja Panu nie przerywałem!

Ciężki los mikrokontrolera

Oczekiwanie w pętli nieskończonej na interesujące nas wydarzenie nie wygląda najlepiej. Mało tego, może nieco poirytować nasz mikrokontroler. Sprawdzanie co jakiś czas czy się coś gdzieś nie zmieniło nie należy do najciekawszych zadań. Można w tym czasie policzyć jakąś całkę... Poza tym - czasy wszędobylskiego pollingu w dobie Reacta dawno minęły... chyba?

Na szczęście nie musimy postępować w ten sposób. Możemy skorzystać z wbudowanego mechanizmu przerwań. Co nam to daje? Ano wyzbycie się z kodu takich czy innych ifów. Póki co musimy zarządzać tym sprawdzającym stan przycisku. Niewiele, do ogarnięcia. Ale w przyszłości będziemy musieli obsłużyć bardziej złożone akcje (np. naciśnięcie kolejnego przycisku, czy obsługa komunikacji). Łatwo można sobie wyobrazić, jak bardzo nieczytelny stanie się kodzik, gdy w każdym przebiegu pętli będziemy sprawdzać po kolei, czy aby coś się nie zmieniło w naszym układzie... Pomijając fakt czytelności, kod nie zdobędzie nagrody najbardziej wydajnego na Świecie.

Czym zatem są wspomniane przerwania?

Przerwanie to takie zdarzenie w cyklu pracy procesora, które sprawia, że aktualnie wykonywany program jest przerywany (z zachowaniem potrzebnych rejestrów), a sterowanie przekazane jest do miejsca w pamięci programu, gdzie umieszczono kod odpowiedzialny za obsługę przerwania. Po wykonaniu tego kodu, sterowanie wraca do miejsca w kodzie programu, gdzie wystąpiło przerwanie. Proste? To tak, jakby pisać sobie w najlepsze kodzik, a ktoś by przyszedł i poprosił nas, żeby na coś zerknąć... Więc zerkamy a potem heja! do miejsca, w którym skończyliśmy.


Datasheet Twoim najlepszym przyjacielem

Atmega posiada wbudowany moduł obsługi przerwań. Datasheet zawiera opis wszystkich, z którymi możemy prędzej czy później mieć styczność. Często będę odsyłał Was do tego pełnego wiedzy wszelkiej pdf'a. gdyż tam jest źródło prawdy - nie na blogach, tylko w dokumencie publikowanym przez producenta. Posty mogą się przedawnić, nota katalogowa nie powinna :)
Atmega162 posiada 2 piny, dzięki którym możemy wyzwolić zewnętrzne przerwanie - na schemacie opisane INT0 i INT1. Podpinając przycisk do jednego z nich i odpowiednio konfigurując odpowiednie rejestry, możemy w elegancki sposób dokonać refaktoru naszego kodu.

Rejestry

Chcąc skorzystać z zewnętrznego przerwania INT0 musimy skonfigurować rejestry:

GICR |= (1 << INT0);


Oraz MCUCRgdy chcemy reagować na konkretną zmianę stanu na pinie INT0 (stan niski, jakakolwiek zmiana stanu, zbocze narastające - zmiana z 0 na 1, czy zbocze opadające - zmiana z 1 na 0) . Pozostawienie w nim wartości domyślnych (0) sprawi, że nasz mikrokontroler "wpadnie" w przerwanie, gdy na pinie pojawi się stan niski. Dodatkowo, po skonfigurowaniu przerwań, musimy wykonać makro, które poinformuje mikrokontroler, że chcemy z nich korzystać

Kodzik!

Jeszcze tylko obsługa przerwania i mamy gotowy kodzik - po naciśnieciu przycisku, zmień stan LEDów na przeciwny:

#include <avr/io.h>
#include <avr/interrupt.h>

int main(void)
{
   // set pd2 (INT0) as input
   DDRD &= (1 << PD2);

   // pull-up for pd2
   PORTD |= (1 << PD2);


   // set pb0 and pb1 pins as output
   DDRB |= (1 << PB0) | (1 << PB1);

   // turn off led connected to pb0
   PORTB |= (1 << PB0);

   // turn on led connected to pb1
   PORTB &= ~(1 << PB1);
   
   // enable INT0 interrupt
   GICR |= (1 << INT0);
   
   // enable global interrupts
   sei();

   while (1)
   {
   }
}

ISR(INT0_vect)
{
   PORTB ^= (1 << PB0);
   PORTB ^= (1 << PB1);
}


Warto pamiętać

Kod, który powinien wykonać się w ramach obsługi przerwania powinien być jak najkrótszy! Wszak ma to być przerwanie, nie zmiana kontekstu :) Jest to jedna z dobrych praktyk kodzenia na niskim poziomie.

I jeszcze notka wyjaśniająca - chwilowo jestem szczęśliwym człowiekiem cieszącym się benfitami płynącymi z przebywania na urlopie - jak tylko wrócę w okolice mojego zestawu deweloperskiego (atmega + programator) dorzucę conieco na githuba. Stay tuned!

Brak komentarzy:

Prześlij komentarz