Kurs Arduino #10: Obsługa modułów RF 433MHz i 315MHz

KURS ARDUINO10W dzisiejszej części kursu zaczniemy radiowo komunikować się między dwoma Arduino przy pomocy modułów RF 433MHz albo 315MHz. Pokaże jak wysyłać zwykły kod, wartość ADC oraz transmisję z danego czujnika. Zapraszam do lektury !

 

 

 

 

 

Spis treści:

  1. Moduły RF  – działanie i obsługa
  2. Omówienie podstawowych funkcji
  3. Pierwszy program – transmisja kodu
  4. Drugi program – transmisja wartości ADC
  5. Trzeci program – transmisja temperatury z czujnika DS18B20

Co będziemy potrzebować:

  • Moduły RF 433MHz albo 315MHz
  • 2x Arduino
  • Wyświetlacz HD44780
  • Czujnik temperatury Dallas DS18B20
  • 2x Przyciski typu tact-switch
  • 2x dioda LED
  • 4x rezystor 220 ohm
  • zestaw przewodów połączeniowych
  • biblioteka VirtualWire

 

1.Moduły RF  – działanie i obsługa

Moduły RF są to urządzenia które wysyłają (nadajnik) bądź odbierają (odbiornik) sygnał elektromagnetyczny. Największą ich zaletą jest to, że cała transmisja odbywa się bezprzewodowo. Dzieję się tak przy pomocy modulacji częstotliwości. Sygnał wysyłany, czyli sygnał elektryczny jest przetwarzany w nadajniku na falę elektromagnetyczną o danej częstotliwości. W naszym przypadku jest to 433Mhz albo 315MHz (w zależności, który moduł kupiliście). Natomiast odbiornik pracuje dokładnie na odwrót niż nadajnik. Odbiornik odbiera falę elektromagnetyczną, a następnie przetwarza ją na zwykły sygnał elektryczny i wysyła do urządzenia odbiorczego. Ale jak to się dzieje że odbiornik odbiera dokładnie te dane ? Tutaj właśnie pojawia się częstotliwość. Sygnał elektromagnetyczny, który jest wysyłany, posiada swoją częstotliwość, czyli te 433MHz albo 315MHz, natomiast odbiornik odbiera wszystkie fale. nie tylko fale naszego urządzenia. Odbiera dokładnie wszystkie fale o częstotliwości na jaką jest zaprojektowany. Dopiero dalsza elektronika (w tym przypadku Arduino) wydziela te sygnały elektryczne, które pokrywają się ze wzorem wgranym do tej elektroniki. Przykład: chcemy wysłać kod, który składa się ze znaków: „Ardu!no”. Nadajnik wysyła ten kod i następnie ten kod „wisi w atmosferze”- dosłownie. Tutaj przychodzi rola odbiornika, który zbiera wszystkie sygnały o danej częstotliwości. W tej całej zbieraninie sygnałów znajduje się nasz kod, czyli Ardu!no. Jeżeli nasza elektronika rozpozna ten wzór to zaczyna jakiś tam swój podprogram przeznaczony dla tego wzoru sygnału. Oczywiście mówimy tutaj o warunkach niemalże wyidealizowanych, ale nie niemożliwych. Odbiorniki słabej jakości, czyli właśnie ten, o którym będzie dzisiaj mowa, zbierają wszystkie „śmieci” z atmosfery, przez co transmisja na większą odległość >30m dla tego typu kodu będzie niemalże nie możliwa. Natomiast, jeżeli zależy nam na jakości i odległości wysyłanego sygnału to możemy zakupić już moduły lepszej jakości, lecz wiąże się to z większymi kosztami- ok. 70zł na jeden z modułów.
Przedstawiony w dzisiejszej części kursu, moduł odbiornika można samemu przestrajać na różne częstotliwości. Obrazek poniżej zaprezentuje sposób ich przestrajania:

modul_rf_up

 

W przypadku nadajnika, to go nie przestroimy ponieważ częstotliwość sygnału jest ustalana przez rezonator typu SAW. Jedynie jego wymiana o innej częstotliwości załatwiła by sprawę. Kolejna kwestia to zasilanie tych modułów.
Zasilanie modułów powinno być dobrze odfiltrowane, np. przez dławik osiowy 10uH bądź pary kondesatorów. Odfiltrowanie zasilania jest bardzo ważne, ponieważ minimalizuje wszelkie szumy czy też zakłócenia. O ile w układzie nadajnika nie ma to tak dużego znaczenia to w odbiorniku ma to ogromne znaczenie. Jak wcześniej wspominałem o droższych modułach to one charakteryzują się tym, że on już posiadają wbudowane filtrowanie zasilania. Następna ważna sprawa co jest dużym przewinieniem to zasilanie nadajnika. Często w internecie widuje, że nadajnik tego typu jest zasilany przez 5V z Arduino. Nie jest to co prawda duże przewinienie, ponieważ nadajnik działa w zakresie 3-12V, ale zasilając napięciem 5V to przeważnie po paru metrach tracimy łączność. Dlatego zazwyczaj używa się baterii 12V, aby wzmocnienie sygnału było duże co w konsekwencji prowadzi do zwiększenia zasięgu nadajnika.
Tyle tematem wstępu. Jeżeli jesteś bardziej ciekawy tej tematyki to poszukaj w literaturze zagadnień opisujących zasadę działania radia, modulacji częstotliwości, modulacji ASK i pochodnych tego tematu.

2. Omówienie podstawowych funkcji

Ze względu na to, że moduły nie są wspierane przez Arduino IDE, to musimy do niego do instalować bibliotekę obsługującą te moduły. W pętli startowej programu dodajemy takie funkcje

prędkość transmisji. W przypadku tych modułów, prędkość 2000 bodów działa dobrze. Jeżeli chcesz poeksperymentować to po próbuj prędkości w zakresie 1000-7000 bodów.

Nadajnik:

Funkcje poniżej zawieramy w pętli głównej programu:

Zdefiniowanie pinu, do którego podłączamy nadajnik:

Funkcja ta odpowiada za wysyłanie naszego kodu. Musimy w niej podać 2 argumenty. Co wysyłamy, czyli jaki kod, oraz z ilu znaków się składa.

Ta funkcja opóźnia działanie Arduino do momentu wysłania całego kodu. Gdybyśmy tej funkcji nie użyli to mogłoby się zdarzyć tak, że Arduino chciałoby wysłać kolejny kod, kiedy poprzedni nie został wysłany w całości. Oczywiście zamiast tej funkcji możemy wstawić opóźnienie, ale musielibyśmy je zmieniać za każdym razem gdy zmieniałaby się długość kodu. Dlatego ta funkcja jest dobra, ponieważ automatycznie zmienia nam się czas opóźnienia programu.

Odbiornik:
Zdefiniowanie pinu, do którego podłączamy odbiornik:

Ta funkcja rozpoczyna transmisję danych z odbiornika do Arduino

Od tego kawałka kodu powyżej zaczynamy pętlę główną programu odbiornika. Mówiąc w większym skrócie, aby nie tłumaczyć zaraz całej biblioteki to ten kod definiuje wszystkie odebrane dane jako pojedyncze znaki 8 -bitowe w systemie ASCII, a następnie sprawdza czy dotarły  do buforu utworzonego przez bibliotekę jakieś dane i czy długość tych danych nie przekracza 8 bitów. Jeżeli wszystko się „zgadza” to program przechodzi dalej.

Gdy już nasze odebrane dane przeszły wstępną weryfikację to są dalej przetwarzane.  Na start tworzymy dwie zmienne. Jedną „i” odpowiadającą za następne iteracje funkcji for() oraz zmienną string „dane„, w której wszystkie nasze odebrane znaki zostaną połączone w jeden ciąg znaków. Funkcja for() przesyła do funkcji niżej znaki do momentu, aż zostanie opustoszony bufor. Każdy znak jest wrzucany do zmiennej string. Przy pomocy operatora += znaki przesłane z buforu do zmiennej są łączone.
Jeżeli od razu nie zrozumiałeś co dzieje się w tym kodzie to się nie martw, ponieważ dla początkujących może być on trochę zaawansowany, ale z czasem jak będziesz próbować implementować własne kody pod te moduły to zrozumiesz ;)

Teraz możemy przejść już do łatwiejszej części jaką jest pisanie programów. Pierwszy program będzie prosty, bo będziemy wysłać znaki, które będą zapalać i gasić diody ;)

3. Pierwszy program – transmisja kodu

Schemat nadajnika:
kurs 10 nadajnik_bb

Odbiornika:

kurs10.1odbironikProgram nadajnika:

W funkcji startowej, jak wcześniej wspomniałem musimy dla nadajnika dodać informację do jakiego pinu jest podłączony oraz z jaką prędkością odbywa się transmisja. Następnie w pętli głównej tworzymy tablice dwuznakowe. Pierwsza tablica zawiera znaki W1, a druga W2. Następnie tworzymy funkcje warunkowe if dla wciśniętych przycisków. Jeżeli przycisk pierwszy został wciśnięty to wyślij w postaci 8 bitowej, tablicę znaków wl, przekonwertowaną na ASCII o wielkości 2 znaków. Następnie czekaj aż cała tablica zostanie wysłana i odczekaj 1 sekundę. Opóźnienie 1 sekundowe wzięło się z tego powodu, że jak wciśniemy przycisk to funkcja może zostać wykonana parę razy. Natomiast jak wstawimy opóźnienie sekundowe to następnie wciśnięcie będzie zrealizowane dopiero po 1 sekundzie. Ten sam warunek dzieje się dla drugiego przycisku.

Okej teraz możemy przejść do trudniejszej części jaką jest odbiór danych:

W dzisiejszej części kursu będzie można zauważyć parę zapożyczeń z języka C++. Jednym z takich zapożyczeń będzie wykorzystanie typu boolowskiego (ang. bool, boolean). Typ ten zwraca dwie wartości prawdę albo fałsz. Przyda się ona do negacji stanów diod.
Definiujemy dwie zmienne boolowskie stanz odpowiadającą za diodę zieloną oraz stancz odpowiadającą za diodę czerwoną i ustawiamy ich wartość początkową na false, czyli 0. Następnie w pętli startowej definiujemy pod jak pin podłączamy odbiornik, z jaką prędkością będzie wykonywana transmisja oraz sygnalizujemy rozpoczęcie odbioru danych. Na początku w pętli głównej odbywa się to o czym wspomniałem wcześniej, czyli sprawdzanie odebranych danych. Następnie te dane przetwarzane są na zmienną string dane. Teraz przystępujemy do funkcji warunkowej. Jeżeli odebrane dane są równe W1, czyli naszej pierwszej tablicy to zmień stan diody zielonej przy pomocy operatora =! , co można dalej przetłumaczyć jako negację zmiennej. Jak widać zamiast na sztywno wpisanego stanu diody w funkcji digitalWrite() to wpisałem zmienną jako stan diody. Po zmianie stanu program ma poczekać 0.1s. To samo dzieje się dla warunku drugiego, gdzie dane równe są W0. Wtedy negowany jest stan diody czerwonej. W efekcie czego nasz pierwszy program działa na takiej zasadzie, że jak wciśniemy raz przycisk to dioda się zapala, a jak drugi raz to dioda gaśnie. Po wgraniu programów efekt powinniśmy otrzymać następujący:

  • Romek

    Witajcie
    Poradnik wyczesany. Mam jednak pytanie jak wysłać kilka parametrów.
    Np. kilka czujników DS18b20

    • Cześć :)
      Możesz spróbować przechowywać dane w tablicy jednowymiarowej i zrobić to na tej zasadzie. W nadajniku zrobić odczyty z kilku czujników, a następnie zapisać je w tablicy, potem wysłać zawartość tej tablicy i odczytać ją w odbiorniku. Zobacz jak to było zrealizować w części o nRF24L01

      • Romek

        Zastanawiam się nad sposobem przypisania do każdej zmiennej indywidualnego znacznika np $ @ # po wykryciu którego odbiornik będzie potrafił przyporządkować konkretnej zmiennej jej odpowiednik z nadajnika.
        Sprawdzę jak to rozwiązałeś w nRF`ie . Dzięki wielkie

        • tak też można zrobić :)

          • Romek

            Pomysł wydaje mi się słuszny lecz nie wiem w którym miejscu kodu i w jaki sposób do przesłać. Czy tworzyć dodatkową zmienną np string i ją wysyłać ??

          • Spróbuj najpierw z tablicami. Jeżeli masz więcej pytań to zapraszam na forum, tam będziemy walczyć z Twoimi problemami :)

  • mbawol

    Poradnik OK, ale jedna rzecz do poprawy – wcięcia kodu są nielogiczne – straciłem chyba godzinę na tym dlaczego kod nie działa, a potem zauważyłem że ify z W1 i W2 nie znajdują się na poziomie globalnym/ w funkcji loop, jak sygerowałyby wcięcia, tylko są zagnieżdżone w ifie vw_get_message :)

  • Rafał Langner

    Są jakieś możliwości do optymalizacji, żeby kod mieścił się w Atmedze 8?

  • saper

    Ostatni kod. Można wyrzucić lcd.clear(); wtedy jeśli temperatura jest w przedziale 0-9 to w miejsce dziesiątek wrzucić spację. Ekran nie będzie migał :)