Czy tego chcemy, czy nie port
RS-232 powoli wymiera. Nowe laptopy go praktycznie nie posiadają, płyty główne normalnych PC-ów jakoś się jeszcze bronią. Co prawda
RS-232 nie jest już zazwyczaj wyprowadzany na złącze z tyłu płyty, niemniej gdzieś tam, w czeluściach
PCB możemy zazwyczaj ciągle znaleźć małe, 10-pinowe złącze, pod które można podłączyć śledzia z gniazdem
RS-232.
Pytanie tylko po co?
RS-232 niewątpliwie jest prosty, ale z punktu widzenia elektronika ma dwie poważne wady:
- wymaga konwertera poziomów (tzw. transceivera, np. max232), jest to układ tani, ale zajmuje miejsce na PCB, wymaga zwykle 4 zewnętrznych kondensatorów, no i zawsze to jakiś element dodatkowy,
- złącze RS-232 nie ma wyprowadzonego zasilania. Co prawda parenaście mA można wyciągnąć z nieużywanych linii interfejsu, jednak nie jest to za wiele.
A jakie
RS-232 ma zalety? Dosyć poważne:
- prostota - nawet początkujący uruchomi transmisję w ciągu kilkunastu minut,
- w USART wyposażony jest praktycznie każdy mikrokontroler, a nawet jeśli nie jest, to stosunkowo łatwo go emulować programowo.
- możliwość komunikacji na duże odległości.
Wydaje się, że przedstawione zalety przeważają tym bardziej, że zanikający port
RS-232 możemy zawsze protezować wykorzystując różnego typu przejściówki, z których najpopularniejsze oparte są na znanym układzie
FT232 i różnych jego odmianach. Inna strategia polega na programowej emulacji
USB bezpośrednio w procesorze dzięki
bibliotece V-USB.
Emulacja programowa USB z pewnością jest tania i wymaga tylko kilku prostych elementów zewnętrznych, ale bardzo obciąża procesor i nie do końca jest zgodna ze
standardem USB.
Z kolei wykorzystanie przejściówek opartych na
FT232 kosztuje:
- sam układ FT232 około 14-18zł (cena 2013r.),
- do tego zajmuje on trochę miejsca na PCB (co także kosztuje),
- no i nie każdy lubi lutować układy SMD.
Przejściówki USB-RS232
Dla tych co nie lubią lub boją się montażu SMD różne firmy oferują zmontowane przejściówki w cenie 30-60zł. Taką przejściówkę wystarczy połączyć przy pomocy listy kołkowej z naszym układem i możemy się cieszyć możliwością komunikacji z PC przy pomocy wirtualnego portu szeregowego.
Co ważne, od strony mikrokontrolera komunikacja ciągle przebiega z wykorzystaniem interfejsu USART.
Alternatywy
Wszystko pięknie, ale świat idzie do przodu i to co było na topie 2-3 lata temu obecnie niekoniecznie jest najlepszym rozwiązaniem. Na rynku mikrokontrolerów, w tym
mikrokontrolerów AVR, pojawiły się układy dysponujące
wbudowanym interfejsem USB (w wersji host, jak i device).
W rodzinie AVR
sprzętowy interfejs USB-device (co wystarcza do implentacji dowolnego urządzenia
USB podłączanego do
PC) posiadają mikrokontrolery
ATMega z literką U w nazwie.
Literka U musi być przy oznaczeniu mikrokontrolera, a nie po myślniku – wtedy znaczy coś innego.
Czyli np. ATMega32U2 posiada interfejs USB, z kolei ATMega32-AU, to zwykły mikrokontroler bez tego interfejsu.
Tak samo jest w rodzinie Xmega - ATXMEGA128A1U posiada sprzętowy interfejs USB, a ATXMEGA128A1-AU nie posiada.
Niemniej obecnie (2013r.) nie ma właściwie żadnego uzasadnienia dla używania rodziny
ATMega, gdyż pod każdym względem (także cenowym) lepsze od nich są mikrokontrolery
XMEGA.
Taki interfejs posiadają także
pokazane wcześniej minimoduły z mikrokontrolerami
XMEGA256A3-BU i
XMEGA128A3U. Co więcej, posiadane moduły są wyposażone w
gniazdo USB i wszystko co do komunikacji jest wymagane. Spróbujmy więc je wykorzystać.
Podłączenie - schemat
Jeśli ktoś nimi nie dysponuje i nie jest przekonany do bezpośredniego łączenia procesora z USB poniżej pokazuję schemat takiego połączenia. Jak widzimy jest on banalnie prosty – odpowiednie linie sygnałowe
D+ i
D- łączymy bezpośrednio z odpowiednimi sygnałami w
gnieździe USB.
Naprawdę prościej już się nie da :-)
Jak widzimy piny mikrokontrolera
PD7 i
PD6 są połączone bezpośrednio z odpowiednimi stykami gniazda
USB.
Jest to możliwe, gdyż XMEGA posiadają wewnętrzne układy dopasowujące. Oczywiście zwolennicy dmuchania na zimne mogą umieścić dodatkowe rezystory szeregowe na tych liniach (typowo 22Ω).
Zasilanie
Warto zwrócić uwagę na jeszcze jedną rzecz –
USB dostarcza napięcia zasilającego, które możemy wykorzystać do zasilania podłączonego układu (maksymalna wydajność przed enumeracją to
100mA, po enumeracji
500mA dla
USB do
2.0 i
900mA dla
USB 3.0 lub
1,5A bez jednoczesnej transmisji danych).
Jednak napięcie na tym interfejsie (około
5V) jest wyższe niż dopuszczalne dla
XMEGA (maksymalnie
3,6V).
Stąd też jeśli chcemy zasilać XMEGA z USB musimy dodać zewnętrzny regulator napięcia, typu low-drop (bardzo ważne, ze względu na niewielką różnicę napięć pomiędzy wejściem a wyjściem). Nie jest to żadnym problemem, gdyż zazwyczaj i tak jakiś regulator w układzie mamy.
Warto podkreślić, że posiadacze pokazanych wcześniej modułów, mają już taki regulator zamontowany. Odpowiednią zworką mogą wybierać zewnętrzne źródło napięcia lub zasilanie z
USB.
Jak widzimy połączenia elektryczne są niezwykle proste,
warto ewentualnie pomyśleć o dodatkowym filtrowaniu napięcia z USB (komputer jest potężnym źródłem zakłóceń), ale dla naszych rozważań nie jest to niezbędne.
Kwarc, czy generator wewnętrzny RC?
Uważni obserwatorzy naszego bloga i osoby znające się co nieco na AVR-ach z pewnością zaprotestują – jak to, a gdzie kwarc? Przecież na wewnętrznym generatorze RC, to w życiu nie zadziała!
No i są w błędzie.
XMEGA posiadają naprawdę stabilny wewnętrzny generator RC, w efekcie nie tylko do realizacji transmisji RS-232, ale nawet do pracy z wykorzystaniem USB żadne zewnętrzne elementy nie są potrzebne! Tak więc przedstawiony schemat jest kompletnym, działającym układem interfejsu
XMEGA-USB.
Program
Ok, mamy sprzęt, czas na program. W pokazanej implementacji
wirtualnego portu szeregowego wykorzystane zostanie oprogramowanie dostarczone przez firmę Atmel.
Firma ta jest tak miła, że za darmo dostarcza nam gotowych bibliotek i przykładów. Taką gotową biblioteką zawierającą wszystko co potrzeba do realizacji
RS-232 przez
USB jest
ASF (
Atmel Software Framework).
Biblioteka trochę ciężka i na pierwszy rzut oka skomplikowana, dlatego osobiście preferuję „własne” rozwiązania. Ale nie ma co wyważać otwartych drzwi – zamiast narzekać wykorzystałem gotowy kod, tylko nieco go „odchudziłem” wyrzucając zbędne komponenty
ASF i niepotrzebne definicje.
Lecz dobra wiadomość jest taka – dzięki pokazanemu przykładowi w ogóle nie musisz zagłębiać się w tajniki implementacji
CDC (
USB communications device class – klasy urządzeń komunikacyjnych, do których zalicza się m.in. urządzenie wirtualnego portu szeregowego). Miało być prosto – i będzie prosto!
Tak więc mamy nieco zmodyfikowaną bibliotekę firmy Atmel implementującą
klasę CDC, dzięki czemu w ogóle nas nie interesuje jak to wszystko działa. Natomiast interesuje nas (a przynajmniej powinno) poznanie jak z tego korzystać.
Czas więc ściągnąć przykładowy projekt – jest on przygotowany dla
Atmel Studio 6.1 i w tym programie możemy go bezpośrednio otworzyć. Ze wszystkich plików, które są zawarte w tym projekcie interesuje nas plik
main.c, w którym znajduje się cała obsługa
RS-232:
Przykład 1 (w kompilatorze)
int main(void)
{
//Włączamy wszystkie poziomy przerwań (potrzebujemy tylko najniższy)
PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm |
PMIC_HILVLEN_bm;
sei();
sysclk_init();
udc_start();
while (1) {
char ch;
if (udi_cdc_is_rx_ready()) {
ch = udi_cdc_getc();
switch(ch) {
case 'n' :
udi_cdc_write_buf("Pozdrowienia z XMEGA!\n\r", 23);
break;
default :
udi_cdc_write_buf("O co chodzi?\n\r", 14);
break;
}
}
}
}
Co nasz przykład robi?
Jak widzimy najpierw włączane są przerwania. Ponieważ
kontroler przerwań w
XMEGA obsługuje
trzy poziomy przerwań, włączamy je wszystkie (chociaż nasz
sterownik USB wykorzystuje tylko przerwania najniższego poziomu) i ustawiamy globalną flagę zezwolenia na przerwania instrukcją
sei().
Następnie inicjalizowane są podsystemy mikrokontrolera – zegar oraz włączany jest
sterownik USB.
Implementacja
USB zaproponowana przez firmę Atmel jest o tyle fajna, że wykorzystuje ona przerwania i bufory, w efekcie cała obsługa
USB jest zupełnie niezależna od kodu użytkownika.
Od tego momentu nasz mikrokontroler może wymieniać dane z PC udając port szeregowy.
W pętli głównej, sprawdzamy czy w buforze odbiornika znajduje się jakiś znak - funkcja
udi_cdc_is_rx_ready(), jeśli tak to go odbieramy. Po sprawdzeniu co to za znak podejmujemy odpowiednią akcję – wysyłamy do komputera PC łańcuch znaków -
funkcja udi_cdc_write_buf().
Funkcja ta przyjmuje jako argumenty adres bufora, w którym znajduje się wysyłany łańcuch oraz jego długość. Oczywiście mamy też do dyspozycji funkcję
udi_cdc_putc(int value), która wysyła jeden znak (argument value).
I to wszystko, prawda, że proste?
Część osób uważnie czytających ten artykuł z pewnością zapyta – a gdzie inicjalizacja portu szeregowego? Przecież musimy ustawić odpowiednią szybkość transmisji, prawda?
Otóż nie. Jedną z przyjemnych cech emulacji portu szeregowego jest to, że szybkość transmisji nas zupełnie nie interesuje. Dlaczego? Ano dlatego, że jest to parametr istotny dla fizycznego interfejsu
RS-232 dzięki niemu odbiornik wie jak szybko nadawane są dane przez nadajnik, co jest niezbędne, gdyż typowa transmisja
RS-232 jest transmisją asynchroniczną (czyli nie przesyłamy żadnego zegara taktującego transmisję).
Tu dane wysyłane są przez interfejs
USB, w efekcie sposób ich wysyłania i szybkość zupełnie nas nie interesują.
Przez interfejs USB przechodzą one zawsze tak szybko jak tylko się da. To aplikacja może je wysyłać lub pobierać wolniej. W efekcie w terminalu możemy ustawić dowolną szybkość transmisji danych!
Ale zanim to zrobimy musimy wczytać nasz przykładowy program do
XMEGA. Możemy to uczynić przy pomocy programatora, albo tak jak
wcześniej pokazałem przy pomocy programu FLIP – właściciele prezentowanych wcześniej modułów dysponują XMEGA z
preprogramowanym bootloaderem.
Po uruchomieniu programu, nasz ulubiony system powinien wykryć
nowe urządzenie USB. Jeśli naszym ulubionym systemem jest
MS Windows, to zapewne nie będzie on dysponował odpowiednimi sterownikami. Nie ma problemu – odpowiednie sterowniki znajdują się w
katalogu RS232overUSB/RS232overUSB – plik
atmel_devices_cdc.inf. Jeśli system nie znalazł właściwych sterowników, należy mu wskazać ten plik. Po poprawnym zainstalowaniu sterowników powinniśmy w menagerze urządzeń zobaczyć nowe urządzenie:
Jest nim
EVK1XXX Virtual Com Port (COM7).
Dlaczego taka dziwaczna nazwa? Problem w tym, że
urządzenia USB muszą posiadać swój unikalny identyfikator
VID/PID. W naszym przykładzie pasożytujemy nieco na firmie
Atmel, wykorzystując ich identyfikatory
(pamiętaj jednak, że absolutnie nie wolno robić tego w urządzeniach komercyjnych!).
Ponieważ użyliśmy
VID/PID, który w
pliku .inf ma przypisaną powyższą nazwę, stąd też nasz układ tak się przedstawia. Oczywiście można to zmienić, ale
skorzystanie z pliku .inf firmy Atmel ma jeszcze jedną zaletę – jest on podpisany cyfrowo. Tak, to nie bajki,
pliki tekstowe .inf też mają w Windows swoje podpisy cyfrowe.
O ile dla Windows XP i Windows 7 brak podpisu nie jest zasadniczo problemem, o tyle użytkownicy Windows 8 mieliby problem. Jeśli plik opisu sterownika (urządzenia klasy CDC nie wymagają instalacji żadnych sterowników) jest podpisany cyfrowo, to także użytkownicy Windows 8 mogą z naszego przykładu korzystać bez problemów.
Ok, na tym etapie zakładam, że twój system rozpoznał nowy układ, a sterowniki są poprawnie zainstalowane. Co dalej? Warto w menagerze urządzeń sprawdzić
numer wirtualnego portu COM – na powyższym zrzucie był to
COM7,
ale w twoim przypadku może to być zupełnie inny port.
Nadeszła więc pora na test – odpalamy nasz ulubiony
terminal. Ja używam
RealTerm – nie jest to żaden cud, ale ma wszystko co jest potrzebne, no i jest za darmo (jeśli go nie masz, to go możesz pobrać stąd:
http://realterm.sourceforge.net).
Uruchamiamy więc terminal, wybieramy port, który jest połączony z naszą
XMEGA (możemy wybrać po numerze lub nazwie, np.
\USBSER000 i zaczynamy zabawę.
A co nasz przykład robi? Po jego uruchomieniu oczekuje on na dane z komputera, po otrzymaniu
litery n wysyła pozdrowienia, które powinniśmy zobaczyć na terminalu, po wysłaniu dowolnego innego znaku wysyła zapytanie „O co chodzi?” – poniższy rysunek.
I to wszystko, prawda, że proste?
Mam nadzieję, że przekonałem Was do używania
USB zamiast archaicznych rozwiązań typu
emulacja USB lub przejściówki
USB - RS232. Jeśl będzie taka potrzeba to pokażemy więcej przykładów rozwiązań opartych na
USB.
Program zajmuje 7,5kB - to dużo, czy mało?
Chwila, ale czemu ten prosty przykład zajmuje prawie
7,5kB? A dlaczego nie, pamiętaj, to
XMEGA, mamy pamięci sporo! A pamięć leżąca odłogiem, to pamięć zmarnowana.
Nie przekonuje cię to? Mnie też nie Prawda jest prozaiczna – nasz przykład, to przycięty
fragment ASF –
biblioteki fajnej, ale uniwersalnej. A jak wiemy za uniwersalność się płaci – najczęściej wzrostem objętości kodu i wolniejszym działaniem. Jeśli by ją dalej przyciąć i np. ustawiać zegar systemowy wpisując gotowe wartości, to spokojnie można zejść do
2-3 kB. Ciągle więcej niż w przypadku
USART, ale za to o ile fajniej? :-)
Do pobrania
Pliki projektu Atmel Studio 6.1:
RS232overUSB.zip
Plik IntelHex do bezpośredniego programowania dla
XMEGA256A3BU (moduły
Xplained XMEGA256A3BU lub moduł z modulowo.pl):
RS232overUSB-XMEGA256A3BU.zip
Inne XMEGA
Jeśli posiadasz inny XMEGA niż użyty w projekcie XMEGA256A3BU, to po prostu zmień w projekcie typ procesora i przekompiluj go. Uzyskasz nowy plik hex, do zaprogramowania.
Kilka RS-232
Oczywiście możesz na raz podłączyć do PC więcej mikrokontrolerów XMEGA – w takiej sytuacji pojawią się kolejne porty szeregowe:
A czy jedna
XMEGA może udawać kilka urządzeń
USB? Jak sądzisz? :-)
Oczywiście, że tak, nawet nie jest to dużo trudniejsze, ale to już całkiem inna historia ...
Wstęp do XMEGA:
Spis treści