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);
//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();
//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); } } }