Arduino WiFi modul NRF24L01

Arduino WiFi modul nRF24L01 je bezdrátový modul, který umožňuje komunikaci mezi Arduino deskami. WiFi v názvu modulu označuje pracovní frekvenci, která je 2,4 GHz a právě tato frekvence je běžně využívána pro propojování počítačů či telefonů s bezdrátovými routery. Je ale nutné zdůraznit, že není možné se pomocí modulu nRF24L01 připojit na domácí síť WiFi a potažmo internet, pro tyto účely slouží například ESP8266. Co se týká napájení, bezdrátový modul nRF24L01 vyžaduje napětí 3,3 V, ale datové piny jsou schopné pracovat s 5 V logikou Arduino desky a není tedy nutné používat žádné převody napájecích úrovní. Vysílací výkon nRF24L01 lze nastavit ve čtyřech úrovních od MIN do MAX (viz ukázkový kód), ale pro úrovně HIGH a MAX je doporučeno použít externí zdroj napětí 3,3 V, protože pro tyto vysílací výkony už není dostačující maximální proud, který dokáže dát stabilizátor na Arduino deskách. Co se týká proudového odběru, v Power down režimu má nRF24L01 udávanou spotřebu jen 1 mikroAmpér. Při odesílání a příjmu dat ale může tento bezdrátový modul odebírat krátkodobě až stovky miliAmpér a proto je vhodné kromě externího zdroje napětí 3,3 V připojit i kondenzátor 10 mikroFarad mezi napájecí napětí 3,3 V a zem GND. Jak bylo zmíněno, jako externí zdroj lze použít například stabilizátor napětí AMS1117-3,3V.

Pro úspěšné propojení s Arduinem je nutné použít dvě Arduino desky a dva nRF24L01 moduly, přičemž obě desky můžeme zapojit shodně. Propojíme pin 1(GND) se zemí Arduina, pin 2(VCC) s napájecím napětím 3,3 V, pin 3(CE) s pinem D7, pin 4(CS) s pinem D8, pin 5(SCK) s pinem D13, pin 6(MOSI) s pinem D11 a pin 7(MISO) s pinem D12. Ze zmíněných pinů je možné zaměnit pouze CE a CS, přičemž změnu je nutné provést i na začátku programu.

Pro správnou funkci uvedených ukázkových kódů je nutné stáhnout a naimportovat knihovnu RF24, návod jak na to je uveden zde. Ukázkový kód pro vysílač obsahuje na svém začátku připojení knihoven a dále nastavení propojovacích pinů CE a CS a inicializaci nRF24L01 z knihovny RF24 společně s vytvořením proměnných pro uložení adres pro přijímač a vysílač. U těchto dvou proměnných je pak nutné použít stejné názvy v obou programech (zde prijimac00 a vysilac00). V podprogramu setup je jako první nastavena komunikace po sériové lince, poté zapnuta komunikace s nRF modulem, nastaven vysílací výkon, nastaveny zapisovací a čtecí kanály a jako poslední nastaven začátek příjmu dat. Nekonečná smyčka loop pak obsahuje for smyčku, která pro ukázku projde svůj kód s postupnou změnou volby (proměnná i). Na začátku for smyčky vždy ukončíme příjem dat a pro informaci vytiskneme aktuální volbu po sériové lince. Jako další uložíme startovní čas komunikace a odešleme volbu pomocí funkce nRF.write. Po úspěšném odeslání se přepneme do režimu pro příjem dat, uložíme aktuální čas a vytvoříme proměnnou timeout pro kontrolu čekání na odezvu. V kódu poté následuje while smyčka, která vyčkává na příjem dat, přičemž se neustále kontroluje čas od začátku čekání a pokud je tento čas větší než 200 milisekund, nastavíme zmíněnou proměnnou timeout. V opačném případě, tedy při příjmu dat, se pokračuje dále v kódu. Zde si vytvoříme proměnnou prijataData a do ní pomocí funkce nRF.read uložíme přijatá data, která pak už jen vytiskneme po sériové lince společně s délkou spojení. Jako poslední je zde pauza po dobu jedné sekundy a smyčka for je ukončena.

// nRF24L01 vysílač

// připojení knihoven
#include <SPI.h>
#include "RF24.h"
// nastavení propojovacích pinů
#define CE 7
#define CS 8
// inicializace nRF s piny CE a CS
RF24 nRF(CE, CS);
// nastavení adres pro přijímač a vysílač,
// musí být nastaveny stejně v obou programech!
byte adresaPrijimac[]= "prijimac00";
byte adresaVysilac[]= "vysilac00";

void setup() {
  // komunikace přes sériovou linku rychlostí 9600 baud
  Serial.begin(9600);
  // zapnutí komunikace nRF modulu
  nRF.begin();
  // nastavení výkonu nRF modulu,
  // možnosti jsou RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX,
  // pro HIGH a MAX je nutný externí 3,3V zdroj
  nRF.setPALevel(RF24_PA_LOW);
  // nastavení zapisovacího a čtecího kanálu
  nRF.openWritingPipe(adresaVysilac);
  nRF.openReadingPipe(1,adresaPrijimac);
  // začátek příjmu dat
  nRF.startListening();
}

void loop() {
  // for smyčka pro postupné odeslání
  // hodnot 0 až 3 pro načtení všech dat
  // z přijímače
  for (int i=0; i < 4; i++ ) {
    // ukončení příjmu dat
    nRF.stopListening();
    // vytisknutí aktuální volby po sériové lince
    Serial.print("Posilam volbu ");
    Serial.println(i);
    // uložení startovního času komunikace
    unsigned long casZacatek = micros();
    // odeslání aktuální volby, v případě selhání
    // vytištění chybové hlášky na sériovou linku
    if (!nRF.write( &i, sizeof(i) )){
       Serial.println("Chyba při odeslání!");
    }
    // přepnutí do příjmu dat pro další komunikaci
    nRF.startListening();
    // uložení času začátku čekání
    unsigned long casCekaniOdezvy = micros();
    // proměnná s uložením stavu čekání na odezvu
    // od přijímače - "timeout"
    boolean timeout = false;
    // čekací while smyčka na odezvu od přijímače
    while ( ! nRF.available() ){
      // pokud do 200 000 mikrosekund nepřijde odezva,
      // ukonči čekání a nastav timeout
      if (micros() - casCekaniOdezvy > 200000 ){
          timeout = true;
          break;
      }      
    }
    // kontrola stavu timeoutu
    if ( timeout ){
      // v případě vypršení čekací smyčky,
      // vytiskni informaci o chybě spojení
      Serial.println("Chyba při prijmu, vyprseni casu na odezvu!");
    }
    // v opačném případě ulož přijatou zprávu a vypiš ji po sériové lince
    else{
        // proměnná pro uložení přijatých dat
        unsigned long prijataData;
        // příjem dat se zápisem do proměnné prijataData
        nRF.read( &prijataData, sizeof(prijataData) );
        // uložení času konce komunikace
        unsigned long casKonec = micros();
        // výpis dat z komunikace po sériové lince
        // včetně délky trvání spojení
        Serial.print("Odeslana volba: ");
        Serial.print(i);
        Serial.print(", prijata data: ");
        Serial.println(prijataData);
        Serial.print("Delka spojeni: ");
        Serial.print(casKonec - casZacatek);
        Serial.println(" mikrosekund.");
    }
    // pauza 1 sekunda
    delay(1000);
  }
}

Ukázkový kód pro přijímač je velice podobný kódu pro vysílač, první rozdíl je při nastavování zapisovacího a čtecího kanálu v podprogramu setup, kde jsou samozřejmě tyto kanály uvedeny v opačném pořadí, abychom získali funkční dvojici. V nekonečné smyčce loop jsou na začátku vytvořeny proměnné pro příjem a odezvu dat a následuje if funkce, která detekuje příjem dat. V případě, že je detekován příjem dat, jsou tyto data načteny pomocí funkce nRF.read a následně vytištěny jako volba po sériové lince. Poté následuje switch s detekcí volby, který v sobě obsahuje tři varianty odpovědi pro různé volby. Pokud je tedy přijata volba 1, uložíme do proměnné odezva čas od připojení napájení v milisekundách, v případě 2 pak v sekundách a u volby 3 v mikrosekundách. V případě, že je detekována neznámá volba (default), uložíme do odezvy nulu. Následně zastavíme příjem dat a odešleme data v proměnné odezva zpět do druhé Arduino desky. Následuje už jen přepnutí do režimu pro příjem dat a informační vytištění odezvy po sériové lince.

// nRF24L01 přijímač

// připojení knihoven
#include <SPI.h>
#include "RF24.h"
// nastavení propojovacích pinů
#define CE 7
#define CS 8
// inicializace nRF s piny CE a CS
RF24 nRF(CE, CS);
// nastavení adres pro přijímač a vysílač,
// musí být nastaveny stejně v obou programech!
byte adresaPrijimac[]= "prijimac00";
byte adresaVysilac[]= "vysilac00";

void setup() {
  // komunikace přes sériovou linku rychlostí 9600 baud
  Serial.begin(9600);
  // zapnutí komunikace nRF modulu
  nRF.begin();
  // nastavení výkonu nRF modulu,
  // možnosti jsou RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX,
  // pro HIGH a MAX je nutný externí 3,3V zdroj
  nRF.setPALevel(RF24_PA_LOW);
  // nastavení zapisovacího a čtecího kanálu
  nRF.openWritingPipe(adresaPrijimac);
  nRF.openReadingPipe(1,adresaVysilac);
  // začátek příjmu dat
  nRF.startListening();
}

void loop() {
  // proměnné pro příjem a odezvu
  int prijem;
  unsigned long odezva;

  // v případě, že nRF je připojené a detekuje
  // příchozí data, začni s příjmem dat
  if( nRF.available()){
    // čekání na příjem dat
    while (nRF.available()) {
      // v případě příjmu dat se provede zápis
      // do proměnné prijem
      nRF.read( &prijem, sizeof(prijem) );
    }
    // vytisknutí přijatých dat na sériovou linku
    Serial.print("Prijata volba: ");
    Serial.print(prijem);
    // dekódování přijatých dat
    switch( prijem ) {
      // pro známou hodnotu dat (1,2,3)
      // se odešle odezva:
      case 1:
        // v případě 1 odešli počet milisekund
        // od připojení napájení
        odezva = millis();
        break;
      case 2:
        // v případě 2 počet sekund
        // od připojení napájení
        odezva = millis()/1000;
        break;
      case 3:
        // v případě 3 počet mikrosekund
        // od připojení napájení
        odezva = micros();
        break;
      // v případě ostatních dat bude odezva 0
      default:
        odezva = 0;
        break;
    }
    // ukončení příjmu dat
    nRF.stopListening();
    // odeslání odezvy 
    nRF.write( &odezva, sizeof(odezva) );     
    // přepnutí do příjmu dat pro další komunikaci
    nRF.startListening();
    // vytištění odezvy po sériové lince     
    Serial.print(", odezva: ");
    Serial.println(odezva);  
  }
}

Po nahrání programů do obou Arduino desek s připojenými bezdrátovými moduly nRF24L01 dostaneme u desky s přijímačem například tento výpis:

Posilam volbu 0
Odeslana volba: 0, prijata data: 0
Delka spojeni: 2000 mikrosekund.
Posilam volbu 1
Odeslana volba: 1, prijata data: 1394059
Delka spojeni: 3928 mikrosekund.
Posilam volbu 2
Odeslana volba: 2, prijata data: 1395
Delka spojeni: 2028 mikrosekund.
Posilam volbu 3
Odeslana volba: 3, prijata data: 1396113436
Delka spojeni: 2000 mikrosekund.

A u Arduino desky s vysílačem například tento výpis:

Prijata volba: 0, odezva: 0
Prijata volba: 1, odezva: 3129
Prijata volba: 2, odezva: 4
Prijata volba: 3, odezva: 5179200

Arduino WiFi modul NRF24L01 je velice jednoduše použitelný modul, který umožňuje bezdrátově komunikovat mezi Arduino deskami. Mezi jeho výhody patří například nízká klidová spotřeba, vysoká rychlost, zabezpečení komunikace pomocí adres či nízká cena. Nevýhodou je pak využití pásma 2,4 GHz, které je zvlášť v obydlených oblastech silně zarušeno díky společnému využívání domácími WiFi routery pro šíření Internetu. Co se týká dosahu, při mém testování jsem s vysílacím výkonem LOW dokázal spolehlivě komunikovat přibližně na 15 metrů ve volném prostoru a 7 metrů v bytě (přes jednu zeď cca na 5 metrů). S externím zdrojem napájení a vysílacím výkonem je pak možné dosáhnout i několika desítek metrů na maximální vysílací výkon.

 

Seznam použitých komponent:

http://dratek.cz/arduino/974-arduino-uno-r3-atmega328p-1424115860.html

http://dratek.cz/arduino/892-arduino-wifi-modul-nrf24l01-1420663506.html

nebo verze s externí anténou

https://dratek.cz/arduino/882-arduino-wifi-modul-bezdratovy-1420494129.html

Další podobné články