Święta IT, czyli choinka sterowana pecetem

Nieodzownym elementem jest jeszcze rezonator kwarcowy, a w zasadzie generator taktujący, czyli coś, co będzie generować takty, w których sekwencyjnie, krok po kroku nasz mikrokontroler będzie wykonywał operacje zapisane w pamięci programu. Na schemacie ideowym płytki sterownika rezonator kwarcowy oznaczony jest literą "Q". ATtiny2313 posiada wewnętrzny oscylator 8 MHz i jego użycie nie było aż taką koniecznością, ale w miejsce tego mikrokontrolera można też użyć AT90S2313, który nie jest już produkowany, ale czasem można go gdzieś spotkać.

Każdy mikrokontroler posiada jeszcze układ "resetu". W niektórych typach kontrolerów jest on bardziej skomplikowany, w innych mniej. W przypadku rodziny AVR nóżkę RESET podłączamy przez rezystor do "plusa" zasilania, aby zapobiec przypadkowym resetom urządzenia w wyniku np. zewnętrznych impulsów elektromagnetycznych, powstających przy włączaniu choćby monitora. Reset służy do tego samego co w komputerze PC - ponowny start urządzenia. Wywołuje się go specjalnie w różnych sytuacjach, ale my używać go będziemy tylko i wyłącznie do programowania urządzenia, dlatego wyprowadzenie RESET zostało podłączone do złącza programatora (programowanie odbywa się, gdy RESET jest ustawiony na 0, czyli urządzenie nie pracuje).

Teraz krótko na temat portów. Port w mikrokontrolerze, to interfejs wejścia/wyjścia, czyli to, co łączy procesor ze światem rzeczywistym. Zwykle porty w 8-bitowych mikrokontrolerach (np. AVR) są właśnie 8-bitowe, co przejawia się tym, że port ma 8 nóżek, na których występować mogą stany wysokie lub niskie - zera lub jedynki, zgodnie z zasadą, że jeden bit to jedna "nóżka" portu. Prościej nie da się chyba wytłumaczyć. Dla większości będą to rzeczy nowe, więc oto przykład: ustawiając wartość poru B na '7' dziesiętnie - zostaną ustawione na stan wysoki linie portu 0, 1, 2 - dlaczego? A dlatego, ponieważ 7 dziesiętnie to binarnie 00000111 (pozycja pierwsza jest od prawej strony). Proste? Super.

Większość mikrokontrolerów posiada możliwość zmiany "kierunku" przepływu danych przez port. A to oznacza, że port / linie portu mogą być wyjściem - wtedy możemy czymś sterować lub coś wysyłać z danej linii / portu, lub wejściem, wtedy można odczytywać dane (stany logiczne 0 lub 1) z jakiegoś konkretnego urządzenia. Do przełączenia kierunku służy specjalny rejestr kierunku przepływu danych. Ustawiając w nim odpowiednią wartość ustawiamy port na wejście lub wyjście. Prosta sprawa. Może w tym momencie wydaje się to trudne, bo "sucha" teoria zwykle stwarza takie wrażenie, ale już niedługo.

Co to są te rejestry? Rejestr to takie miejsce w pamięci, do którego zapisujemy konkretne ustawienia "czegoś", możemy za pośrednictwem rejestru sprawdzić stan któregoś z peryferii. W niektórych rejestrach można przechowywać dane, inne rejestry służą do parametryzacji mikrokontrolera. Rejestry zawsze są skojarzone z nazwą, np. rejestr kierunku danych portu A to w mikrokontrolerze AVR: DDRA (Data Direction Register A), rejestr wartości timera/licznika 0 to TCNT0. Jak widać rejestry to nic strasznego.

Timer / licznik to element mikrokontrolera, który zlicza coś niezależnie od działania programu. Niezależnie pod tym względem, że raz ustawiony nie wymaga późniejszej ingerencji programu. Timery służą zazwyczaj do odmierzania czasu pomiędzy jakimiś operacjami. My będziemy używać timera do wyznaczania limitu czasu na odebranie pełnej ramki danych od komputera oraz do odmierzania czasu pomiędzy kolejnymi krokami "programu mrugania lampkami". Timery w większości mikrokontrolerów mogą wywołać przerwanie, gdy np. zliczając w górę "dojdzie" do jego skrajnej wartości (Timer Overflow - przepełnienie).

Teraz do kompletu muszę wspomnieć o przerwaniach. Zapewne każdemu użytkownikowi komputera to słowo obiło się o uszy. Wyobraźmy sobie, że nasz mikrokontroler wykonuje w nieskończonej pętli coś, np. na przemian zmienia stan któregoś z portów. Teraz komputer PC wysyła do naszego układu znak. Normalnie kontroler by tego nie przechwycił, gdyby nie przerwanie. Mikrokontroler "przerywa" na moment pracę i "skacze" do funkcji obsługi przerwania. Tam odbieramy znak, przetwarzamy go i na koniec "skaczemy" z powrotem do miejsca w programie, na którym skończyliśmy ostatnio. Jest to ogólna zasada działania przerwań. Większość pracy związanej z obsługą przerwań (te "skoki") wykonuje za nas kompilator (np. AVR-GCC, czy CodeVision AVR i inne). Nasze zadanie ogranicza się do napisania funkcji obsługi z odpowiednimi parametrami. Mikrokontrolery posiadają różną ilość przerwań, od zera do kilkunastu. Przerwania występują w najprzeróżniejszych sytuacjach, np. przepełnienie licznika, odbiór znaku z UART, zewnętrzne przerwanie - pojawił się stan wysoki na odpowiednim wejściu portu, itp. Przerwania możliwe do wystąpienia zależą od typu mikrokontrolera.

Na koniec pozostało nam omówienie interfejsu szeregowego UART. Nie będziemy się szczegółowo zajmować tym interfejsem, ponieważ szczegółowa zasada działania nie jest nam na tym etapie potrzebna. UART wykorzystuje dwie linie do przesyłania danych: TX - nadawanie, RX - odbiór. Jest to interfejs FULL DUPLEX, czyli jednocześnie można nadawać i odbierać dane. Transmisja odbywa się z określoną prędkością. Nie istnieje żaden mechanizm "negocjacji połączenia" pomiędzy komputerem i mikrokontrolerem, dlatego obie strony muszą być skonfigurowane w identyczny sposób.