20.05.2013Transceiver NRF24L01 - Základy použití



Transceiver nRF24L01+ je nízkoodběrový digitální vysílač a příjmač na frekvenci 2.4GHz založený na chipu Nordic nRF24L01+ od Nordic Semiconductor. Tento chip obsahuje vše potřebné ke komunikaci. Je potřeba pouze krystal, odpovídající obvod a anténa. Díky tomu je možné udělat opravdu malé zařízení schopné kvalitní komunikace. nRF24L01+ komunikuje přes SPI a umožňuje i kontrolu zda byla zaslaná data doručena do cíle! Zařízení pracuje rychlostí až 2Mbps na vzdálenost až 100m bez externí antény (na volném prostranství). Maximální napájecí napětí je 3.6V

Pokud máte zájem, můžete si odemne koupit 1ks za 65kč + poštovné (do 20ks za 35kč). Možnost osobního vyzvednutí v Praze (u metra Muzeum, samozřejmě bez poštovného). V případě zájmu piště na hawwwran@launchpad.cz

Pro program Energia existuje knihovna (github, forum.43oh.com), která používání tohoto zařízení velmi zjednoduší.

Pinout (pohled shora)


Pinout (pohled shora) - varianta nano


Varianta Nano - Nejmenší na trhu!


Varianta Nano - nejmenší na trhu

Varianta Nano - nejmenší na trhu


Ukázka zapojení pro MSP430G2553

(platí pro ukázky dodávané s knihovnou, ke stažení na konci článku)

nRF pin / LaunchPad pin
=======================

Vcc -> Vcc
GND -> GND
SCK -> P1.5
MO -> P1.7
MI -> P1.6
(pozn. MO a MI musí být pro G2xx2 a G2xx1 čipy prohozené)
CE -> P2.0
CSN -> P2.1
IRQ -> P2.2

Pozor: Definice Enrf24 class "Enrf24 radio(..., ..., ...);" nahoře v ukázkách bere piny v pořadí CE, CSN a IRQ.

enrf24_txdemo.ino - Ukázka programu pro vysílač

#include <Enrf24.h>
#include <nRF24L01.h>
#include <string.h>
#include <SPI.h>

Enrf24 radio(P2_0, P2_1, P2_2);  // P2.0=CE, P2.1=CSN, P2.2=IRQ
const uint8_t txaddr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x01 };

const char *str_on = "ON";
const char *str_off = "OFF";

void dump_radio_status_to_serialport(uint8_t);

void setup() {
  Serial.begin(9600);

  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(1); // MSB-first

  radio.begin();  // Defaults 1Mbps, channel 0, max TX power
  dump_radio_status_to_serialport(radio.radioState());

  radio.setTXaddress((void*)txaddr);
}

void loop() {
  Serial.print("Sending packet: ");
  Serial.println(str_on);
  radio.print(str_on);
  radio.flush();  // Force transmit (don't wait for any more data)
  dump_radio_status_to_serialport(radio.radioState());  // Should report IDLE
  delay(1000);

  Serial.print("Sending packet: ");
  Serial.println(str_off);
  radio.print(str_off);
  radio.flush();  //
  dump_radio_status_to_serialport(radio.radioState());  // Should report IDLE
  delay(1000);
}

void dump_radio_status_to_serialport(uint8_t status)
{
  Serial.print("Enrf24 radio transceiver status: ");
  switch (status) {
    case ENRF24_STATE_NOTPRESENT:
      Serial.println("NO TRANSCEIVER PRESENT");
      break;

    case ENRF24_STATE_DEEPSLEEP:
      Serial.println("DEEP SLEEP <1uA power consumption");
      break;

    case ENRF24_STATE_IDLE:
      Serial.println("IDLE module powered up w/ oscillators running");
      break;

    case ENRF24_STATE_PTX:
      Serial.println("Actively Transmitting");
      break;

    case ENRF24_STATE_PRX:
      Serial.println("Receive Mode");
      break;

    default:
      Serial.println("UNKNOWN STATUS CODE");
  }
}


enrf24_rxdemo.ino - Ukázka programu pro příjmač

#include <Enrf24.h>
#include <nRF24L01.h>
#include <string.h>
#include <SPI.h>

Enrf24 radio(P2_0, P2_1, P2_2);
const uint8_t rxaddr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x01 };

const char *str_on = "ON";
const char *str_off = "OFF";

void dump_radio_status_to_serialport(uint8_t);

void setup() {
  Serial.begin(9600);

  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(1); // MSB-first
  
  radio.begin();  // Defaults 1Mbps, channel 0, max TX power
  dump_radio_status_to_serialport(radio.radioState());

  radio.setRXaddress((void*)rxaddr);
  
  pinMode(P1_0, OUTPUT);
  digitalWrite(P1_0, LOW);
  
  radio.enableRX();  // Start listening
}

void loop() {
  char inbuf[33];
  
  dump_radio_status_to_serialport(radio.radioState());  // Should show Receive Mode

  while (!radio.available(true))
    ;
  if (radio.read(inbuf)) {
    Serial.print("Received packet: ");
    Serial.println(inbuf);

    if (!strcmp(inbuf, str_on))
      digitalWrite(P1_0, HIGH);
    if (!strcmp(inbuf, str_off))
      digitalWrite(P1_0, LOW);
  }
}

void dump_radio_status_to_serialport(uint8_t status)
{
  Serial.print("Enrf24 radio transceiver status: ");
  switch (status) {
    case ENRF24_STATE_NOTPRESENT:
      Serial.println("NO TRANSCEIVER PRESENT");
      break;

    case ENRF24_STATE_DEEPSLEEP:
      Serial.println("DEEP SLEEP <1uA power consumption");
      break;

    case ENRF24_STATE_IDLE:
      Serial.println("IDLE module powered up w/ oscillators running");
      break;

    case ENRF24_STATE_PTX:
      Serial.println("Actively Transmitting");
      break;

    case ENRF24_STATE_PRX:
      Serial.println("Receive Mode");
      break;

    default:
      Serial.println("UNKNOWN STATUS CODE");
  }
}


Poznatky


  • Při snížení rychlosti SPI nejde zapisovat registry (a nejspíš selže i mnoho dalších příkazů). Zatím se zdá, že nastavení prescaleru SPI na 0x20 je při taktovací frekvenci 1MHz bezpečné.
  • Je náchylný na zkrat IO pinů, speciálně při přímém uzemění serial out pinu úplně shoří (doslova a do kouře).
  • Při výkyvech napájení občas selže. Je potřeba na to dát pozor a když neodpovídá dobré věci, přeinicializovat ho. V tomhle by možná pomohlo trošku ověřovat co vlastně ten čip vrací a občas si přečíst status registr, nejenom když z něj něco chci…
  • Pomocí IRQ pinu jde bez zdržování zjistit, že je v paměti přijatá zpráva. Pokud je HIGH, je v paměti zpráva. Lze to zjistit i přes SPI, ale trvá to déle. Knihovna Enrf24 uní oboje, běžně se využívá právě IRQ viz. "while (!radio.available(true))", kde "true" určuje použít právě IRQ.


Poznatky ke knihovně Enrf24


  • Pro komunikaci se musí nastavit "adresa" pro komunikaci. Je to takový klíč, kterým se "podepíše" vysílání a příjmač tak pozná (protože má nastavenou stejnou adresu), že je vysílání určené pro něj. Tato adresa se skládá z 5 bajtů. To davá opravdu velikou svobodu, pokud chcete komunikovas s více zařízeními. Vždy platí, že příjmač a vysílač musejí mít stejnou adresu, ale tu lze kdykoliv měnit. Můžete tak nastavit adresu, poslat zprávu, změnit adresu a poslat zprávu jinam. Změnu adresy lze dělat velmi rychle, bez následného čekání na "přeladění". Prostě nastavíte na jendom řádku adresu a hned odesíláte. Mimo definice adresy v HEXA, jak je to v příkladech jde nastavit adresu i jinak, například pomocí charů. Můžete tak nastavit adresu která je mnohem lépe zapamatovatelná. Ukázka definování v charech: "char txaddr[] = {'d','e','v','-','0'};"
  • Lze mít zapnutý příjmač i vysílač zároveň. Ne tedy opravdu najednou, ale můžete v "setup" nastavit adresy pro RX i TX a zapnout RX (radio.enableRX();) a přes to používat "radio.print();" a "radio.flush();". Jednoduše se přeruší poslouchání (RX), odešle se zpráva (TX) a pak se zase zapne poslouchání (RX) a to automaticky, takže obousměrná komunikace je snadná.
  • Lze jednoduše kontrolovat zda zpráva dorazila do cíle. Tato schopnost se jmenuje auto-ack (auto acknowledgement). Dělá se to tak, že se před odesláním zprávy nastaví "radio.lastTXfailed=false;", pak se odešle zpráva a ověří se stav lastTXfailed "if(radio.lastTXfailed){/*zpráva nebyla přijata*/}".
  • Bez zapojeného IRQ pinu nefunguje auto-ack (informace o úspěšnosti doručení zprávy)


Ke stažení

examples.zip - Ukázky použití (kód pro příjmač, vysílač a scanner kanálů)
nrf24l01p_product_specification_1_0.pdf - Datasheet k chipu nRF24L01+

Odkazy

Knihovna na práci s chipem pro Energia
Fórum na 43oh.com věnující se knihovně pro Energia
Informace o chipu na webu Nordic Semiconductor
Návod pro zapojení a použití s Arduino


comments powered by Disqus