Hola amigos del foro,
Llevo un par de semanas tratando de resolver un problema de comunicación entre mi Arduino UNO rev3 y un dispositivo que es controlado a través de RS232, usando el protocolo de comunicación Modbus.
Gracias al trabajo increíble de gente altruista dentro del foro, pude encontrar unas librerías que permitían conectar un Arduino UNO (haciendo de máster) con un escalvo usando el protocolo de comunicación Modbus.
Estas librerías se encuentran en el siguiente link:
Previo a la implementación del código de mi Arduino, quise probar la comunicación mediante un emulador de máster y el esclavo en cuestión, un controlador Eurotherm 2406.
El detalle del controlador puede ser visto en la siguiente dirección:
El programa usado fue Qmodbus, un software genial y sencillo de manejar:
Conociendo la dirección del registro en el esclavo que debía consultar, su identificador, la función y la configuración del puerto serie, no tuve ningún problema para extraer dicho dato. El programa hacia su función al 100% y el esclavo respondía a la petición del máster.
En un segundo step, cargué el ejemplo del máster en Arduino UNO, llamada software_serial_simple_master, ya que quería monitorizar el resultado de la adquisición del máster en el PC tras la respuesta del slave y si usaba el ejemplo de simple_master tenía problemas con el USB y los pines de Tx y Rx predeterminados en Arduino UNO. A la par que cargaba el ejemplo, usé el programa de emulación de esclavo modbus, llamado Modbus Slave. Un programa muy sencillo de manejar, también.
El programa lo podéis encontrar aquí:
http://www.modbustools.com/download.html
Una vez cargaba el ejemplo y configuraba el esclavo; función, dirección de registro, número de registros, congifuración del puerto serie, etc..; Arduino era capaz de recibir y plotear los valores de las direcciones del esclavo, previa petición del máster.
A modo de ejemplo, aquí pongo una parte del código que usé:
case 1:
telegram.u8id = 1; // slave address
telegram.u8fct = 3; // function code (this one is registers read)
telegram.u16RegAdd = 1; // start address in slave
telegram.u16CoilsNo = 1; // number of elements (coils or registers) to read
telegram.au16reg = au16data; // pointer to a memory array in the Arduino
Hasta aquí bien...
-
Conozco las direcciones del esclavo donde debo mirar,
-
Me percato de que el Máster emulador esta leyendo el esclavo real, Eurotherm 2406, y hay comunicación
-
Programo Arduino en versión máster y me lee las direcciones que predetermino en el esclavo emulado
Pero al conectar el máster arduino al esclavo real, el Eurotherm, este no me devuelve nada. O más bien, me devuelve 0, cuando teóricamente debería estar leyendo un parámetro de temperatura del controlador, el cual se encuentra en la dirección 1.
Permitidme dejaros las capturas de pantalla que he ido generando en cada step, así como el código completo que cargo en Arduino Uno.
Breve explicación de las capturas:
-
Lectura Qmodbus Eurotherm 2406: Se puede ver como Eurotherm ha devuelto el dato de temperatura, 259 (25.9ºC)
-
Modificiación dato registro esclavo simulado: En el programa Modbus Slave se pude ver como modifico la dirección de registro 1.
-
Retorno esclavo simulado hacia Arduino Master: Aquí podemos ver cómo el puerto serie devuelve el valor que tenía la dirección del registro del esclavo simulado
-
Lectura Arduino máster hacia Eurotherm 2406: Respuesta de la entrada de recepción de Arduino máster tras hacer petición a Eurotherm.
#include <ModbusRtu.h>
#include <SoftwareSerial.h>
// data array for modbus network sharing
uint16_t au16data[16];
uint16_t au16data1[16];
uint8_t u8state;
/**
* Modbus object declaration
* u8id : node id = 0 for master, = 1..247 for slave
* u8serno : serial port (use 0 for Serial)
* u8txenpin : 0 for RS-232 and USB-FTDI
* or any pin number > 1 for RS-485
*/
Modbus master(0); // this is master and RS-232 or USB-FTDI via software serial
/**
* This is an structe which contains a query to an slave device
*/
modbus_t telegram;
unsigned long u32wait;
SoftwareSerial mySerial(3, 5);//Create a SoftwareSerial object so that we can use software serial. Search "software serial" on Arduino.cc to find out more details.
void setup() {
Serial.begin(9600);//use the hardware serial if you want to connect to your computer via usb cable, etc.
master.begin( &mySerial, 9600 ); // begin the ModBus object. The first parameter is the address of your SoftwareSerial address. Do not forget the "&". 9600 means baud-rate at 9600
master.setTimeOut( 2000 ); // if there is no answer in 2000 ms, roll over
u32wait = millis() + 1000;
u8state = 0;
}
void loop() {
switch( u8state ) {
case 0:
if (millis() > u32wait) u8state++; // wait state
break;
case 1:
telegram.u8id = 1; // slave address
telegram.u8fct = 3; // function code (this one is registers read)
telegram.u16RegAdd = 1; // start address in slave
telegram.u16CoilsNo = 1; // number of elements (coils or registers) to read
telegram.au16reg = au16data; // pointer to a memory array in the Arduino
master.query( telegram ); // send query (only once)
u8state++;
break;
case 2:
master.poll(); // check incoming messages
if (master.getState() == COM_IDLE) {
u8state = 0;
u32wait = millis() + 2000;
Serial.print("Valor de la direccion 1: ");Serial.println(au16data[0]);//Or do something else!
u8state++;
}
break;
}
}
¿A alguna alma caritativa se le ocurre qué puedo estar haciendo mal?
Os doy gracias mil por la ayuda que pueda recibir.
Saludos,