Promocja na książki: elektroniki, Arduino, programowanie, IT od 6,90 zł. Sprawdź listę ponad 350 tytułów »

Port szeregowy i interfejs USART – #2

Port szeregowy i interfejs USART – #2

Poprzednia część praktycznie w całości została poświęcona tworzeniu programu od strony komputera. Teraz przyszła pora zająć się mikrokontrolerem.

W tej części dokonałem przeglądu prostych technik programistycznych związanych z pisaniem programu na AVRa.

« Poprzedni artykuł z serii

Program reagujący na przychodzące dane

Jak wiadomo istnieją dwie szkoły obsługi układów peryferyjnych mikrokontrolera. Przez tak zwany polling, czyli sprawdzanie odpowiedniej flagi w głównej pętli programu oraz przez system przerwań.

W przypadku interfejsu USART pierwszy sposób nie jest zbyt praktyczny, dlatego zajmiemy się obsługą przerwaniową. Zdarzeniem wyzwalającym przerwanie będzie odebranie wiadomości. Reakcją układu będzie wysłanie wiadomości zwrotnej. Program działający w ten sposób jest nieprzyzwoicie wręcz prosty:

Moja Atmega działa na zewnętrznym kwarcu 18,432MHz. Przed wgraniem programu należy pamiętać o odpowiedniej modyfikacji fuse bitów. Dzięki wpisaniu stałej baudrate oraz zastosowaniu wzoru na baud prescale, powyższy kod jest niezwykle prosty do przystosowania dla innych częstotliwości.

Dalsza część kodu jest podzielona na 3 części - konfiguracja USARTa, główna pętla i przerwanie od Rx. Komentarze do kodu tłumaczą działanie poszczególnych części. Zwracam tutaj uwagę na zmienną pomocniczą a, która jest niezbędna, aby dokonać jakiejś obróbki otrzymanej wiadomości. Drugą, wyraźnie widoczną w tym kodzie rzeczą jest podwójna rola rejestru UDR, przechowującego raz odbieraną, a raz wysyłaną informację w zależności od tego, po której stronie znaku równości się znajduje.

Kolejną ważną obserwacją jest to, że zapis UDR = a jest wystarczający do wysłania wiadomości i dzięki niemu nie trzeba już wykonywać żadnych dodatkowych operacji. Aby przetestować działanie programu, wystarczy użyć terminala z poprzedniej części artykułu.

Program przesyłający dane do komputera

Innym prostym, aczkolwiek niezwykle przydatnym (szczególnie przy debugowaniu, testowaniu czy identyfikacji układów) programem jest praca USARTa, ograniczająca się do samego wysyłania danych.

Tym razem nasz program potrzebował tylko pinu Tx interfejsu, aby wysyłać dane do komputera. Jego zadaniem było wysyłanie danych co określony czas. Z tego powodu właśnie zostało użyte przerwanie od timera.

Jak widać przerwanie od USARTa nie było tu w ogóle potrzebne. Do komputera wysyłane były dane odczytane z portu B mikrokontrolera. Do czego mogłaby się przydać podobna aplikacja? Wyobraźmy sobie, że do portu B podłączone są czujniki linefollowera, a zamiast pustej pętli, wykonuje się algorytm PID i sterowanie PWMem. W ten prosty sposób możemy otrzymać informacje o odczytach czujników.

Poza tym nic nie stoi na przeszkodzie, żeby zamiast wartości PINB wysyłać na przykład wartość PWM czy odczyty ADC. Tego typu informacje o działaniu układów mikrokontrolera są wprost niezastąpione w procesie tworzenia programów. Ten tryb pracy jest również bardzo przydatny, jeśli nasz układ ma zajmować się mierzeniem i archiwizowaniem jakichś danych pomiarowych. Na przykład: co określony przedział czasu ma wysyłać do komputera analogowy odczyt z czujnika temperatury. Po stronie komputera można bez problemu dopisać odpowiedni kod, zapisujący te dane do plików, robiący wykresy itp.

Podobny program, tylko napisany w asemblerze zastosowałem do dekodowania sygnału z pilota. Był mi potrzebny do odtworzenia ramki danych odczytywanej przez mikrokontroler. Więcej szczegółów w odpowiednim artykule: http://www.forbot.pl/forum/topics20/komunikacja-jak-przystosowac-domowego-pilota-do-wlasnych-celow-vt5994.htm

Buforowanie danych

Podczas wysyłania informacji może się okazać, że niektóre dane są gubione. Dzieje się tak dlatego, że są one generowane szybciej niż układ może je wysyłać. W tym wypadku przydatne może okazać się stworzenie programowego bufora czyli struktury FIFO (first in first out, po polsku kolejka). Jest to tablica o zadanej przez nas wartości oraz zmienna, wskazująca koniec tablicy.

Dopisanie elementu powoduje inkrementację wskaźnika, natomiast wysłanie powoduje przesunięcie wszystkich elementów tablicy na wyższą pozycję oraz dekrementację wskaźnika.

Alternatywą dla takiej kolejki może być bufor cykliczny, w którym mamy wskaźnik na pierwszy element i miejsce za ostatnim elementem, w które można zapisać nową daną. Wysłanie danych powoduje zwiększenie wartości wskaźnika początku, natomiast dopisanie zwiększa końcowy wskaźnik. Struktura jest pusta jeśli oba wskaźniki są sobie równe, poza tym niezbędne jest ograniczenie, aby dodawanie danych nie nadpisywało początku.

Należy pamiętać, że dopisanie danej do bufora nie powoduje bezpośrednio wysłania. Trzeba zawsze sprawdzić, czy bufor jest pusty i jeśli tak, wysłać dane w sposób klasyczny. Zastosowanie tego typu struktury pozwala na zatrzymanie w pamięci informacji, które normalnie byłyby tracone i dosłanie ich później, gdy nowe dane przestaną dochodzić.

Powyższy kod to modyfikacja poprzedniego przykładu - w praktyce nie zmieniająca jego funkcjonalności. Możemy tutaj jednak zobaczyć strukturę bufora cyklicznego oraz funkcje dopisywania i wysyłania.

Dodatkowo, doszło przerwanie od zwolnienia rejestru, z którego są wysyłane dane, a w nim wysyłana jest jedna wiadomość z bufora. Zmodyfikowane zostało także przerwanie od timera, żeby wysyłanie się nie zawieszało, kiedy nie dochodzą do bufora nowe dane. W przykładzie bufor ma 16 bajtów, ale wartość tę można łatwo zmienić dzięki zadeklarowaniu stałej na początku.

Bufory mają szerokie zastosowanie w transmisji danych. Można je stosować również przy odbiorze. Sprawdzają się idealnie, kiedy raz na jakiś czas musimy szybko przesłać dużą porcję informacji, a łącze nie jest wykorzystywane pomiędzy pakietami.

Po stronie komputera klasa Visual C# SerialPort ma zaimplementowane buforowanie danych wysyłanych oraz odbieranych. Operacje na buforach można tam wykonywać, traktując je jako Stringi, tablice bajtów lub tablice charów. Więcej szczegółów można znaleźć na msdn.

Wydawanie poleceń

Popularną konfiguracją jest układ, w którym komputer wysyła polecenia sterujące, natomiast mikrokontroler zgodnie z nimi zmienia swój tryb pracy, czy wysyła informacje zwrotne. Można to bardzo prosto zrealizować za pomocą zdefiniowanych stałych oraz polecenia sterującego switch w funkcji przerwania od odebranej wiadomości.

Program w przerwaniu odczytuje otrzymaną daną, a następnie - w zależności od jej wartości - podejmuje odpowiednią akcję. Można odczytać lub zmienić wartość jednej ze zmiennych a, b lub c, albo rozpocząć lub zakończyć przesyłanie aktualnych wartości portu B.

Zmienna pomocnicza stan pozwala na budowanie kolejnych poziomów, na których może znajdować się program. Na każdej gałęzi wykonywane są inne polecenia. W ten sposób można zbudować nawet skomplikowane drzewa zależności. Oczywiście kod zaprezentowany powyżej jest tylko przykładem i nic wielkiego nie robi. Pomaga jedynie zrozumieć ogólną zasadę działania.

Podsumowanie

Mam nadzieję, że przedstawione tutaj przykłady dobrze pokazują podstawy obchodzenia się z USARTem. Doświadczeni programiści pewnie nie znaleźli tutaj nic ciekawego. Myślę jednak, że początkujący będą mieli ułatwione zadanie dzięki tym kilku przykładom.

Artykuł był pisany w pośpiechu, a sprzęt na którym robiłem testy wiele już przeszedł, dlatego możliwe, że wkradły się jakieś błędy. Jeśli coś nie będzie działać, dajcie znać, a postaram się wyłapać i poprawić ewentualne błędy. Po raz kolejny artykuł okazał się za mały, aby wyczerpać temat.

W dalszym ciągu brakuje opisu protokołu komunikacyjnego z prawdziwego zdarzenia czy dedykowanego programu w C# do obsługi konkretnego układu przy pomocy USARTa. Poza tym możnaby poruszyć temat bootloaderów. Jeśli będę miał więcej czasu oraz będzie takie zapotrzebowanie, prawdopodobnie powstaną kolejne części.

« Poprzedni artykuł z serii

avr, bufor, komunikacja, odbieranie, przerwania, RS232, rxd, txd, USART, wysyłanie

Trwa ładowanie komentarzy...