środa, 27 kwietnia 2016

[24] Arduino - Transmisja radiowa nRF24L01+

W tym poście chciałbym przedstawić sposób wykonania transmisji bezprzewodowej za pomocą modułu nRF24L01+.

Opis modułu


Moduł transmisji opiera się na paśmie 2.4 GHz. Płytka zawiera wbudowaną antenę. Teoretyczny zasięg deklarowany w idealnych warunkach ma wynosić 100m. Zbadany zasięg pozwala na osiągnięcie odległości około 25m.

Poniżej przedstawiam opis najważniejszych elementów układu:

  • Zasilanie 3.3V, Akceptowane z zakresu od 1.9V do 3.6V.
  • Pobór prądu - odbieranie 13mA, wysyłanie 12mA
  • Częstotliwość 2,4GHz
  • Prędkość transmisji 250kbps, 1Mbps, 2Mbps
  • Antena wbudowana w moduł
  • Wzmocnienie sygnału 0 dB, -6 dB, -12 dB, -18 dB,

Rys. 1. nRF24L01+

Podczas odbierania danych pobierany jest prąd o wartości 13 mA. Natomiast podczas odbioru 12 mA. Wartość pobieranego prądu można zmniejszyć wykorzystując jeden ze stanów oszczędzania energii.

Układ posiada następujące wyprowadzenia:

  • GND - Masa
  • VCC - Zasilanie
  • CE - Pin aktywacyjny(Chip Enable)
  • CSN - Wyjście wybierające (Chip Select)
  • SCK - Sygnał zegarowy (Serial Clock)
  • MOSI - Dane dla układu peryferyjnego (Master Output Slave Input

Pin aktywacyjny CE odpowiada za wybranie sposobu pracy układu czy będzie występowało nadawanie bądź odbieranie danych. Piny CSN, SCK, MOSI oraz MISO są wyprowadzeniami interfejsu SPI. Mają one za zadanie wybranie układu peryferyjnego, zadania sygnału taktujące, obsługi danych wejściowych oraz wyjściowych.

Do transmisji danych wykorzystywana jest modulacja GFSK. Jest ona odmianą modulacji FSK, która jest stosowana przy wykonywaniu różnego typu łączności bezprzewodowej. Wartość logicznej jedynki jest generowana poprzez dodanie odchylenia częstotliwości , natomiast logiczne zero jest wyrażone poprzez ujemne odchylenie.

Ten moduł nie posiada wzmacniacza sygnału, możliwe jest wyłącznie tłumienie sygnału, w celu obniżenia wartości prądu jaki jest potrzebny do działania układu. Poniżej przedstawiam listę możliwych wartości wzmocnienia wraz z wartością prądu jaki jest pobierany:

  • 0dBm - 11,3 mA
  • -6dBm - 9mA
  • -12dBm - 7,5mA
  • -18dBm - 7,0mA
Oczywiście im mniejsza wartość wzmocnienia tym zasięg ulega drastycznemu zmniejszeniu. Przy wartości -18dBm, efektywny zakres pracy będzie się znajdował w granicach 2-3 metów.

Podłączenie


Układ należy podłączyć w następujący sposób:
VCC - 3,3V
GND - GND
MOSI - Pin 11 Arduino
MISO - Pin 12 Arduino
SCK - Pin 13 Arduino
CE - Pin 2 Arduino
CSN - Pin 3 Arduino

Dodatkowo jak najbliżej układu dobrze jest podłączyć kondensator 10uF. Inny sposób polega na podłączeniu dwóch równolegle jeden 10uF, drugi natomiast 0,1uF. 

Rozkład pinów na module do komunikacji jest taki jak na rysunku 2.

Rys. 2. Rozmieszczenie wyprowadzeń

Programowanie


Wykorzystywane są moduły jeden pracuje w trybie nadajnika, drugi natomiast jako odbiornik.

Pierwszy program będzie wysyłał stałą wartość w postaci ciągu znaków co określony interwał czasowy.

  1. //Dołączone biblioteki
  2. #include <SPI.h>
  3. #include <nRF24L01.h>
  4. #include <RF24.h>
  5. //Obiekt o nazwie radio
  6. //Jako dane piny do podłączenia
  7. //Odpowiednio CE oraz CSN
  8. RF24 radio(2, 3);
  9. //Stworzenie tablicy
  10. //z podanym adresem urządzenia
  11. //Istotne w przypadku podłączenie
  12. //kilku takich modółów
  13. const byte rxAddr[6] = "00001";
  14. void setup()
  15. {
  16.   //Aktywacja układu
  17.   radio.begin();
  18.   //ilosc prob jakie nastapia
  19.   //do utraty polaczenia, w tym przypadku
  20.   //wystąpi 20 prób
  21.   radio.setRetries(20, 20);
  22.   //dodanie nazwy adresu odbiornika z ktorym
  23.   //nastąpi komunikacja
  24.   radio.openWritingPipe(rxAddr);
  25.   //przełączenie układu do trybu transmisji
  26.   radio.stopListening();
  27. }
  28. void loop()
  29. {
  30.   //zdefiniowanie tablicy z danymi
  31.   const char text[] = "Dziala!";
  32.   //Przeslanie danych
  33.   radio.write(&text, sizeof(text));
  34.   //Funckja opozniajaca
  35.   delay(4000);
  36. }

Teraz wersja oprogramowania dla odbiornika.

  1. //Dołączone biblioteki
  2. #include <SPI.h>
  3. #include <nRF24L01.h>
  4. #include <RF24.h>
  5. //Obiekt o nazwie radio
  6. //Jako dane piny do podłączenia
  7. //Odpowiednio CE oraz CSN
  8. RF24 radio(2, 3);
  9. //Stworzenie tablicy
  10. //z podanym adresem urządzenia
  11. //Istotne w przypadku podłączenie
  12. //kilku takich modółów
  13. const byte rxAddr[6] = "00001";
  14. void setup()
  15. {
  16.   //Oczekiwanie na włączenie
  17.   //transmisji szeregowej
  18.   while (!Serial);
  19.   Serial.begin(9600);
  20.   //Aktywacja układu
  21.   radio.begin();
  22.   //Podanie adresu oraz liczby strumieni
  23.   //z danymi
  24.   radio.openReadingPipe(0, rxAddr);
  25.   //przełączenie układu do trybu transmisji
  26.   radio.startListening();
  27. }
  28. void loop()
  29. {
  30.   //sprawdzenie czy jakies dane zostały dostarczone
  31.   if (radio.available())
  32.   {
  33.     //Definicja tablicy z danymi
  34.     char text[32] = {0};
  35.     //Odczytanie danych
  36.     radio.read(&text, sizeof(text));
  37.     //Wyswietlenie danych
  38.     Serial.println(text);
  39.   }
  40. }

Kolejny program będzie odczytywał dane z potencjometru, które po przesłaniu będą wyświetlane poprzez port szeregowy oraz wyświetlacz ze sterownikiem HD44780 podłączony poprzez konwerter I2C.

W pierwszej kolejności przychodzi program z nadajnika:

  1. //Dołączone biblioteki
  2. #include <SPI.h>
  3. #include <nRF24L01.h>
  4. #include <RF24.h>
  5. //Obiekt o nazwie radio
  6. //Jako dane piny do podłączenia
  7. //Odpowiednio CE oraz CSN
  8. RF24 radio(2, 3);
  9. //Stworzenie tablicy
  10. //z podanym adresem urządzenia
  11. //Istotne w przypadku podłączenie
  12. //kilku takich modółów
  13. const byte rxAddr[6] = "00001";
  14. const int PotPin = 0;
  15. int PotencjometrWar;
  16. char Pomocnicza;
  17. void setup()
  18. {
  19.   //Oczekiwanie na włączenie
  20.   //transmisji szeregowej
  21.   while (!Serial);
  22.   Serial.begin(9600);
  23.   //Aktywacja układu
  24.   radio.begin();
  25.   //ilosc prob jakie nastapia
  26.   //do utraty polaczenia, w tym przypadku
  27.   //wystąpi 20 prób
  28.   radio.setRetries(20, 20);
  29.   //dodanie nazwy adresu odbiornika z ktorym
  30.   //nastąpi komunikacja
  31.   radio.openWritingPipe(rxAddr);
  32.   //przełączenie układu do trybu transmisji
  33.   radio.stopListening();
  34. }
  35. void loop()
  36. {
  37.   PotencjometrWar = analogRead(PotPin);
  38.   //Pomocnicza = int(PotencjometrWar);
  39.   //zdefiniowanie tablicy z danymi
  40.   int wart = PotencjometrWar;
  41.   //Przeslanie danych
  42.   radio.write(&wart, sizeof(wart));
  43.   //Funckja opozniajaca
  44.   delay(1000);
  45.   //Wyswietlenie danych
  46.   Serial.println(PotencjometrWar);
  47.   Serial.println(wart);
  48. }

Program dla odbiornika:

  1. //Dołączone biblioteki
  2. #include <SPI.h>
  3. #include <nRF24L01.h>
  4. #include <RF24.h>
  5. #include <Wire.h>  
  6. #include <LiquidCrystal_I2C.h>
  7. //Ustawienie adresu układu
  8. LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
  9. //Obiekt o nazwie radio
  10. //Jako dane piny do podłączenia
  11. //Odpowiednio CE oraz CSN
  12. RF24 radio(2, 3);
  13. //Stworzenie tablicy
  14. //z podanym adresem urządzenia
  15. //Istotne w przypadku podłączenie
  16. //kilku takich modółów
  17. const byte rxAddr[6] = "00001";
  18. void setup()
  19. {
  20.   //Oczekiwanie na włączenie
  21.   //transmisji szeregowej
  22.   while (!Serial);
  23.   Serial.begin(9600);
  24.   //Aktywacja układu
  25.   radio.begin();
  26.   //Rozpoczęcie pracy wyświetlacza
  27.   lcd.begin(16,2);
  28.   //Włączenie podświetlania
  29.   lcd.backlight();
  30.   //Ustawienie kursora w pozycji poczatkowej
  31.   lcd.setCursor(0,0);
  32.   //Podanie adresu oraz liczby strumieni
  33.   //z danymi
  34.   radio.openReadingPipe(0, rxAddr);
  35.   //przełączenie układu do trybu transmisji
  36.   radio.startListening();
  37. }
  38. void loop()
  39. {
  40.   //sprawdzenie czy jakies dane zostały dostarczone
  41.   if (radio.available())
  42.   {
  43.     lcd.clear();
  44.     //Definicja tablicy z danymi
  45.     int wart = 0;
  46.    
  47.     //Odczytanie danych
  48.     radio.read(&wart, sizeof(wart));
  49.     lcd.println(wart);
  50.     //Wyswietlenie danych
  51.     Serial.println(wart);
  52.   }
  53. }