Aproximación al RFM69


           El RFM69 es un módulo de radio de bajo coste y baja potencia. Es un transceptor, es decir, puede emitir y recibir entre nodos sensores y/o con un nodo estación base que puede centralizar todos los datos generados por otros módulos, así como emitir ordenes a esos nodos. Por su precio, alcance, consumo mínimo y escalabilidad son ideales para crear redes de domótica.

           Básicamente, se crea una red (identificada con un número de 0 a 255) y cada nodo también se identifica de 0 a 255. Por tanto, dentro de una red, cada nodo puede enviar y recibir teniendo en cuenta el número del otro nodo.

          Disponible en tres frecuencias 433, 868 y 915Mhz. Funciona de 1,8 a 3,6v  y transmite hasta 100mW, pero  solo cuando envía un paquete de datos.
          El consumo va de 130mA a 16mA cuando recibe. He usado los módulos de 433Mhz
          No entro en más detalles ya que la documentación técnica en internet es extensa.
          El objetivo de este artículo es mostrar un uso básico de este módulo con un montaje y un software mínimos, aunque aparte de lo mostrado, el RFM69 tiene muchas más posibilidades.
          El RFM es estupendo, pero no hace nada por si solo, necesita un microprocesador para gestionarlo.
          He elegido el Arduino Pro Mini a 3,3v que podemos conectar directamente al RFM69 que también funciona a esa tensión en entradas y salidas de pines. Evidentemente se necesitan dos módulos y dos Arduino. En el lado emisor uso un sensor de temperatura LM35 y en lado receptor una pantalla OLE de 0,96''.
          Para la frecuencia de 433Mhz una antena de 1/4 de onda mide 60,4mm
          El Sketch del receptor envía una petición al módulo con el/los sensores y este responde. Además, entre ambos hay un envío ACK  que confirma la transacción de datos. En la pantalla se va actualizando temperatura, humedad (he puesto un valor ficticio) y también tenemos disponible el indicador de fuerza de la señal recibida (RSSI).
          Y puesto que los módulos son transceptores, el receptor que recibe los datos, puede cambiar a transmitir ordenes a los sensores para realizar acciones (encender la calefacción). En el Sketch se envía cada 5'' la orden "encender LED"

          Para buen funcionamiento debe alimentarse con una fuente de 3,3v. La potencia que da el interface USB-TTL solo es suficiente para conexión a pocos centímetros. 
//Sketch receptor de datos nodo maestro
//www.jopapa.me 2021
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#include <RFM69.h>
#include <SPI.h>
#include <Wire.h>

//Configuracion de este nodo
#define RED                 100   //Identificacion de la red, debe ser la misma para todos los nodos entre 0 y 255
#define NODO_ID             2   //Identificacion individual del Nodo, debe ser diferente para cada nodo
#define NODO_DESTINO  1   //Identificacion del nodo con el que se desea comunicar (0 to 254, 255 = a todos)
#define FRECUENCIA  RF69_433MHZ  //Cambiar si es de 433 o 868
#define CLAVE "Chapuzas_Jopapa" //Clave de encriptacion para todos los modulos                     
RFM69 radio;

int x=0, Error=0;
bool Conexion=true;

int Periodo=5000;
unsigned long TiempoAhora=0;

void setup(){
Serial.begin(115200);
display.begin(SSD1306_SWITCHCAPVCC, 0x3c);
display.setTextSize(1);
display.setTextColor(WHITE);
// Inicializacion del modulo  RFM69HCW
radio.initialize(FRECUENCIA, NODO_ID, RED); // configuracion de los parametros de red
radio.setHighPower();  //Potencia maxima solo para el RFM69HCW
radio.encrypt(CLAVE);  //Encriptación
Serial.println("Inicializacion terminada"); //Mensaje de finalizacion solo para depuracion
PedirDatos();
}


void loop(){
  if(x==100){ //Leemos datos cada 1'' aprox. Puede actualizarse mucho mas rápido.
    PedirDatos(); //Se consulta la temperatura
    x=0; //Reinicio de contador de ciclos
  }
  x++;
 
  // Recibir
  if (radio.receiveDone()){ //Espera hasta recibir un dato
    String data = ""; //Cadena recibida
    String Temp = ""; //Cadena para la temperatura
    String Humedad="";
   
    for (byte i = 0; i < radio.DATALEN; i++) {
      data.concat((char)radio.DATA[i]); //Se guardan los datos recibidos
    }
     
    //Datos recibidos
    uint8_t t = data.indexOf("t"); uint8_t h = data.indexOf("h");
    Temp=data.substring(0,t);
    Humedad =data.substring(6,h);      //Extrae solo valor humedad
    //conversion a valores numericos
    float data_temp = Temp.toFloat();
    float data_Humedad = Humedad.toFloat();
   
    display.clearDisplay();
    display.setCursor(0,0);
    display.println("Temp: "+String(data_temp));
    display.setCursor(0,12);
    display.println("Humd: "+String(data_Humedad));
    display.setCursor(0,24);
    display.println("RSSI: "+String(radio.RSSI));
    Serial.println("Temp: "+String(data_temp)); 
    Serial.println("Humedad: "+String(data_Humedad)); 
    Serial.println("Señal: " + String(radio.RSSI));
    display.display();

    //Envio de ACK cuando es solicitada
    if (radio.ACKRequested()){
      Serial.println("ACK enviado");
      radio.sendACK();
    }
    delay(10);
  }

if(millis() > TiempoAhora + Periodo){  //Simulación de enviar orden al sensor
  TiempoAhora=millis();
  enviar();
}
  delay(10);
}


void PedirDatos(){
  char buf[]="D";
  Serial.println("Consulta de datos");
  if (radio.sendWithRetry(NODO_DESTINO, buf, sizeof(buf))){
     Error=0;
     if(Conexion==false){
        Conexion=true;
      }
     Serial.println("ACK recibido");
  }else{
     Error++;
     Serial.println("ACK  no recibido");
  }
  //Comprobacion de la conexion
  if(Error==5){
    Error=0;
    Conexion=false;
  }
  delay(15);



void enviar(){   //envia una orden al esclavo
char radiopacket[20] = "Enciende LED";  
Serial.print("Enviando "); Serial.println(radiopacket); 
if (radio.sendWithRetry(NODO_DESTINO, radiopacket, strlen(radiopacket))) {
  Serial.println("OK");
  } 
radio.receiveDone(); //pone radio en modo RX
delay(20);
}
//Sketch que envia datos nodo esclavo
//www.jopapa.me 2021
#include "RFM69.h"
#include <SPI.h>
#include <Wire.h>

//Configuracion de este nodo
#define RED                   100   // Debe ser el mismo para todos los nodos (0 a 255)
#define NODO_ID               1   // Mi identificador del nodo (0 a 255)
#define NODO_DESTINO    2   // Identificador del nodo destido (0 a 254, 255 = a todos)
#define FRECUENCIA     RF69_433MHZ     //Cambiar si es de 433 o 868
#define CLAVE "Chapuzas_Jopapa" //Clave de encriptacion para todos los modulos
RFM69 radio;
const int sensorPin= A0;  //para leer temp. con LM35

void setup(){
  Serial.begin(115200); delay(100);
  // Inicializacion del modulo  RFM69HCW
  radio.initialize(FRECUENCIA, NODO_ID, RED);
  radio.setHighPower(); //Potencia maxima solo para el RFM69HCW
  radio.encrypt(CLAVE);
}

void loop(){
  int value = analogRead(sensorPin);
  float millivolts = (value / 1023.0) * 3300;
  float temp = millivolts / 10;
  float humedad = random(41,59);  //valor ficticio para pruebas
//  Serial.println(temp);
  if (radio.receiveDone()){ //Espera hasta recibir un dato
    String Mensaje = "";
    for (byte i = 0; i < radio.DATALEN; i++){
      // Se construye el mesaje recibido:
      Mensaje.concat((char)radio.DATA[i]);
    }
    //Envio de ACK cuando es solicitada
    if (radio.ACKRequested()){
      radio.sendACK();
    }
    // Si se ha solicitado envíar la temperatura:
    if (Mensaje == "D") {     
      String str = String(temp)+ 't' + String(humedad) + 'h';  //Trama a enviar
      int sendlength2 = str.length();
      char sendbuffer2[sendlength2];
      str.toCharArray(sendbuffer2, sizeof(sendbuffer2) + 1);

      // Verificación del envio:
      radio.sendWithRetry(NODO_DESTINO, sendbuffer2, sendlength2);
    }
    if (Mensaje == "Enciende LED") {
        //Realizar cualquier acción en este nodo
        Serial.println(Mensaje);
    }
  }
}
Menu