Arduino Tutorial 24: Enviar datos digitales mediante NRF24L01

En esta entrada vamos a usar el módulo NRF24L01. Con este módulo podemos llevar a cabo comunicaciones inalámbricas entre 100 y 200 metros de longitud máxima. El precio es bajo y se pueden encontrar en Amazon.
Podéis consultar el datasheet del integrado en el siguiente link. Además os dejo el enlace de la librería que usamos en el siguiente link.
 
Para esta entrada necesitamos:
  • 2  módulos NRF24L01
  • 2 arduinos
  • 1 led
  • 1 pulsador

 

Lo primero que tenemos que saber es como conectar el módulo NRF24L01 al arduino:
Módulo NRF24L01
Módulo NRF24L01

esquema pines
Esquema de la conexión de los pines
La columna que indica los colores, es referente a la forma de como se conectara nuestro dispositivo con respecto a la imagen que dejare anexada.
 
Una vez conocidos los pines, tenemos que descargarnos la libreria que he dejado al principio de la entrada y agregarla a las librerias de vuestro arduino.
 
Por otro lado, en el arduino que elijáis como emisor, debereís conectar el pulsador, en este caso al pin 2, y en el receptor el led al pin 2.
 
A continuación os dejo el montaje y el código del emisor y del receptor:

 EMISOR

Esquema del emisor
Esquema del emisor
//exportamos la libreria mirf de nuestras librerias
#include <Mirf.h>
#include <MirfHardwareSpiDriver.h>
#include <nRF24L01.h>
#include <SPI.h>

int pulsador = 2;

void setup(){
  Serial.begin(9600);
  pinMode(pulsador, INPUT);

  // Iniciamos el modo de trasmision
  Mirf.spi=&MirfHardwareSpi;
  Mirf.init();

  // Nombre que le vas a dar a este modulo NRF24L01
  // sería el equivalente a la IP de un ordenador. 5 bytes maximo.
  Mirf.setRADDR((byte *)"RX_99");

  // payload de un byte (es decir, un número entre 0 y 255). Si quiere mandar dos datos, ponemos un 2 (en vez de un 1), y así hasta cuantos datos queramos enviar
  Mirf.payload = 1;

  // indicamos el canal por el cual vamos a enviar la información. En el receptor tenemos que poner el mismo canal
  Mirf.channel = 32;

  // a configurar y vaciar cola FIFO
  Mirf.config();

  Serial.println("iniciando...");
}

void loop(){
  int estado = digitalRead(pulsador);
  Serial.print("Valor pulsador: ");  
  Serial.println(estado);

  // nombre del NRF24l01 al que vamos a emitir. (nombre del receptor el cual se configura en el programa arduino del receptor)
  Mirf.setTADDR((byte *)"TX_01");

  //ahora emitimos
  Mirf.send((byte*)&estado);

  //esperamos a que termine de emitir
  while( Mirf.isSending() ) ;
  delay(1000);
}

 RECEPTOR

Esquema del receptor
Esquema del receptor
#include <MirfHardwareSpiDriver.h>
#include <Mirf.h> 
#include <nRF24L01.h> 
#include <SPI.h> 

const int led=2; 

void setup() { 
  Serial.begin(9600); 
  pinMode(led,OUTPUT); 
  Mirf.spi=&MirfHardwareSpi; 
  Mirf.init(); 

  // Nombre que le damos a este módulo NRF24L01. 
  // seria el equivalente a la ip de un ordenador. 5 bytes maximo. 
  Mirf.setRADDR((byte *)”TX_01″); 

  // Payload, en bytes, a transmitir (es decir, un número entre 0 y 255). Si quiere mandar dos datos, ponemos un 2 (en vez de un 1), y así hasta cuantos datos queramos enviar 
  Mirf.payload = 1; 

  // el canal por el cual estaremos transmitiendo (el mismo que hemos puesto en el emisor) 
  Mirf.channel = 32; 

  // Esto inicia el mirf y borra la lista FIFO 
  Mirf.config(); 
} 

void loop() { 
  byte c; 
  // comprobamos que no hay datos a recibir. 
  if( Mirf.dataReady() ) { 
    // recibimos la información y lo almacenamos en c 
    Mirf.getData(&c); 
    if(c==1) { 
      digitalWrite(led,HIGH); 
    } 
    else { 
      digitalWrite(led,LOW); 
    } 

    // imprimiremos en el puerto serial el estado que recibimos del PIR 
    Serial.print(“El valor es: “); 
    Serial.println(c); 
    } 
}

 


A continuación os dejo un vídeo con la demostración:
Como hemos comentado en el código, enviamos un byte, es decir, un número entre 0 y 255. Para este ejemplo no hemos tenido problemas ya que enviabamos un 0 ó un 1. Si queremos enviar señales analógicas, lo mejor es realizar una escala de 0 a 100 para poder enviarlo, es decir, convertir el valor analógico en el programa del emisor, enviarlo y si luego se desea, desconvertir el valor en el programa del receptor.
El código para realizar esta conversión es:
 
position = map(humedad, 0, 1023, 0, 100);
 
Los dos primeros valores indican el valor mínimo y máximo que alcanza el instrumento analógico y los dos siguientes valores indican el valor mínimo y máximo que queremos que alcancen. En este caso el 0 analógico equivaldria a 0% y el 1023 analógico a 100%.

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

6 comentarios en “Arduino Tutorial 24: Enviar datos digitales mediante NRF24L01”

  1. Hola, primero para agradecer los alcances que nos das con estos tutoriales y segundo para realizarte una pregunta.
    Yo me estoy iniciando en el mundo de arduino y Raspberry Pi 3, y trato de desarrollar un sistema de comunicaciones entre 2 arduinos y un raspberry a distancia.
    Básicamente el proyecto trata de una par cisternas que almacenan agua de la red publica y estas abastecen a otras que están algo distantes, se que tienes otros tutoriales que explican esos procedimientos pero no puedo saltar a algo mas complejo si aun no entiendo lo mas básico.

    En el “void loop()” cuando haces la emisión del datos “Mirf.send((byte*)&estado);”.

    Si yo tengo mas de un dato para enviar como seria la linea de instrucción ??
    “Mirf.send((byte*)&estado, &Dato1, &Dato2);”, y así sucesivamente ??, o como tendría que hacer ??
    Saludos cordiales.

    1. Muchas gracias por los cumplidos 😀 Puedes subscribirte a nuestro blog.

      Lo primero decirte que yo siempre he trabajado con Raspberry Pi (la 1), así que puede que algunos comandos del blog relacionados con la Raspberry Pi te den error. Pero bueno, para este tutorial no necesitamos Raspberry Pi, así que vamos al lio.

      Lo primero que tienes que hacer es cambiar el Mirf.payload e igualarlo al número de datos que quieras enviar. Si quieres enviar dos datos entonces será Mirf.payload=2;

      Por otro lado, el Mirf.send((byte*)&estado); no puedes cambiarlo, tiene que ser así. Lo que tienes que cambiar es “el estado”, ahí irán los dos datos a enviar.

      Te pongo un ejemplo. Quieres enviar una temperatura y un tiempo:

      EMISOR


      struct DATOS{
      float temp;
      unsigned long time;
      }
      datos;

      ....
      ....

      Mirf.payload = sizeof(datos);

      ...
      ...

      Mirf.send((byte *)&datos);

      RECEPTOR

      struct DATOS{
      float temp;
      unsigned long time;
      }
      datos;

      ...
      ...

      Mirf.payload = sizeof(datos);

      ...
      ...

      Mirf.getData((byte *) &datos);

      Puedes poner Mirf.payload = sizeof(datos); o Mirf.payload = 2 eso ya como te guste. Lo bueno de no poner el número directamente es que si amplias en número de datos a enviar, no tienes que preocuparte de si te acordarás o no de cambiarlo ahí también.

      Espero que te sirva, yo nunca he probado a enviar dos datos porque no lo he necesitado, pero puede que lo pruebe dentro de poco.

      Saludos

  2. Muchas gracias por tu pronta respuesta y si, ya me acabo de suscribir al blog, muy interesante, gracias.

    Con respecto al consejo que me alcanzas, lo pruebo y te comento.

    Cabe señalar que he estado usando la biblioteca RF24 y tengo problemas al enviar datos, por ejemplo tengo el CE en pin 9 y CSN en pin 10 y da el error de transmisión, cambio los pines físicamente sin cambiar la configuración del programa compilo, subo y mismo error, devuelvo los pines a su sitio original , compilo, subo y empieza a transmitir, luego desconecto el arduino de la raspberry y lo alimento de forma de externa pero ya no transmite, le pude un led para que acuse cuando se ejecute satisfactoriamente la transmisión y este se enciende obviamente cuando empieza a transmitir conectado a la raspberri pero ya no enciende cuando lo conecto con la fuente de alimentación externa.

    Te alcanzo el código de transmisión para que lo revises, quizás hay algo que no estoy haciendo bien y me imagino que el código debe andar algo inestable o débil, luego te alcanzo el código de recepción ya lo estoy modificando, así vamos avanzando.

    Luego pruebo la librería Mirf, estaría bueno conocer ambas.

    Codigo de transmision con libreria RF24:

    /* Proyecto 1: Nivel de cisternas con sensor ultrasonico HC-SR04
    *
    * Este programa sensa constantemente el nivel de agua de las cisternas elevadas
    * con el sensor ultrasonico, si el nivel de agua se encuentra en un rango bajo
    * se envia una peticion a las cisternas de abajo para que le sumistren agua.
    * Este sistema tiene 3 leds.
    * Led verde: Indica un nivel alto
    * Led amarillo: Indica un nivel medio
    * Led naranja: Indica un nivel bajo
    * Led rojo: Indica un nivel muy bajo
    */
    // Incluimos las librerias para el modulo RF
    #include
    #include “RF24.h”
    #include “nRF24L01.h”
    #include “RF24_config.h”

    /*Pines NEF24L01 no configurables
    * MOSI => 11
    * MISO => 12
    * SCK => 13
    */
    // Modulo RF: CE = 9 (Slave Select) – CSN = 10 (Chip Select Not)
    // Sintaxis: RF24 moduloRF(pinCSN, pinCE)

    #define pinCE 9
    #define pinCSN 10
    RF24 moduloRF(pinCSN, pinCE);

    // Definiendo un array que representa la direccion (“pipe”)
    const uint64_t pipe = 0xF0F0F0F0E1LL;

    // definiendo array para envio de datos
    int datos[4];

    // Definiendo los pines del HCSR04
    const int trigPin = 2;
    const int echoPin = 3;

    // Definiendo pines I/O
    const int ledVer = 4; // Pin 4, verde led RGB
    const int ledAzu = 5; // Pin 5, azul led RGB
    const int ledRoj = 6; // Pin 6, rojo led RGB
    const int ledAma = 7; // pin 7, led amarillo – acuse transmision datos

    // Variables para statusLED, distancia y tiempo
    String estadoLED = “”; // Mensaje texto estado led
    int statusLED = 0; // Mensaje numerico estado led
    int distancia; // Variable que aloja el calculo de distancia
    unsigned long duracion; // Variable duracion de señal HCSR04

    // Niveles cisterna (cm)
    int nivActual; // Iniciamos variable nivel actual de agua
    int altSens = 180; // Distancia entre la base de la cisterna y el sensor
    int fullCis = 170; // Cisterna full
    int ledVerd = 150; // Si valor = 170 : nivel alto
    int ledAmar = 100; // Si valor = 149 : Nivel medio
    int ledNara = 50; // Si valor >= 50 y valor = 0 y valor = ledVerd && nivel = ledAmar && nivel = ledNara && nivel = ledRojo && nivel <= ledNara)
    {
    digitalWrite(ledVer, LOW);
    digitalWrite(ledAzu, LOW);
    digitalWrite(ledRoj, HIGH);
    estadoLED = ", Rojo: Nivel de agua muy bajo…";
    statusLED = 4;
    }
    return;
    }

    1. Hola de nuevo. Lo primero preguntarte si con la libreria RF24 has intentado mandar un número o un mensaje, para ver si realemnete te funciona bien (antes de meter el sensor y los leds).

      Por otro lado a siemple vista veo algunos fallos como:
      RF24 moduloRF(pinCSN, pinCE); esta mal. Es –> RF24 radio(pinCE, pinCSN);
      – Ese código no envia nada, se necesita radio.begin(); radio.openWritingPipe(addresses[1]); radio.openReadingPipe(1,addresses[0]); radio.startListening();

      Te aconsejo que primeros intentes comunicar tus arduinos con el siguiente ejemplo (o los que vienen por defecto de arduino) y a partir de ahí vayas modificando.

      EMISOR

      #include
      #include
      #include

      //Declaremos los pines CE y el CSN
      #define CE_PIN 9
      #define CSN_PIN 10

      //Variable con la dirección del canal por donde se va a transmitir
      byte direccion[5] ={‘c’,’a’,’n’,’a’,’l’};

      //creamos el objeto radio (NRF24L01)
      RF24 radio(CE_PIN, CSN_PIN);

      //vector con los datos a enviar
      float datos[3];

      void setup()
      {
      //inicializamos el NRF24L01
      radio.begin();
      //inicializamos el puerto serie
      Serial.begin(9600);

      //Abrimos un canal de escritura
      radio.openWritingPipe(direccion);

      }

      void loop()
      {
      //cargamos los datos en la variable datos[]
      datos[0]=1;
      datos[1]=22;
      datos[2]=3.14;
      //enviamos los datos
      bool ok = radio.write(datos, sizeof(datos));
      //reportamos por el puerto serial los datos enviados
      if(ok)
      {
      Serial.print(“Datos enviados: “);
      Serial.print(datos[0]);
      Serial.print(” , “);
      Serial.print(datos[1]);
      Serial.print(” , “);
      Serial.println(datos[2]);
      }
      else
      {
      Serial.println(“no se ha podido enviar”);
      }
      delay(1000);
      }

      RECEPTOR

      #include
      #include
      #include

      //Declaremos los pines CE y el CSN
      #define CE_PIN 9
      #define CSN_PIN 10

      //Variable con la dirección del canal que se va a leer
      byte direccion[5] ={‘c’,’a’,’n’,’a’,’l’};

      //creamos el objeto radio (NRF24L01)
      RF24 radio(CE_PIN, CSN_PIN);

      //vector para los datos recibidos
      float datos[3];

      void setup()
      {
      //inicializamos el NRF24L01
      radio.begin();
      //inicializamos el puerto serie
      Serial.begin(9600);

      //Abrimos el canal de Lectura
      radio.openReadingPipe(1, direccion);

      //empezamos a escuchar por el canal
      radio.startListening();

      }

      void loop() {
      uint8_t numero_canal;
      //if ( radio.available(&numero_canal) )
      if ( radio.available() )
      {
      //Leemos los datos y los guardamos en la variable datos[]
      radio.read(datos,sizeof(datos));

      //reportamos por el puerto serial los datos recibidos
      Serial.print(“Dato0= ” );
      Serial.print(datos[0]);
      Serial.print(“Dato1= ” );
      Serial.print(datos[1]);
      Serial.print(“Dato2= ” );
      Serial.println(datos[2]);
      }
      else
      {
      Serial.println(“No hay datos de radio disponibles”);
      }
      delay(1000);
      }

      Este código lo que hace es enviar: 1; 22: 3.14
      Lo que recibe es: Dato0=1, Dato1=22, Dato3=3.14

      Ya nos contarás que tal vas …

      Saludos

  3. Hola,
    Yo trato de enviar un dato del tipo integer (int).
    Pero para no complicarme la existencia voy a ir por pasos y seguir tu consejo.
    Tengo 2 arduino UNO y dos módulos RFN24L01, al primer conjunto le llamaremos equipo1 y al otro equipo2.
    Cargue el sketck de emisor en el equipo1 y me muestra “no se puede enviar”, pero cuando desconecto el pin PIN_CSN empieza transmitir, por ahi me sale un “no se puede enviar” pero son muy pocos; En el equipo2 me pasa exactamente lo mismo.
    Ahora, en teoría se que los módulos funcionan, como ??, no se, ya tienen el mensionado PIN_SCN desconectado, bien, subo el receptor en el equipo2 con el PIN_SCN desconectado y dejando al emisor en equipo1 y obtengo como respuesta “no hay datos de radio disponible”, entonces al equipo2 le vuelvo a conectar el PIN_CSN y sigo obteniendo el mismo mensaje.
    Solo cuando empiezo a conectar los cables PIN_CE y PIN_CSN por ahí tengo tengo respuestas:
    Dato0= nanDato1= nanDato2= nan
    Dato0= 0.00Dato1= 0.00Dato2= 0.00
    Luego y por ultimo, reconecte los PIN_CSN en ambos equipos y empezó nuevamente con el bendito mensaje de “no hay datos de radio disponible”.
    Quiero creer y por lo que veo, el problema pasa por un tema de contactos, espero sea eso.
    Tu que opinas de mi dilema ??
    Saludos cordiales

    1. La verdad que es muy raro lo que cuentas de los pines, es como si los cables hicieran mal el contacto o estuvieran rotos/cortados por algún lado.
      Por si acaso te recuerdo que en la libreria RF24 los pines se conectan diferente que en la Mirf: https://e-elektronic.com/nrf24-arduino-raspberry-pi-bidireccional/

      Indagando un poco por las redes, he descubierto que existe una libreria con la que se puede testear si algun módulo funciona mal: http://playground.arduino.cc/InterfacingWithHardware/Nrf24L01

      Como ya te he comentado no puedo probarlo ahora mismo, así que ya nos contaras…

      #include
      #include

      // Singleton instance of the radio driver
      //RH_NRF24 nrf24;
      RH_NRF24 nrf24(8, 7); //8–>csn ,7–>cs use this to be electrically compatible with Mirf
      // RH_NRF24 nrf24(8, 10);// For Leonardo, need explicit SS pin
      // RH_NRF24 nrf24(8, 7); // For RFM73 on Anarduino Mini

      void setup()
      {
      Serial.begin(9600);
      // while (!Serial)
      // ; // wait for serial port to connect. Needed for Leonardo only
      if (!nrf24.init()){
      Serial.println(“init error”); }
      else {
      Serial.println(“init OK !!!!”); }
      // Defaults after init are 2.402 GHz (channel 2), 2Mbps, 0dBm
      if (!nrf24.setChannel(1)){ Serial.println(“setChannel error”);}
      if (!nrf24.setRF(RH_NRF24::DataRate2Mbps, RH_NRF24::TransmitPower0dBm)) {
      Serial.println(“setRF error”); }
      }

      void loop()
      {
      Serial.println(“Sending to nrf24_server”);
      // Send a message to nrf24_server
      uint8_t data[] = “holaaaaaaaaaaaaa”;
      nrf24.send(data, sizeof(data));

      nrf24.waitPacketSent();
      // Now wait for a reply
      uint8_t buf[RH_NRF24_MAX_MESSAGE_LEN];
      uint8_t len = sizeof(buf);

      if (nrf24.waitAvailableTimeout(1500))
      {
      // Should be a reply message for us now
      if (nrf24.recv(buf, &len))
      {
      Serial.print(“got reply: “);
      Serial.println((char*)buf);
      Serial.println(” reply EXITO “);
      delay(1000);
      }
      else
      {
      Serial.println(“recv failed”);
      }
      }
      else
      {
      Serial.println(“No reply, is nrf24_server running?”);
      }
      delay(1);
      }

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *