K U R S
AVR GCC: kompilator C dla
mikrokontrolerów AVR, część 11
Obsługa interfejsu USART
Jako uzupełnienie odcinków o przerwaniach przedstawimy
kilka przykładów ich praktycznego zastosowania. Jednym
z najpopularniejszych przykładów jest obsługa interfejsu
komunikacji szeregowej USART.
Zazwyczaj pierwsze próby uru- klu 0,125 ms) traci bezproduktyw- Wszystkich powyższych niedo-
chomienia komunikacji szeregowej nie 67000/0,125=536000 cykli (!) godności unikniemy stosując prze-
opierają się na wykorzystaniu pętli tylko na oczekiwanie, aż powolny rwania. Każdy przychodzący znak
oczekujących na wystąpienie odpo- interfejs szeregowy wykona swoją wywołuje przerwanie SIG_UART_
wiednich stanów portu USART: pracę. W praktyce będzie to czas RECV, w którego obsłudze wyko-
o p r ó ż n i e n i a r e j e s t r u U D R krótszy, gdyż zwykle przy pierw- nujemy potrzebną czynność (czyli
w przypadku nadawania wte- szym znaku rejestr jest zwolniony, przede wszystkim przepisanie zna-
dy możemy wpisać kolejny bajt poza tym na ogół obecnie stosu- ku z UDR do bufora), a poza prze-
do wysłania, jemy znacznie większe szybkości rwaniem program cały czas nor-
pojawienia się nowego (jeszcze przesyłu, jednak i tak dla mikro- malnie pracuje sprawdzając jedynie
nie odczytanego) znaku (bajtu) kontrolera jest to bardzo dużo. okresowo czy przyszły jakieś nowe
w rejestrze UDR odbiornika (dla Oczywiście nie ma sprawy jeśli ko- komunikaty/komendy/dane (to oczy-
przypommnienia: rejestr pod tą munikacja jest czynnością nadrzęd- wiście zawsze będzie zależeć od
samą nazwą obsługuje dwie róż- ną i możemy sobie w programie na konkretnego sposobu w jaki zorga-
ne funkcje, nadawanie przy zapi- takie czekanie pozwolić gorzej nizowaliśmy sobie protokół komu-
sie oraz odbiór przy odczycie). gdy zabiera ono moc obliczenio- nikacji).
Jest to zrealizowane poprzez wą jakimś innym, być może kry- Z kolei w celu wysłania pakie-
polling (cykliczne kontrolowanie) tycznym czasowo, zadaniom. tu danych ładujemy bufor nada-
wartości flag odpowiadających tym Z odbieraniem jest zupełnie zle. wania potrzebną zawartością i po
stanom. Podczas nadawania przed Wchodząc w pętlę oczekiwania na prostu uruchamiamy przerwanie
każdym wpisem znaku do UDR znak uzależniamy działanie naszego nadajnika w jego obsłudze prze-
sprawdzamy czy zapalona jest fla- programu od czynnika zewnętrznego pisujemy kolejne znaki z bufora do
ga wskazująca na jego opróżnienie, oddalonego nadajnika, który ten rejestru UDR a po ostatnim znaku
np. w taki sposób: znak może przysłać prędzej, pózniej wyłączamy przerwanie (tutaj także
void Wyslij_znak (uchar Znak)
albo wcale (co skutecznie obez- szczegółowe rozwiązanie zależy od
{
while ((UCSRA & _BV(UDRE)) == 0);
while ((UCSRA & _BV(UDRE)) == 0);
while ((UCSRA & _BV(UDRE)) == 0);
władni nasze urządzenie). Takie przyjętego protokołu). Pętla głów-
// czekaj do ustawienia flagi UDRE
UDR = Znak; rozwiązanie ma sens jedynie przy na przygotowuje dane i rozpoczyna
// wpisz znak do rejestru
nawiązywaniu terminalowej komuni- transmisję pózniej już nie musi
}
Dla odebrania znaku również kacji z operatorem. Aatwo zauważyć, się przebiegiem procesu nadawania
oczekujemy na zapalenie odpowied- że jest to przeniesienie żywcem w ogóle zajmować.
niej flagi, np. w taki sposób: zasad programowania znanych z kon- Jeśli zajmowaliśmy się progra-
uchar Czytaj_znak (void)
solowych aplikacji PC: program zgła- mowaniem mikrokontrolerów rodzi-
{
while ((UCSRA & _BV(RXC)) == 0);
while ((UCSRA & _BV(RXC)) == 0);
while ((UCSRA & _BV(RXC)) == 0);
sza komunikat, czeka cierpliwie na ny 51 zwróćmy uwagę na zasad-
// czekaj do ustawienia flagi RXC
return UDR; wprowadzenie danych
// odczytaj odebrany znak z rejestru
lub komendy w klawia-
}
Nadawanie, oczywiście, będzie tury, wykonuje zlecone
działać bez problemów, ale kosz- zadanie i wypisuje wy-
tem znacznego marnowania czasu nik. Ten schemat prze-
procesora. Na przykład przesłanie ważnie zupełnie nie
bloku 64 bajtów z szybkością 9600 pasuje do większości
baud (przy 8 bitach danych, 1 bi- zastosowań mikrokon-
cie stopu i bez bitu parzystości, trolerów ukierunko-
czyli przy 10 bitach na znak) zaj- wanych na działanie
muje 640/9600=ok. 67 ms. To bar- samodzielne po raz
dzo niewiele w skali operatora ter- kolejny zauważamy, że
minala, jednak np. mikrokontroler w świecie małych ko-
ATmega pracujący z częstotliwością stek obowiązują nieco
8 MHz (czyli z czasem trwania cy- inne reguły. Rys. 27. Okno konfiguratora ustawień portu USART
Elektronika Praktyczna 1/2006
100
K U R S
TX_OFF;
niczą różnicę w działaniu przerwa- ka do własnych plików nagłówko-
TX_BUSY = false;
}
nia nadajnika: wych) i zapisujemy projekt jako ...\
}
w 51 jest ono wywoływane do- Przyklad 05\test05.gcp. W ten spo-
SIGNAL (SIG_UART_RECV)
piero po wysłaniu kolejnego sób utworzyliśmy kopię poprzed- {
RxBuffer[0] = UDR;
znaku; aby zapoczątkować pracę niego projektu, którą teraz możemy if (! TX_BUSY) NEW_COMMAND = true;
}
nadajnika ustawialiśmy samo- rozwijać pozostawiając wcześniejszy
dzielnie w programie flagę TI; przykład w stanie nie naruszonym. Szablony handlerów przerwań
w AVR jest odwrotnie: przerwa- Do pliku projdat.h dopisujemy tworzymy korzystając z opisanego
nie (SIG_UART_DATA) jest ak- kilka nowych definicji, zmiennych wcześniej okienka autokompletacji
tywne zawsze gdy rejestr UDR (klasyfikator volatile dla zmiennych kodu. Natomiast dla ustawienia
jest pusty i gotowy na przyjęcie używanych w przerwaniach !) oraz parametrów USART użyjemy wspo-
następnego znaku; oznacza to, deklaracji funkcji: magającego konfiguratora. Polecenie
#define RXSIZE 4
że będzie wywołane przed wy- Narzędzia > Kreator kodu >
// rozmiar bufora odbiornika
słaniem znaku, natychmiast po Atmega usart otwiera okienko po-
volatile Flags UsartFlags;
odblokowaniu przerwania. // flagi stanu portu szeregowego kazane na rys. 27. Wybieramy we-
Błędem będzie więc w AVR dług potrzeb:
volatile char RxBuffer[RXSIZE];
// definicja bufora odbiornika
odblokowanie na stałe SIG_UART_ Długość słowa danych, liczbę
#define NEW_COMMAND UsartFlags.Bits.Flag1
#define NEW_COMMAND UsartFlags.Bits.Flag1
#define NEW_COMMAND UsartFlags.Bits.Flag1
DATA, a dopiero pózniej wysyłanie bitów stopu i rodzaj parzystości.
#define TX_BUSY UsartFlags.Bits.Flag2
#define TX_BUSY UsartFlags.Bits.Flag2
#define TX_BUSY UsartFlags.Bits.Flag2
// wygodne nazwanie poszczególnych flag
znaków, przerwanie bowiem za- Szybkość transmisji. Do dyspo-
stanu portu
cznie pracować od razu wywołując zycji mamy konwencjonalny sze-
extern void InitUsart(void);
na ogół nieoczekiwane efekty. extern void SendAnswer(int AnswerId); reg szybkości RS 232 oraz war-
extern void SendPrompt(void);
Zauważmy jednak, że nie do- // deklaracje funkcji obsługi USART
tość dowolną (USER) przydatną
tyczy to drugiego wbudowanego przy mniej typowych rozwiąza-
Dodajemy nowy moduł usart.c o następują-
cej treści:
w AVR przerwania: SIG_UART_ niach. Pole Error pokazuje nam
Error
Error
// obsługa USART
#include projdat.h
TRANS, które zachowuje się od- na bieżąco procentową odchyłkę
#include
#include
wrotnie, jest bowiem uaktywniane szybkości rzeczywiście możliwej
po kompletnym wysłaniu całe- #define TX_ON (UCSRB |= _BV(UDRIE)) do uzyskania (przy stosowanej
#define TX_ON (UCSRB |= _BV(UDRIE))
#define TX_ON (UCSRB |= _BV(UDRIE))
#define TX_OFF (UCSRB &= ~_BV(UDRIE))
#define TX_OFF (UCSRB &= ~_BV(UDRIE))
#define TX_OFF (UCSRB &= ~_BV(UDRIE))
go znaku (łącznie z bitem stopu) w projekcie częstotliwości oscy-
// włączanie i wyłączanie przerwań na-
dajnika
z rejestru przesuwnego nadajnika latora) od pożądanego ideału.
volatile static char *TxPtr;
na pin TxD, pod warunkiem, że Aatwo zauważymy, że wbudowa-
// wskaznik na znak wysyłany
w tym momencie rejestr UDR jest ny generator 8 MHz dopuszcza
static char Prompt[] = Gotowość do od-
pusty (a więc był to ostatni wysy- bioru komendy 1 3.\n ;
tylko kilka wartości z typowego
// tekst zgłoszenia
łany znak). Takie działanie (wykry- szeregu. Doskonale natomiast
static char Odp0[] = Nie mogę określić
cie końca przekazywania ostatniego nadaje się do nawiązania ko-
komendy: (!\n ;
static char Odp1[] = Wykonuję komendę
znaku w pakiecie do linii transmi- munikacji USB z użyciem kost-
numer jeden.\n ;
static char Odp2[] = Wykonuję komendę
syjnej) jest przewidziane specjalnie ki FT8U232BM i szybkościami
numer dwa.\n ;
static char Odp3[] = Wykonuję komendę
dla przypadków łączności half 125 kbaud lub 250 kbaud (do
half du-
half
numer trzy.\n ;
plex
plex sprawy używania wewnętrzne-
plex (np. przy jednoparowym RS // teksty odpowiedzi na komendy
485) w celu prawidłowego prze- static char *AnswerTable[] = {Odp0,Od- go generatora jeszcze za chwilę
p1,Odp2,Odp3};
łączenia interfejsu linii z powrotem
// tablica wskazników na komunikaty od- powrócimy).
powiedzi
w tryb odbioru. W zwykłej trans- Włączenie nadajnika, odbiornika
void InitUsart(void)
misji RS 232 zazwyczaj używamy oraz przerwań odbiornika (nie
{
// ==== single usart configuration ====
SIG_UART_DATA , jednak zastoso- ma tu oczywiście, zgodnie z po-
// 19200 baud with 8000 kHz osc./erro-
r=0,2%
wanie zamiennie SIG_UART_TRANS przednimi uwagami, możliwości
// data 8/stop 1/parity NONE
(w sposób podobny jak w 51) jest // receiver ON/transmitter ON/recv in- włączenia przerwań nadajnika).
terrupt enabled
oczywiście również możliwe. Numer portu (USART dla ko-
UBRRH = 0x00;
UBRRL = 0x19;
Jak zwykle najlepiej obejrzeć stek z jednym portem, USART0
UCSRA = 0x0;
UCSRB = _BV(RXEN) | _BV(TXEN) |
to wszystko na przykładzie. Nowy lub USART1 dla kostek dwu-
_BV(RXCIE);
UCSRC = _BV(URSEL) | _BV(UCSZ0) |
projekt będzie kontynuacją po- portowych).
_BV(UCSZ1);
_BV(UCSZ1);
_BV(UCSZ1);
przedniego. W tym celu w dowol- // ==== end usart ====
Zatwierdzenie dialogu (OK) po-
}
nym managerze plików tworzymy woduje wstawienie bloku odpo-
void SendAnswer(int AnswerId)
folder ...\Kurs\Przyklad i kopiuje- {
...\Kurs\Przyklad 05\
...\Kurs\Przyklad wiedniego kodu w miejscu ustawie-
if((AnswerId < 1) || (AnswerId > 3))
my do niego pliki zródłowe (main. nia kursora tekstowego (karetki).
AnswerId = 0;
TxPtr = AnswerTable[AnswerId];
c, timers.c, projdat.h) z ...\Kurs\Przy- W naszym przykładzie kod ten lo-
TX_BUSY = true;
TX_ON;
klad 04\. Teraz w AvrSide otwie- kujemy wewnątrz funkcji InitUsart
}
ramy nowy projekt, ładujemy do (void) inicjalizującej port.
void SendPrompt(void)
niego pliki zródłowe poleceniem { Jerzy Szczesiul, EP
TxPtr = Prompt;
menu Projekt >Importuj z folderu jerzy.szczesiul@ep.com.pl
TX_BUSY = true;
TX_ON;
(przechodzimy w oknie wyboru do
}
nowego subfolderu ...\Przyklad 05\ UWAGA!
SIGNAL (SIG_UART_DATA)
{ Środowisko IDE dla AVR GCC opracowane
i zaznaczamy wszystkie skopiowane
char Znak;
przez autora artykułu można pobrać ze
Znak=*(TxPtr++);
tam przed chwilą pliki z kodem),
if(Znak) UDR = Znak; else
strony http://avrside.ep.com.pl.
ustawiamy potrzebne opcje (ścież- {
Elektronika Praktyczna 1/2006
101
Wyszukiwarka
Podobne podstrony:
AVR GCC kompilator C dla mikrokontrolerów AVR, część 12
AVR GCC kompilator C dla mikrokontrolerów AVR, część 4
AVR GCC kompilator C dla mikrokontrolerów AVR, część 3
Płytka testowa dla mikrokontrolerów AT89S oraz AVR
więcej podobnych podstron