Skocz do zawartości

[Kurs] Kurs programowania ARM cz.09 - RS-232


Elvis

Pomocna odpowiedź

Poprzednia lekcja

Lekcja 9 - RS-232

Nastepna lekcja

Na początek krótki wstęp

Wszyscy pewnie znają interfejs RS-232. Charakterystyczne gniazdo DB-9 dawniej montowane było w każdym komputerze PC.

Obecnie coraz częściej gniazdo zastępowane jest przez USB, na szczęście dostępne są przejściówki USB<->RS232.

Wtyczka wyposażona jest w 9 linii, opis możemy znaleźć na wikipedii, poniżej dla przypomnienia najważniejsze linie:

Numer pinu Oznaczenie Funkcja

2 - RxD - Odbiór danych

3 - TxD - Transmisja danych

5 - GND - Masa

Te trzy linie wystarczą do naszych celów - wymiany informacji między mikrokontrolerem, a PC.

Łącząc dwa urządzenia, musimy podłączyć je „na krzyż”, czyli linię RxD łączymy z TxD drugiego układu:

Zasada jest prosta, chociaż łatwo się pomylić: to co jeden układ wysyła przez linię TxD, drugi musi odebrać, linią RxD.

Takie połączenie dawno temu było popularne do łączenia dwóch komputerów PC.

Komunikacja z mikrokontrolerem

Najpierw ostrzeżenie:

Nie wolno łączyć bezpośrednio mikrokontrolera z gniazdem RS-232 w PC.

Dlaczego? Otóż RS-232 przesyła dane za pomocą napięć ±11V. Procesory nie tolerują takich napięć. Więc należy zapamiętać, że nie wolno podłączać bezpośrednio RS-232 do naszego układu.

Procesory ARM tolerują napięcia od 0V do 3.3V, więc podłączenie 11V mogłoby nasz układ uszkodzić.

Aby temu zapobiec potrzebujemy tzw. konwertera napięć. Jest to specjalny układ, który napięcie -11V zamieni na 3.3V, a +11V na 0V.

Na rynku dostępnych jest wiele tego typu układów, chociażby popularny max232.

Podłączamy więc układ następująco:

W naszym przypadku płytka ZL1ARM jest już wyposażona w odpowiedni konwerter napięć. Warto jednak pamiętać o odpowiednim podłączeniu, gdy będziemy chcieli budować własne układy.

Płytka ewaluacyjna wyposażona jest w dwa gniazda RS-232, oznaczone COM0 oraz COM1.

Jeden układ MAX232 wystarcza do konwersji napięć dla obu gniazd, a nasz układ LPC2114 wyposażony jest w dwa sprzętowe interfejsy zgodne ze standardem RS-232.

Interfejsy te nazywane są odpowiednio UART0 oraz UART1.

Interfejs UART0 połączony jest z gniazdem COM0, natomiast UART1 z COM1.

Dotychczas już wykorzystywaliśmy łącze COM0 (UART0) do programowania procesora. Dodatkowe układy umieszczone na płytce ewaluacyjnej pozwalają na łatwe programowanie (zapewniają reset oraz uruchomienie bootladera). Wrócimy do nich później.

Ponieważ COM0 jest zajęty przez programator, na początek wykorzystamy COM1 do komunikacji z komputerem PC.

Łączymy wyjście COM1 naszej płytki z wolnym portem COM komputera. Ja wykorzystam przejściówkę USB<->RS232 ponieważ mój laptop nie posiada gniazda RS-232.

Prędkość transmisji i format danych

Łącze RS-232 pozwala na przesyłanie danych z różnymi prędkościami oraz w różnej postaci danych.

Zastosujemy popularny format, czyli: 8 bitów danych, 1 bit stopu, brak kontroli parzystości oraz transmisji.

Prędkość możemy ustawić dość dowolnie, zaczniemy od 9600 kbps, możemy zmienić na 115200 kbps jeśli chcemy szybciej przesyłać dane.

Wysyłanie danych

Na początek zdefiniujemy stałą, ustalającą prędkość transmisji:

#define BAUDRATE                  9600

Aby zmienić prędkość transmisji wystarczy przypisać jej inną wartość.

Do rejestrów będziemy musieli wpisać wartość równą prędkości zegara peryferiów (pclk) podzielonej przez prędkość transmisji pomnożoną przez 16. Jeśli to zawiłe, wystarczy napisać:

#define BAUDRATEDIVISOR           (15000000/(BAUDRATE*16))

Wartość pclk wynosząca 15000000 (15MHz) pojawiła się w części poświęconej zegarom.

Teraz musimy wpisać wartości konfiguracyjne do odpowiednich rejestrów. Więcej informacji jak zwykle znajdziemy w dokumentacji procesora:

void uart1_init(void)
{
 PCB_PINSEL0 |= 0x00010000;  
 PCB_PINSEL0 |= 0x00040000;  
 UART1_FCR = 1;

 //Set baudrate
 UART1_LCR |= 0x80; // DLAB = 1;
 UART1_DLL = BAUDRATEDIVISOR & 0x00ff;
 UART1_DLM = (BAUDRATEDIVISOR >> 8) & 0x00ff;
 UART1_LCR &= ~0x80; // DLAB = 0;

 //Set mode
 UART1_LCR = 0x03; //8 bit word length, 1 stop bit, No parity
}

Rejestry PINSEL odpowiadają za funkcję pełnioną przez dane wyprowadzenie. Domyślnie (czyli po resecie procesora) linie pracują jako wejścia-wyjścia, za pomocą podanego przypisania linia P0.8 będzie działać jako nadawanie (TxD), a P0.9 jako odbieranie (RxD) danych przez UART1.

Następne instrukcje ustawiają prędkość oraz tryb transmisji.

Gdy UART jest już skonfigurowany możemy zacząć wysyłać przez niego dane.

void uart1_send_byte(unsigned char byte)
{
 while(!(UART1_LSR & 0x20));
 UART1_THR = byte;
}

Funkcja czeka najpierw na koniec poprzedniej transmisji (o ile trwała), po czym zapisuje do bufora kolejny bajt. Za cało transmisję odpowiada sprzęt.

Będziemy wysyłać napisy, więc przygotujemy jeszcze jedną funkcję:

void uart1_send(const char *s)
{
while (*s) {
	uart1_send_byte(*s);
	s++;
}
}

Pozwoli ona na wysłanie całego napisu.

Teraz możemy uruchomić program program17.zip i zobaczyć rezultat. Na PC powinniśmy uzyskać komunikat „Hello world!”.

Kod programu jest bardzo krótki:

int main(void)
{
pll_init();
timer0_init();
uart1_init();

while (1) {
	uart1_send("Hello world!!!\r\n");
}
}

Warto przy okazji zwrócić uwagę na program obsługujący port RS-232. Nie wszystkie działają równie dobrze. Polecam putty, dostępny za darmo pod adresem: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html

Rezultat działania programu widać poniżej:

Komunikacja dwukierunkowa

Skoro umiemy już wysyłać dane, czas spróbować dane odbierać.

Poniższa funkcja będzie odpowiedzialna za odczyt danych z UART1 (COM1):

unsigned char uart1_recv(void)
{
   if ((UART1_LSR & 0x01)==0) return 0;
   return UART1_RBR;
}

W pierwszej linii sprawdzamy, czy są jakieś odebrane dane. Procesor LPC2114 ma wbudowany bufor dla odbieranych i wysyłanych danych o pojemności 16 bajtów.

Dzięki temu nawet bez obsługi przerwań nasz program może działać całkiem sprawnie.

Jeśli bufor odbiorczy jest pusty zwracamy 0. Jest to informacja dla programu głównego, że chwilowo brak danych.

W przeciwnym przypadku odczytujemy daną z bufora i zwracamy jako wynik funkcji.

Przykładowy program będzie odczytywał komendy 'a', 'w', 'd' oraz wyświetlał komunikat o wybranym kierunku jazdy robota. Oczywiście poza wysyłaniem komunikatu, należałoby odpowiednio wysterować silniki.

   while (1) {
       c = uart1_recv();
       switch (c) {
           case 'a':
               uart1_send("a - Jazda w lewo\r\n");
               break;
           case 'w':
               uart1_send("w - Jazda w prawo\r\n");
               break;
           case 'd':
               uart1_send("d -Jazda prosto\r\n");
               break;            
           case 0:
               break;
           default:
               uart1_send("Nieznane polecenie\r\n");
               break;                
       }
   }

W pliku Program18.zip znajdziemy kompletny kod przykładu. Poniżej rezultat działania:

Program18.zip

Program17.zip

  • Lubię! 1
Link do komentarza
Share on other sites

Witam!

Miałem wczoraj problem z rozgryzieniem tego fragmentu dotyczącego konfiguracji PINSEL0.

Postanowiłem więc trochę poczytać i tak powstał dziś ten pliczek

➡️LPC211x - Rejestry wyboru funkcji wyprowadzeń (PINSEL0 i PINSEL1).

Mam nadzieje, że dobrze to wszystko rozpracowałem i żadnych bzdur tam nie napisałem.

Może się to komuś też przyda 🙂.

Czy ktoś mógłby potwierdzić czy to co opisałem w pliku jest poprawne. 🙂

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.