Jednym z najbardziej popularnych interfejsów komunikacji jest RS-232. Większość mikrokontrolerów wyposażona jest w co najmniej jeden taki moduł.
Podstawową zaletą RS-232 jest możliwość komunikacji na duże odległości nawet ponad jednego kilometra. Wadą natomiast radykalnie zmniejszająca się przepustowość łącza, wraz ze wzrostem odległości. Coś, za coś :-)
Nie będę tutaj omawiał dokładnie zasad komunikacji pokażę jedynie jak w praktyce połączyć mikrokontroler z komputerem i jak zrealizować łączność z prędkością 57,6kbps z wykorzystaniem przerwań.
Dowiesz się także jakie błędy popełniane są najczęściej w temacie wykorzystania tego interfejsu.
Przeczytaj także jak wykorzystać interfejs RS-232 za pomocą Bletooth: Bluetooth + mikrokontroler
Krzyżowe połączenie
W przypadku RS-232 (w przeciwieństwie do innych interfejsów) urządzenia łączy się krzyżowo, czyli w taki sposób, by wyjście jednego trafiało na wejście drugiego:
Należy o tym pamiętać w szczególności, że standardowe przewody łączące mogą być dwojakiego rodzaju:
Jeżeli więc podwójnie skrzyżujesz sygnały RxD i TxD (raz w urządzeniu i drugi raz w przewodzie łączącym), to de facto krzyżowania nie będzie i komunikacji także :-)
Pinologia
W komputerach znajdziesz gniazda RS-232 w formie wtyku typu D-SUB o 9 pinach w wersji męskiej.
![]() |
Źródło |
Każdy pin ma numerek (patrz przez lupę - mogą być słabo widoczne). Numerki są zgodne z wersją damską złącza. Innymi słowy damskie jest lustrzanym odbiciem męskiego, przez co piny o tych samych numerach wzajemnie się łączą.
W starszych urządzeniach można znaleźć gniazda w wersji 25 pinowej.
Warto zerknąć na tę stronę: RS232 Connector Pin Assignment lub w wersji PDF.
Prędkości transmisji
RS-232 oferuje bardzo szeroki zakres możliwych prędkości transmisji. Pozwala to na dobranie odpowiedniej do danych warunków (możliwości obu połączonych urządzeń) oraz odległości i innych warunków zewnętrznych (zakłócenia, rodzaj i jakość przewodów, itp). Zerknijmy na tabelę zawartą w datasheet ATmega8 dla zegara taktującego mikrokontroler od 16MHz wzwyż:
Baud rate, to jednostka prędkości łącza wyrażona w bitach na sekundę (ang. bits per second). Jak każdą jednostkę także i tę możemy wyrażać za pomocą przedrostków wielokrotności jednostki miary. Stąd:
- kbps - oznacza kilo bitów na sekundę,
- Mbps - mega bitów na sekundę.
Takich tabel jak powyższa w datasheet znajdziesz więcej (także dla niższych częstotliwości zegara mikrokontrolera). Za pomocą nich możesz wybrać i ustawić odpowiednio interfejs USART (UART) mikrokontrolera.
Zauważysz w nich, że w trybie asynchronicznym niektóre częstotliwości taktowania mikrokontrolera pozwalają uzyskać znacznie większe prędkości transmisji danych, niż inne częstotliwości. Na pierwszy rzut oka może dziwić fakt, że dla częstotliwości taktowania mikrokontrolera 8MHz, można osiągnąć 1Mbps, podczas gdy z zegarem 20MHz zaledwie 0,5Mbps.
Wytłumaczenie tego faktu znajdziesz tutaj:
Podczas obliczania wartości jaką należy ustawić w rejestrze UBRR, zamiast tabelek możesz skorzystać ze wzorów, które także w datasheet znajdziesz:
Efektywna prędkość transmisji
Moduł USART umożliwia wybranie jednej z 30 możliwych kombinacji ramki danych, czyli pakietu przesyłającego jedną daną. Parametry ramki danych zależne są od tego
- bit startu (jest zawsze jeden),
- bity danych (może być od 5 do 9),
- bit parzystości (może lecz nie musi występować),
- bity stopu (co najmniej jeden lub nawet dwa).
Ramka danych przedstawia się więc następująco:
![]() |
Rys. RS-232 - Ramka danych modułu USART. |
Bity zaznaczone na czerwono występują zawsze.
Pozostałe (zaznaczone na zielono) w zależności jak ustawisz parametry transmisji.
Jak widzisz ramka może mieć od 7, aż do 13 bitów.
Skoro ramka może mieć różną długość, a BAUD RATE jest stały np. 9600bps, to efektywna prędkość transmisji danych (Data bits) będzie różna dla różnych ustawień długości ramki.
Obliczeń efektywnej prędkości transmisji danych możesz dokonać za pomocą poniższego kalkulatora:
Kalkulator efektywnej prędkości transmisji danych (USART) |
|
---|---|
Baud rate | bps |
Bit startu | |
Bitów danych | |
Bit parzystości | |
Bit stopu | |
Długość ramki | bitów |
Efektywna prędkość transmisji | bps % |
Odległości
Odległości uzyskiwane za pomocą tego interfejsu orientacyjnie wynoszą:
Prędkość [bps] | Odległość [m] |
---|---|
19200 | 16 |
9600 | 160 |
4800 | 320 |
2400 | 1000 |
Źródło: Tomasz Francuz: Język C dla mikrokontrolerów AVR.
Od podstaw do zaawansowanych aplikacji. str. 369
Faktyczne osiągi zależą oczywiście od wielu czynników jak zastosowane przewody, wersja nadajnika i odbiornika oraz środowiska w jakim pracuje tak zrealizowana linia komunikacyjna.
Niezbędna elektronika
W przypadku wykorzystania RS-232 do komunikacji pomiędzy dwoma mikrokontrolerami na niewielkich odległościach np. w tym samym urządzeniu nie ma potrzeby korzystania z dodatkowych układów i można operować napięciami w standardzie mikrokontrolerów.
Jednakże w przypadku łączenia mikrokontolera z urządzeniem pracującym w standardzie napięć RS-232, musisz wiedzieć o tym, że standard poziomów napięć RS-232 znacząco odbiega od poziomów napięć, którymi operują mikrokontrolery. Właśnie dzięki temu możliwe jest osiąganie znacznych odległości. Ceną takiego rozwiązania jest potrzeba stosowania dodatkowych układów pośredniczących.
Mogą być nimi dedykowane do tych zadań układy scalone lub można zbudować własny za pomocą niewielkiej ilości elementów. Układ ten powinien znajdować się po obu stronach linii, czyli na wejściach i wyjściach obu komunikujących się ze sobą urządzeń.
Dedykowane układy RS-232
Podstawowym, powszechnie stosowanym i tanim układem jest MAX232:
Biblioteka Eagle: maxim.lbr
Fakt, że mikrokontroler może osiągnąć prędkość np. 1Mbps nie oznacza, że możesz z taką prędkością komunikację prowadzić za pomocą MAX232, czy innych tego typu układów, ponieważ układy te mają swoje górne granice prędkości transmisji. W przypadku MAX232 jest to zaledwie 120kbps.
Ale jest także wiele innych układów, które mają znacznie większe prędkości i/lub inne parametry, które mogą być istotne dla Ciebie, jak na przykład pobór prądu w stanie spoczynku w przypadku urządzeń zasilanych z baterii, czy akumulatora:
Często jak w przypadku MAX232 w jednym układzie zawarte są dwa komplety nadajników i odbiorników. Jeżeli nie wykorzystujesz obu nadajników i odbiorników, warto jest zadbać o wymuszenie stanu niskiego na nieużywanych wejściach, by te części układu nie "łapały" zakłóceń:
MAX'y vs kondensatory
Częstym problemem początkujących jest sprawa kondensatorów używanych w tej rodzinie układów. Trzeba zwrócić uwagę na dwa ważne aspekty:
- kondensator C4 ma z pozoru nieprawidłową polaryzację, ale wynika ona z faktu, że na pinie V- jest napięcie ujemne(!).
- wartość i rodzaj kondensatorów zależy od typu zastosowanego układu MAX. Dokładną informację znajdziesz w datasheet danego układu. W przypadku MAX232 kondensatory powinny mieć 1µF i mogą być elektrolityczne, tantalowe, a nawet ceramiczne. W przypadku MAX202 kondensatory mają wartość 0,1µF. Zawsze sprawdzaj w datasheet:
![]() |
Rys. MAX232 - wymagania dot. kondensatorów. |
Nie mam pod ręką MAX'a !
Transmisję z wykorzystaniem RS-232 można także prowadzić za pomocą prostego intrerfejsu zrealizowanego za pomocą dwóch tranzystorów i kilku dodatkowych elementów:
Tak wykonany interfejs jest bezpieczną wersją o całkiem dobrych parametrach transmisji danych, chociaż mogą wystąpić problemy przy dłuższych przewodach. Innymi słowy rozwiązanie to należy traktować jako awaryjne, testowe, doświadczalne lub świadomy kompromis.
Dodatkową zaletą jest fakt, iż użyte tranzystory i diody mają wiele zamienników, więc praktycznie zawsze pod ręką jakieś znajdziesz. Także rezystory mogą przybierać różne wartości od 2,2k do 10k.
Przykład "koprocesora matematycznego" :-)
Czas przejść do zadania praktycznego. Zbudujemy taki układ:
Poniżej program pokazujący transmisję danych z wykorzystaniem przerwań, by nie blokować mikrokontrolera. Program ma za zadanie:
- odebrać liczbę wysłaną z komputera za pomocą RS-232,
- dokonać obliczeń funkcji kwadratowej podstawiając odebraną liczbę za X,
- wysłać za pomocą RS-232 do komputera ciąg znaków reprezentujących obliczony wynik funkcji.
Rezultat działania programu, możesz zobaczyć na filmie umieszczonym pod koniec artykułu.
/* Program realizujący obliczanie i wysłanie przez RS-232 wyniku funkcji kwadratowej y = 0.3187x^2 + 2x - 7 na podstawie x odebranego wcześniej także za pomocą RS-232. Szczegóły: http://mikrokontrolery.blogspot.com/2011/03/rs-232-atmega8-komputer-terminal.html Mikrokontroler: Atmega8 Autor: Dondu Data: 2012.11.30 */ //#include <stddef.h> #include <avr\io.h> #include <stdio.h> #include <avr/interrupt.h> #include <util/delay.h> //zmienne dot. odbioru danych volatile unsigned char odb_x; //odebrana liczba X volatile unsigned char odb_flaga =0;//flaga informująca main o odebraniu liczby //bufor znaków ze wzorem funkcji, który wysyłamy po starcie programu volatile unsigned int usart_bufor_ind; //indeks bufora nadawania char usart_bufor[30] = "y = 0.3187x^2 + 2x - 7"; //bufor nadawania void usart_inicjuj(void) { //definiowanie parametrów transmisji za pomocą makr zawartych w pliku //nagłówkowym setbaud.h. Jeżeli wybierzesz prędkość, która nie będzie //możliwa do realizacji otrzymasz ostrzeżenie: //#warning "Baud rate achieved is higher than allowed" #define BAUD 57600 //tutaj podaj żądaną prędkość transmisji #include <util/setbaud.h> //linkowanie tego pliku musi być //po zdefiniowaniu BAUD //ustaw obliczone przez makro wartości UBRRH = UBRRH_VALUE; UBRRL = UBRRL_VALUE; #if USE_2X UCSRA |= (1<<U2X); #else UCSRA &= ~(1<<U2X); #endif //Ustawiamy pozostałe parametry moduł USART //U W A G A !!! //W ATmega8, aby zapisać do rejestru UCSRC należy ustawiać bit URSEL //zobacz także: http://mikrokontrolery.blogspot.com/2011/04/avr-czyhajace-pulapki.html#avr_pulapka_2 UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0); //bitów danych: 8 //bity stopu: 1 //parzystość: brak //włącz nadajnik i odbiornik oraz ich przerwania odbiornika //przerwania nadajnika włączamy w funkcji wyslij_wynik() UCSRB = (1<<TXEN) | (1<<RXEN) | (1<<RXCIE); } //-------------------------------------------------------------- ISR(USART_RXC_vect) { //przerwanie generowane po odebraniu bajtu odb_x = UDR; //zapamiętaj odebraną liczbę odb_flaga = 1; //ustaw flagę odbioru liczby dla main() } //-------------------------------------------------------------- ISR(USART_UDRE_vect){ //przerwanie generowane, gdy bufor nadawania jest już pusty, //odpowiedzialne za wysłanie wszystkich znaków z tablicy usart_bufor[] //sprawdzamy, czy bajt do wysłania jest znakiem końca tekstu, czyli zerem if(usart_bufor[usart_bufor_ind]!= 0){ //załaduj znak do rejestru wysyłki i ustaw indeks na następny znak UDR = usart_bufor[usart_bufor_ind++]; }else{ //osiągnięto koniec napisu w tablicy usart_bufor[] UCSRB &= ~(1<<UDRIE); //wyłącz przerwania pustego bufora nadawania } } //-------------------------------------------------------------- void wyslij_wynik(void){ //funkcja rozpoczyna wysyłanie, wysyłając pierwszy znak znajdujący się //w tablicy usart_bufor[]. Pozostałe wyśle funkcja przerwania, //która zostanie wywołana automatycznie po wysłaniu każdego znaku. //dodaj do tekstu wyniku znaki końca linii (CR+LF), by na //ekranie terminala wyniki pojawiały się w nowych liniach unsigned char z; for(z=0; z<30; z++){ if(usart_bufor[z]==0){ //czy to koniec takstu w tablicy //tak znaleziono koniec tekstu, dodajemy znak CR usart_bufor[z] = 13; //znak powrotu karetki CR (Carrige Return) usart_bufor[z+1] = 10; //znak nowej linii LF (Line Feed) usart_bufor[z+2] = 0; //znak końca ciągu tekstu w tablicy break; } } //Zaczekaj, aż bufor nadawania będzie pusty while (!(UCSRA & (1<<UDRE))); //bufor jest pusty można wysłać //następny znak do wysyłki to znak nr 1 usart_bufor_ind = 0; //włącz przerwania pustego bufora UDR, co rozpocznie transmisję //aktualnej zawartości bufora UCSRB |= (1<<UDRIE); } //-------------------------------------------------------------- int main(void) { usart_inicjuj(); //inicjuj moduł USART (RS-232) sei(); //włącz przerwania globalne wyslij_wynik(); //na początku wysyłamy text wzoru, który po //resecie jest w tablicy usart_bufor[] while(1){ //tutaj Twój program .... //czekamy na informację o odebraniu danej nie blokując mikrokontrolera if(odb_flaga){ odb_flaga = 0; //zgaś flagę //wykonaj obliczenia i wynik przekształć na znaki ładując do //bufora usart_bufor[] sprintf(usart_bufor, "%f", 0.3187 * odb_x * odb_x + 2 * odb_x - 7); wyslij_wynik(); //rozpocznij wysyłanie wyniku przez RS-232 } //w tym czasie można wykonywać dowolny program //umieść go tutaj lub przed if() powyżej } }
Do pobrania: Kompletny projekt AVR Studio 4 + plik HEX dla 16MHz
Testujemy programem terminala
Do kontroli komunikacji oraz wysyłania i odbierania danych na komputerze wykorzystamy program Realterm. To bardzo rozbudowany w porównaniu z zawartym w systemie Windows Hyper Terminal'u.
Możesz oczywiście wykorzystać dowolny inny program terminala.
Po uruchomieniu programu musisz ustawić parę opcji. Zaczniemy od zakładki Display:
Następnie w zakładce Port ustawiamy takie same parametry transmisji jakie ustawiliśmy w programie mikrokontrolera:
Włączamy nasz mikrokontroler i naszym oczom powinien ukazać się przesłany przez niego tekst wzoru:
Jeżeli napis się nie ukazał, powinieneś sprawdzić swój projekt dokładnie. Poniżej opisałem najczęściej występujące problemy.
Zanim zaczniemy testować dalej włączymy opcję Display as: Ansi w zakładce Display, po to by nie było widać znaków sterujących.
Czas wypróbować jak działa nasza projekt. W tym celu za pomocą zakładki Send wyślemy liczbę z zakresu od 0 do 255. Mikrokontroler odbierze liczbę, obliczy wartość funkcji i zwróci wynik:
Za każdym razem, gdy wyślesz liczbę, natychmiast otrzymasz wynik funkcji. Oznacza to, że komunikacja przebiega prawidłowo.
Działanie układu możesz zobaczyć na poniższym filmie (ustaw sobie najwyższą rozdzielczość z możliwych):
Pozostałe tryby pracy USART
Moduł USART ma spore możliwości i wiele różnych ustawień, nie będę się na ten temat rozpisywał, bo musiałbym napisać książkę, a ponieważ jest już sporo literatury na ten temat więc pozwolicie, że swój czas poświęcę na inne ważniejsze artykuły. Bardzo dokładnie opisał to Tomek Francuz w swojej książce. Można także posiłkować się dokumentacją mikrokontrolera.
Najczęściej występujące problemy
W trakcie projektowania i testów, możesz się natknąć na kilka problemów.
Brak lub niepoprawna komunikacja
Z tym interfejsem wieże się spora ilość miejsc, w których można popełnić błąd skutkujący brakiem komunikacji. Oto najważniejsze z nich:
- zapominanie o tym, iż w niektórych mikrokontrolerach dwa różne rejestry mogą być pod tym samym adresem, patrz: Pułapki AVR'ów,
- ustawienie różnych parametrów transmisji w obu urządzeniach,
- stosowanie niestabilnego (niedokładnego) źródła zegara taktującego mikrokontroler, szczególnie w przypadku pracy USART w trybie asynchronicznym,
- błędne połączenie urządzeń w zależności od posiadanego przewodu (prosty lub krzyżowy),
- zbyt długi przewód łączący oba urządzenia w stosunku do wybranej prędkości transmisji,
- kiepskiej jakości przewody,
- zbyt duże zakłócenia zewnętrzne.
Jeżeli coś będzie sygnalizowane na czerwono powinieneś się nad tym zastanowić.
Problem liczb i znaku zapytania w terminalu
Jeżeli wysyłasz do terminala liczby w postaci kodów ASCII, możesz się natknąć na problem pojawiającego się w zamian jedynie znaku zapytania. Rozwiązanie problemu znajdziesz tutaj: Problem znaku zapytania podczas konwersji float do znaków ASCII