Niejednokrotnie w robotyce pojawia się potrzeba komunikacji z urządzeniem. W przeróżnych celach – począwszy od wydawania poleceń (np. szukaj piłeczki, przynieś), poprzez monitorowanie pracy a na kalibracji czujników skończywszy.
Powodów jest bardzo wiele, tak samo jak i dróg, którymi możemy tę komunikację prowadzić.
Gdy pomyślimy o połączeniu z naszym robotem, na pewno od razu do głowy wpadnie nam odwieczny przyjaciel elektronika – kabel.
Takie podejście jest nieodzowne w wielu przypadkach, jednak specyfika robotyki nieco utrudnia sprawę. Przewodowe połączenie z robotem nie jest zbyt trafnym, ani wygodnym rozwiązaniem – chyba nie muszę tłumaczyć dlaczego.
W związku z tym, prowadząc dalsze poszukiwania, zapewne każdy spojrzy na pilota od telewizora – bingo!
Taki sposób przesyłania danych jest całkiem prosty i funkcjonalny – za odpowiednie układy sprzętowe zapłacimy jedynie kilka-kilkanaście złotych. Ta metoda komunikacji posiada jednak 2 wady:
przede wszystkim urządzenia muszą być wzajemnie widoczne (możemy czasem korzystać z odbicia promieni świetlnych, ale nie jest to pewne rozwiązanie). W znacznym stopniu ogranicza to nasze możliwości,
komunikacja taka zwykle będzie jednokierunkowa – między innymi z powodu wspomnianego ograniczenia widocznością.
Co w związku z tym wybrać? Moim zdaniem warto rozważyć komunikację drogą radiową. Rzecz jasna nie twierdzę, że jest to jedyny słuszny wybór – inne drogi komunikacji w określonych warunkach będą wystarczające, bądź nawet lepsze. Mimo to w tym cyklu artykułów chciałbym przedstawić możliwości komunikacji radiowej wraz z praktycznymi przykładami i poradami dotyczącymi stosowania jej w robotyce.
Radio – jak to właściwie działa?
Na ten temat można napisać książkę (i to nie jedną). Dlatego przedstawię mocno uproszczony i obrazowy opis.
Zapewne każdy zna pokrótce zasadę działania transformatora. Zmienny prąd płynący w uzwojeniu pierwotnym powoduje powstanie zmiennego pola magnetycznego, które z kolei indukuje zmienny prąd w uzwojeniu wtórnym.
Teraz wyobraźmy sobie, że z transformatora usuwamy rdzeń. Rzecz jasna natężenie pola magnetycznego spadnie, co będzie równoznaczne ze zmniejszeniem się zmian prądu na uzwojeniu wtórnym. Jeśli będziemy oddalać od siebie te uzwojenia, to zmiany w uzwojeniu wtórnym będą coraz mniejsze.
Korzystając z odpowiednio czułego sprzętu będziemy mogli je jednak zauważyć.
Bardzo podobnie działa radio – tylko, że zamiast cewek mamy odpowiednie anteny, które emitują i odbierają fale elektromagnetyczne. Fale są także odpowiednio wzmacniane, zarówno w nadajniku, jak i w odbiorniki. W zależności od tego wzmocnienia a także innych parametrów fali i urządzeń, transmisja taka może mieć różny zasięg (od kilku cm w przypadku kart zbliżeniowych do setek tysięcy kilometrów w przypadku sond kosmicznych).
Moduły radiowe i nasz bohater – RFM12B
Oczywiście my nie będziemy budować układów do transmisji radiowej od podstaw – skorzystamy z gotowego modułu. Na rynku naprawdę jest z czego wybierać, urządzenia różnią się parametrami, m.in.:
możliwością komunikacji jednokierunkowej lub dwukierunkowej,
zasięgiem,
częstotliwością pracy,
rozmiarami,
zintegrowaną anteną,
obecnością dodatkowego układu wzmacniacza sygnału,
stopniem rozbudowania warstwy logicznej
i wieloma innymi.
Mój wybór padł na układy RFM12B (wersja pracująca w paśmie 868MHz). Są one łatwo dostępne i stosunkowo proste w obsłudze, a mimo to dają możliwość prowadzenia dwukierunkowej transmisji w bardzo przyjemny sposób.
Szczególną uwagę musimy zwrócić na wspomnianą literkę B w nazwie modułu.
Układy bez niej są uboższe o niektóre funkcje, przez co możemy narazić się na nieprzyjemne zmagania z tymi bliźniaczo podobnymi, a jednak różnymi, układami.
Moduły te można znaleźć w różnych obudowach – w wersji SMD i DIP z rastrem 2.0mm. Podłączenie drugiej z nich wymaga posiadania odpowiedniej złączki, natomiast dosyć łatwo można przylutować moduł w wersji SMD na zwykłą płytkę uniwersalną, co pokazuje poniższe zdjęcie:
Technika wykonania jest następująca:
Bierzemy dłuższy kawałek odizolowanego drutu miedzianego, przekładamy go od spodu przez płytkę.
lutujemy go do płytki.
Wystającą część doginamy tak, aby dotykała pola lutowniczego modułu, po czym przycinamy, aby nie wystawała ponad jego poziom.
Lutujemy drut do modułu.
Odcinamy jego nadmiar od spodniej strony płytki.
Oczywiście układ pozycjonujemy tak, aby jego środkowe wyprowadzenia były w jednej linii z otworami na płytce – dzięki temu układ będzie umocowany symetrycznie.
RFM12B i jego nóżki – czyli rzecz o podłączeniu
Kolejną kwestią, którą musimy rozważyć jest zasilanie – jak możemy odczytać z noty katalogowej, moduł musi być zasilany napięciem z zakresu 2.2-3.8V. W związku z tym logiczne wydaje się zastosowanie zasilania napięciem 3,3V. Na tym etapie nie powinniśmy mieć co do tego żadnych wątpliwości, o ile nasz procesor także jest zasilany napięciem 3,3V. Co zrobić w innym wypadku?
Po pierwsze, musimy zapewnić naszemu układowi stabilne napięcie 3,3V – do tego celu zastosujemy stabilizator LDO LM1117-3.3. Dzięki temu na wejście możemy podać napięcie niewiele wyższe niż 3,3V (możemy zasilić go z 5V).
Następnie musimy zadbać o to, aby sygnały docierające do modułu miały co najwyżej napięcie 3,3V. Można tu zastosować dzielnik rezystancyjny, ale znacznie lepsze parametry będzie miał prosty translator, wykonany w oparciu o układ 74HC125, zasilany napięciem 3,3V.
Komunikacja w drugą stronę, czyli z układu do procesora, nie wymaga już dodatkowych układów, gdyż procesory AVR zasilane napięciem 5V powinny bez problemu rozpoznać napięcie 3,3V jako logiczną jedynkę. Ewentualnie moglibyśmy zastosować podobny bufor, zasilany napięciem 5V.
Wszystkie te połączenia pokazane są na poniższym schemacie.
Do procesora podpinamy linie MOSI, MISO, SCK i CS (do PB4 – pin SS). Na razie linię INT zostawiamy niepodłączoną – jej wykorzystaniem zajmiemy się później.
Na sam koniec do modułu radiowego musimy rzecz jasna podłączyć wspomnianą wcześniej antenę – w najprostszej wersji może być to kawałek drutu, jednak trzeba koniecznie zadbać o odpowiednią długość, w zależności od zastosowanej częstotliwości:
Do dzieła, czyli zaczynamy pisać oprogramowanie
Rzecz jasna sam moduł radiowy, nawet zasilony i z antenką, nie będzie nam do niczego przydatny bez mikrokontrolera, który będzie nim sterować. Swoje przykłady oparłem na mikrokontrolerze ATMega644P, jednak po ewentualnej modyfikacji funkcji niskopoziomowych (odpowiedzialnych za komunikację poprzez UART i SPI) bez problemu będą one działały na innych mikrokontrolerach, także spoza AVR.
Między tymi wersami przemyciłem już pewną informację – z procesorem będziemy się komunikować używając UARTu. Do połączenia będzie nam potrzebny port COM w komputerze i kabelek z układem MAX232 lub przejściówka USB<->UART (np. FT232RL). Dzięki temu będziemy mogli śledzić i analizować dane przetwarzane przez nasz układ.
Struktura programu
Na początek, jako dobrzy programiści, powinniśmy jak najlepiej zaplanować strukturę projektu.
I tak plik main.c będzie zawierać główny program, pliki RFM12B.c oraz RFM12B.h - funkcje komunikacji z układem RFM12B, plik RFM12B_reg.h - definicje wszystkich rejestrów i komend układu RFM12B, zaś pliki uart.c i uart.h to przygotowane przeze mnie biblioteki do obsługi transmisji szeregowej z wykorzystaniem buforów i przerwań (nie będę im tu poświęcał więcej uwagi, gdyż nie jest to temat tego artykułu, a ponadto są one bogato skomentowane).
Czym jest SPI?
Na początek powiem co nieco o samym interfejsie SPI. Jest to interfejs szeregowy, składający się z 3 linii: MOSI, MISO, SCK.
SCK to linia zegarowa, taktująca wysyłanie danych
MOSI to linia wyjścia z układu nadrzędnego (czyli tego, który generuje sygnał zegarowy, ang. Master Output Slave Input), podpinana do wejścia układu podrzędnego
MISO to linia o przeciwnej funkcji – stanowi wejście danych układu nadrzędnego i jest połączona z wyjściem danych układu podrzędnego.
Zasada działania tego systemu jest niezwykle prosta. W każdym cyklu zegarowym układ master wystawia na linię MOSI jeden bit danych, który jest odczytywany przez układ slave. W tym samym czasie układ slave wystawia jeden bit danych na linię MISO, skąd dana ta jest odczytywana przez układ master. Sytuacja powtarza się z każdym cyklem zegara i w ten sposób przesyłany jest kolejny bit danych.
Dodatkowo, aby umożliwić połączenie kilku układów równolegle do tej samej magistrali, wprowadzono linię CS (Chip Select – wybór układu). Tylko układ, którego linia CS zostanie ustawiona w odpowiedni stan (dla RFM12B jest to stan niski), będzie się z nami komunikował, a pozostałe układy będą niejako niewidoczne.
Początek programu
Najpierw musimy skonfigurować sam moduł SPI w mikrokontrolerze i piny konieczne do komunikacji. Realizuje to przedstawiona poniżej funkcja.
void Rfm_spi_init(void){
SPI_DDR |= (1<<SPI_SCK)|(1<<SPI_MOSI)|(1<<SPI_SS);//konfiguracja kierunku i podciągania linii SPI
SPI_PORT |= (1<<SPI_MISO);
//do poprawnej pracy modułu SPI w procesorze linia SS musi być ustawiona jako wyjście
SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPR0);//SPI w trybie master z podziałem zegara przez 64
CS_PORT |= (1<<CS_RFM);//dezaktywacja układu RFM12B
CS_DDR |= (1<<CS_RFM);//konfiguracja kierunku linii CS
}
Konfigurujemy odpowiednie linie jako wyjściowe. Na uwagę zasługuje konieczność ustawienia linii SS jako wyjścia – bez tego kontroler SPI nie będzie działał prawidłowo, nawet jeśli do sterowania linią CS RFM12B użyjemy innej linii. Dodatkowo podciągamy linię wejścia danych, następnie włączamy moduł SPI (bit SPE) w trybie master (bit MSTR) i ustawiamy podział sygnału zegarowego.
Kolejne linijki dodatkowo konfigurują linię CS podłączoną do układu RFM12B i dbają, by układ był początkowo dezaktywowany.
Układ RFM12B posiada rejestry 16-bitowe, przygotujmy funkcję, która pozwala na wymianę 16 bitów danych z układem (będziemy jednocześnie wysyłać i odbierać 16 bitów).
uint16_t Rfm_xmit(uint16_t data){
//na początek rozdzielamy dane na 2 bajty
uint8_t msb, lsb;
lsb = data;
msb = data>>8;
CS_PORT &= ~(1<<CS_RFM);//aktywujemy linię CS układu
//teraz wysyłamy 2 bajty jednocześnie odbierając 2 bajty z układu
SPDR = msb;
while(!(SPSR&(1<<7)));
msb = SPDR;
SPDR = lsb;
while(!(SPSR&(1<<7)));
lsb = SPDR;
CS_PORT |= (1<<CS_RFM);//dezaktywujemy linię CS układu
//i zwracamy odebrane dane
return( (((uint16_t)msb)<<8)+((uint16_t)lsb) );
}
Program testowy
Teraz, kiedy już mamy zdefiniowane podstawowe funkcje, umożliwiające komunikację z RFM12B, czas na prosty program testowy:
Rfm_xmit(SW_RESET);//resetuję programowo układ RFM12B
uint16_t mask;
do{//pętla...
_delay_ms(250);//dajemy układowi nieco czasu na wykonanie polecenia
status=Rfm_xmit(STATUS_READ);//odczytujemy rejestr statusu
mask=0b1000000000000000;
do{//ta pętla wyświetla binarnie zawartość tego rejestru
uart_putc((status&mask)?'1':'0');
mask>>=1;
}while(mask);
uart_puts("rn");
}while(!(status&M_POR));//...powtarzana dopóki nie odczytamy ustawienia bitu sygnalizującego poprawny reset
uart_puts("POR detectedrn");
//po odczycie bit ten powinien zostać skasowany, więc dokonujemy kolejnego odczytu
status=Rfm_xmit(STATUS_READ);
mask=0b1000000000000000;
do{//znowu wyświetlamy zawartość
uart_putc((status&mask)?'1':'0');
mask>>=1;
}while(mask);
uart_puts("rn");
//jeśli bit nadal jest ustawiony to komunikacja jest błędna
if(status&M_POR){
uart_puts("TEST FAILrn");
}else{//w przeciwnym wypadku wszystko jest OK
uart_puts("TEST PASSrn");
}
while(1);
Program ten wysyła do układu komendę resetującą – jeśli ta zostanie poprawnie wykonana, w rejestrze statusu powinien zostać zaznaczony bit POR, po czym odczyt powinien jednocześnie spowodować skasowanie tego bitu. Zatem w kolejnym odczycie bit ten powinien mieć wartość 0.
Podsumowanie
Nasze pierwsze spotkanie zakończmy więc na ustanowieniu połączenia z układem RFM12B – przed jego rozpoczęciem powinniśmy mieć przygotowane 2 bliźniacze układy z prawidłowo podłączonym układem RFM12B. Oznacza to, że 2 urządzenia powinny wyświetlić optymistyczny komunikat na ekranie: TEST PASS.
Dajcie koniecznie znać w komentarzach, jakie macie doświadczenia z tymi układami!
Dołącz do 20 tysięcy osób, które otrzymują powiadomienia o nowych artykułach! Zapisz się, a otrzymasz PDF-y ze ściągami (m.in. na temat mocy, tranzystorów, diod i schematów) oraz listę inspirujących DIY na bazie Arduino i Raspberry Pi.
To nie koniec, sprawdź również
Przeczytaj powiązane artykuły oraz aktualnie popularne wpisy lub losuj inny artykuł »
Dołącz do 20 tysięcy osób, które otrzymują powiadomienia o nowych artykułach! Zapisz się, a otrzymasz PDF-y ze ściągami (m.in. na temat mocy, tranzystorów, diod i schematów) oraz listę inspirujących DIY z Arduino i RPi.
Trwa ładowanie komentarzy...