USART w mikrokontrolerach AVR
Masz własną stronę WWW (prywatną lub firmową)? Dodaj ją do katalogu stron związanych z elektroniką. Wpis jest całkowicie darmowy!
Asynchroniczny protokół komunikacyjny RS232 jest od dawna powszechnie stosowany w komputerach oraz systemach cyfrowych. Protokół ten nazywany jest asynchronicznym, ponieważ dane nie są synchronizowane dodatkowym sygnałem zegarowym. Synchronizację zapewniają bity startu i stopu.
RS232 nadaje się idealnie do stworzenia prostego połączenia pomiędzy komputerem a mikrokontrolerem. Połączenie to może służyć do przesyłania danych zbieranych przez mikrokontroler, sterowania nim itp. Najczęściej jednak, port USART wykorzystywany jest w roli monitora, na który możemy przesłać komunikaty np. o błędach. Jest to bardzo przydatne przy projektowaniu i uruchamianiu urządzeń.
W artykule nie będę omawiał standardu RS232 - informacji na ten temat znajdziesz mnóstwo w internecie. Tu zajmiemy się konkretami, czyli obsługą portu RS232 w mikrokontrolerach AVR.
Funkcje
Aby korzystać z modułu USART w mikrokontrolerze, należy go odpowiednio skonfigurować. Napiszemy kod dla mikrokontrolera ATMEGAx8 (ATMEGA48, ATMEGA88, ATMEGA168, ATMEGA328), dla innych należy dokonać stosownych zmian (szczegóły w dokomentacji konkretnego układu).
Inicjowanie
Inicjowanie pozwala nam określić parametry transmisji. Określamy prędkość transmisji oraz format ramki. Poniżej przedstawiony kod inicjuje moduł transmisyjny z najczęściej stosowanym formatem ramki, prędkość transmisji przekazywana jest w parametrze funkcji. Jeśli potrzebujesz innego formatu ramki, zajrzyj do dokumentacji mikrokontrolera i ustaw odpowiednio rejestry.
void uart_init(uint16_t ubrr) { // Ustawienie prędkości transmisji UBRR0H = (uint8_t)(ubrr >> 8); UBRR0L = (uint8_t)ubrr; // Włączenie nadajnika i odbiornika UCSR0B = (1 << RXEN0) | (1 << TXEN0); // Ustawienie formatu ramki: // 8 bitów danych, 1 bit stopu, brak parzystości UCSR0C = (1 << UCSZ00) | (1 << UCSZ01); }
Wysyłanie danych
Gdy moduł USART jest już włączony możemy wysyłać dane. Funkcja wysyłająca bajt danych jest banalnie prosta. Musimy poczekać, aż zakończone zostanie nadawanie (jeśli nadajnik jest zajęty), a następnie wpisujemy daną do wysłania do rejestru UDR0. Na tym kończy się obsługa nadajnika.
void uart_putc(uint8_t data) { // Oczekiwanie na zakończenie nadawania while (!(UCSR0A & (1 << UDRE0))); // Wysłanie danych UDR0 = data; } // przydatna (ale nie niezbędna) funkcja wysyłająca ciąg znaków void uart_puts(const char *s ) { while (*s) uart_putc(*s++); }
Odbieranie danych
Funkcja odbierająca dane z portu RS232 jest, podobnie jak funkcja wysyłająca, bardzo prosta. Czekamy na pojawienie się danych w buforze, a następnie odczytujemy je z rejestru UDR0. Tutaj małe wyjaśnienie. Jak zauważyłeś rejestr do którego zapisujemy dane do wysłania oraz rejestr, z którego odczytujemy odebrane dane, mają taką samą nazwę. Fizycznie sa to jednak dwa niezależne rejestry i nie zachodzi w tym przypadku żadne konflikt.
uint8_t uart_ischar() { // Czy w buforze są dane? return (UCSR0A & (1 << RXC0)); } uint8_t uart_getc() { // Czy w buforze są dane? while(!uart_ischar()); // Dane z bufora return UDR0; }
Przykład wykorzystania
#include <avr/io.h> #include <inttypes.h> #ifndef F_CPU #define F_CPU 8000000UL // zegar w Hz #endif #define RS_BAUD 9600 #define RS_UBRR F_CPU / 16 / RS_BAUD - 1 int main(void) { uint8_t c; uart_init(RS_UBRR); uart_puts("ATMega88 UART test\r\n"); uart_puts("mikrokontroler.info\r\n"); while(1) { c = uart_getc(); uart_putc(c); } }
Podsumowanie
Jak widzisz, obsługa portu RS232 w mikrokontrolerach AVR jest bardzo prosta - napisanie odpowiednich funkcji zajmuje kilka, kilkanaście minut. Rozwiązanie przedstawione powyżej nie jest idealne. Brakuje tu kontroli błędów transmisji i możliwości przenoszenia kodu na różne mikrokontrolery rodziny AVR. Jest to jednak rozwiązanie wystarczające w wielu przypadkach, a w razie potrzeby można przecież rozbudować kod. w jednym z kolejnych wpisów przedstawię rozwiązanie bardziej uniwersalne.


