Comunicacion modbus VARIOS arduinos. Modulo MAX485.

Hola, llevo unos dias trabajando para crear una red modbus dirigida con un Arduino Mega 2560 que sea capaz de dar una orden para que otros arduinos UNO esclavos ejecuten una accion u otra.

Es decir, con mi arduino mega mando una señal modbus a diferentes arduinos para que abran o cierren unos reles a distancia. Eso esta hecho, conecto mi arduino mega a un solo arduino y abro y cierro sin problema, mi duda basicamente es cuando conecto varios arduino UNO esclavos, como elijo o direcciono cada uno de los arduinos para que abra y cierre solamente uno de ellos, porque con mi codigo abriria todos al mismo tiempo.

Este seria el codigo de mi arduino mega maestro:

void setup() 
{ 
  Serial.begin(9600);
   pinMode(4, INPUT_PULLUP);
} 
 
void loop() 
{ 
  int data; 

 if (digitalRead(4) == LOW) {
  data = 1;  
 }

  else {
    data = 0;
  }
  
  Serial.write(data);
  delay(250);
  Serial.println(data);                           
}

Y este otro el de un arduino UNO esclavo:

#include <ModbusMaster.h>
ModbusMaster node;

void setup() 
{ 
  Serial.begin(9600); 
    // Modbus slave ID 1
    node.begin(1, Serial); 
} 
 
void loop() 
{  
  if (Serial.available()) 
  {
    int data = Serial.read(); 
    
    if (data == 1){
    Serial.println("abrir");
    }
    
        if (data == 0){
    Serial.println("cerrar");
    }
  }

}

¿Que parte del codigo debo modificar en los receptores o el emisor para que solo envie la orden a uno en concreto? Un saludo y gracias de antemano.

Los ejemplos de la librerías Modbus siempre traen un Master y un Slave.
Parte de ellos para entender como comunicarte de ida o de vuelta.

Buenas surbyte, ya he mirado los ejemplos y otros post en el foro para llegar al punto donde estoy, ya se mandar y recibir datos conectando solamente 2 arduinos, el problema es que al conectar 3 o mas, no se como apuntar para leer o escribir unicamente en uno de ellos, no he encontrado ejemplos claros sobre eso.

Basicamente si que puedo escribir y recibir sobre 1 dispositivo que actue como esclavo modbus pero no se como convertir un arduino en un dispositivo esclavo modbus con una direccion fija.

Hola, como puse al principio estoy intentando hacer una red modbus entre varios arduinos, como no lo conseguía he decidido simplemente optar por probar los códigos de ejemplo como me dijo subryte de las librerías pero no consigo hacer que funcione nada. Ahora mismo estoy trabajando con la librería ArduinoModbus que depende de la librería ArduinoRS485.

Dentro de ArduinoModbus estoy probando los programas de ejemplo subiendo un programa client a mi Arduino mega y el server a mi Arduino UNO. Ambos los tengo conectados con un modulo TTL to RS485 MAX485, los tengo bien conectados dejando RO a RX, DI a TX, DE y RE a VCC para client y a GND para server.

CODIGO CLIENT:

#include <ArduinoRS485.h> // ArduinoModbus depends on the ArduinoRS485 library
#include <ArduinoModbus.h>

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

  Serial.println("Modbus RTU Client Toggle");

  // start the Modbus RTU client
  if (!ModbusRTUClient.begin(9600)) {
    Serial.println("Failed to start Modbus RTU Client!");
    while (1);
  }
}

void loop() {
  // for (slave) id 1: write the value of 0x01, to the coil at address 0x00 
  if (!ModbusRTUClient.coilWrite(1, 0x00, 0x01)) {
    Serial.print("Failed to write coil! ");
    Serial.println(ModbusRTUClient.lastError());
  }

  // wait for 1 second
  delay(1000);

  // for (slave) id 1: write the value of 0x00, to the coil at address 0x00 
  if (!ModbusRTUClient.coilWrite(1, 0x00, 0x00)) {
    Serial.print("Failed to write coil! ");
    Serial.println(ModbusRTUClient.lastError());
  }

  // wait for 1 second
  delay(1000);
}

CODIGO SERVER:

#include <ArduinoRS485.h> // ArduinoModbus depends on the ArduinoRS485 library
#include <ArduinoModbus.h>

const int ledPin = LED_BUILTIN;

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

  Serial.println("Modbus RTU Server LED");

  // start the Modbus RTU server, with (slave) id 1
  if (!ModbusRTUServer.begin(1, 9600)) {
    Serial.println("Failed to start Modbus RTU Server!");
    while (1);
  }

  // configure the LED
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  // configure a single coil at address 0x00
  ModbusRTUServer.configureCoils(0x00, 1);
}

void loop() {
  // poll for Modbus RTU requests
  ModbusRTUServer.poll();

  // read the current value of the coil
  int coilValue = ModbusRTUServer.coilRead(0x00);

  if (coilValue) {
    // coil value set, turn LED on
    digitalWrite(ledPin, HIGH);
  } else {
    // coil value clear, turn LED off
    digitalWrite(ledPin, LOW);
  }
}

Con todo así lo único que consigo es recibir por el monitor serie del cliente es el mensaje "Failed to write coil! Conection timed out". Me gustaría saber posibles errores en la conexión/compatibilidad del modulo, ya que al ser un ejemplo de la librería deduzco que no será cosa del código. Un saludo y gracias.

Es muy posible que las conexiones RS485 esten con algun error.
Dime como las tienes hechas entre ambos Arduinos.

No olvides nada. Si te resulta mas fácil haz un esquema y tomale una foto y luego la subes. Especifica los arduinos, los pines, y cada conexion hecha.

EDITO 1:

Supongo que respetaste esto

MKR 485 shield

  • ISO GND connected to GND of the Modbus RTU server
  • Y connected to A/Y of the Modbus RTU client
  • Z connected to B/Z of the Modbus RTU client
  • Jumper positions
  • FULL set to OFF
  • Z // Y set to OFF

En especial GND

EDITO 2: Ahora veo que la librería por defecot supone que uses TX y RX por lo tanto cosas como

Serial.print("Failed to write coil! ");

Se transforman en un problema porque envia mensajes que seran rechazados por la RED RS485 a menos que me equivoque.

Si miras con atención encontrarás esto

Modify the pins to used to communicate with the MAX3157. By default the library uses pin 14 for TX, pin A6 for drive output enable, and pin A5 for receiver output enable.

TX apunta a pin 14 y pin A5 es RE y A6 es DE

RS485.setPins(int txPin, int dePin, int rePin)

esta todo pensado para los MKR1XXX

Asi que usa esto para cambiar los pines y que no sean TX y RX. Asigna otros asi conservarás el SErial para ver que ocurre.

Mi consejo es que busques otra librería. Lee que en Hardware alguien esta usando otra librería con un PLC Siemens.
O busca en el foro que hay muchos ejemplos exitosos.

Buenas, de primeras perdón por la tardanza pero estuve ausente por covid, y muchas gracias por tus aportes.
Es mi primer post en el foro asique no se si recibiré respuesta en un post pasados tantos días pero voy a intentar explicarlo todo detalladamente aquí, allá voy.

Lo que intento conseguir es un riego automático mediante un sistema mono cable, en este, un Arduino Mega2560 situado en un cuadro eléctrico general dentro de un cabezal actuara como maestro y recibiría unas entradas mediante sus pines, dependiendo de que pin reciba debería actuar por modbus sobre diferentes relés situados en el campo, los cuales, al abrir o cerrar su contacto alimentaran solenoides para dar paso al agua.

Teniendo esto en mente compré una placa de 4 relés manejados por modbus (Relay Board-4 V1.2), con el siguiente código ya he conseguido actuar sobre esta placa modbus de relés para alimentar un solenoide con la librería "ModbusMaster" y el siguiente código:

#include <ModbusMaster.h>    //utilizamos la libreria modbusmaster (añadir libreria en programa-añadir libreria).

#define MAX485_DE      2    //PIN utilizado para elegir modo receptor(LOW GND)/transmisor(HIGH VCC)


ModbusMaster node;  //Definir objeto maestro.

void preTransmission()
{


  digitalWrite(MAX485_DE, 1);
  delay(10);
}

void postTransmission()
{
  digitalWrite(MAX485_DE, 0);
  delay(10);
}

void setup()
{

  
  pinMode(MAX485_DE, OUTPUT);
  
  // iniciar en modo receptor
  digitalWrite(MAX485_DE, 0);

  // Iniciamos comunicacion modbus 9600 baud rate.
  Serial.begin(9600);

  // Iniciamos puesto modbus  ( ID del esclavo, puerto)
    node.begin(1, Serial);
  
  // Configuracion voids para pasar de receptor a transmisor
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
  
}

void loop()
{


//declalro variables para alojar la lectura.
int entrada1;
int entrada2;
int entrada3;
int entrada4;




//lecturas de entradas
int Mdelay = 15;   // microdelay
node.readDiscreteInputs(0x0, 1);       // node."funcion"(registro inicial, numero de registros)
Serial.print("[ENTRADA1] ");
entrada1 = node.getResponseBuffer(0);  //Igualamos el valor de la respuesta buffer a la variable entrada1
Serial.print(entrada1); 
delay(Mdelay);
node.clearResponseBuffer();            //limpiamos el valor del buffer para siguientes lecturas


Serial.print("  ");
node.readDiscreteInputs(0x1, 1);
Serial.print("[ENTRADA2] ");
entrada2 = (node.getResponseBuffer(0));
Serial.print(entrada2);
delay(Mdelay);
node.clearResponseBuffer();


Serial.print("  ");
node.readDiscreteInputs(0x2, 1); 
Serial.print("[ENTRADA3] ");
entrada3 = (node.getResponseBuffer(0));
Serial.print(entrada3);
delay(Mdelay);
node.clearResponseBuffer();


Serial.print("  ");  
node.readDiscreteInputs(0x3, 1); 
Serial.print("[ENTRADA4] ");
entrada4 = (node.getResponseBuffer(0));  
Serial.print(entrada4);
delay(Mdelay);
node.clearResponseBuffer();

Serial.print("  ");  

//escribir salidas al leer entradas


if ( entrada1 == 1 ) {
  node.writeSingleCoil(0x0, 1);  // node."funcion"(registro, valor a escribir)
  node.writeSingleCoil(0x3, 1);
   
}
else{
  node.writeSingleCoil(0x0, 0); 
  node.writeSingleCoil(0x3, 0);

}

if ( entrada2 == 1 ) {
  node.writeSingleCoil(0x1, 1);
    node.writeSingleCoil(0x2, 1);  
}
else{
  node.writeSingleCoil(0x1, 0);
  node.writeSingleCoil(0x2, 0);

} 
}

Problemas:
1º- No encuentro forma de cambiar la dirección asignada a la placa de relés para utilizar varias de estas.

2º- Según comprendo la dirección del esclavo se elige en el setup haciendo

node.begin(1, Serial); //(ID, PUERTO)

y no se hasta que punto podría estar apuntando a diferentes direcciones en mitad del código.

3º- Creo que de la forma en la que actuó con esta librería no puedo hacerlo sobre otros arduinos como explico en la parte de abajo.


Habiendo hecho todo lo anterior decidí intentar hacer lo mismo pero en vez de usar placas de relés modbus, utilizar Arduinos UNO como esclavos,, estos solo deberían ser capaces de recibir un numero, ya sea de cualquiera de estas 2 formas:

1º- Que todos reciban el numero que se manda al mismo tiempo, por ejemplo un numero del 1 al 10 y yo haría que el Arduino 1 ejecute el código para abrir el solenoide si recibe un 1, el 2 si recibe un 2, etc..

2º- Direccionar de alguna forma cual es cada uno y mandarles constantemente un 0 o un 1 para que actúen o dejen de actuar sobre el solenoide.

Problemas:

1º- No consigo establecer conexión entre un Arduino MEGA2560 y un Arduino UNO utilizando modbus (si por serial) con el adaptador MAX485(ttl to rs484) y no logro encontrar un ejemplo de esta situación comunicando varios arduinos.

PD: No he entendido bien lo que me has dicho de asignar otros pines que no sean TX y RX, según los esquemas que he visto sobre la placa DI va conectado a TX y RO a RX para transformar la comunicación serial a RS485, y RE y DE deben alimentarse con HIGH para emisor y GND para receptor por lo que supongo que A5 y A6 son los que usa la librería para cambiar el estado de emisor a receptor. Al final mi conclusión es que tienes razón, esa librería esta hecha para los MKR1XXX y no me da buenos resultados.

igualmente, ¿Cómo podría cambiar la librería para probar si asignando bien los pines me sirve?

PD2: Respecto al comentario que me has hecho sobre

Serial.print("Failed to write coil! ");

la verdad que no se si seria un problema, ese código no es mío, ambos tanto emisor como receptor son los ejemplos que traía la librería en ejemplos.

Sigo con mi búsqueda pero me vendría genial que me pasasen algún ejemplo similar resuelto con éxito porque por el momento no he logrado encontrar ninguno que me sirva o alguna librería adecuada a los MAX485 o alguna que me sirviese para configurar los arduino UNO como receptores porque las que he ido probando no me dan buenos resultados.

Adjunto esquema de cableado de las placas MAX485 (el arduino Mega conectado como emisor, el arduino UNO conectado como receptor y las placas conectadas entre si A-A y B-B) y imagen de los dispositivos que he utilizado para realizar las pruebas que he mencionado.

Edito: No me deja subir la imagen que hice con el telefono de los aparatos.

Edito2: Me he dado cuenta de que todo el rato me estoy refiriendo a modbus lo cual implica tener registros prediseñados donde mandar o leer los datos y creo que esta un poco desacertado, lo que necesito es una comunicacion basica RS485 donde simplemente pueda mandar un valor a los distintos arduino UNO para que actuen en su codigo teniendo como condicion ese valor que les llega.
Captura.PNG

Captura.PNG

1º- No encuentro forma de cambiar la dirección asignada a la placa de relés para utilizar varias de estas.

Dices que compraste un Relay Board-4 V1.2 pero no termino de entender si la manejas con un arduino o tiene su propio controlador modbus.
Para evitar malos entendidos porque no pones un enlace a la placa que has comprado? Siempre ayúdanos a entender lo que estas usando porque en general las personas creen que todos tenemos conocimiento de la inmesidad de placas y variantes que existen.
Un enlace debidamente posteado alcanza.

  1. Con el objeto node estas vinculando a tu master y al esclavo id 1 solamente.
    No hay referencia a otro nodo con otro Id.
    Asi que no hay posibilidad de que confundas ordenes.
    Necesitarás un objeto llamado node1 ... node 4 para cubrir 4 esclavos por ejemplo.
    Tendras que inicializarlos del mismo modo y hacer el código que corresponda a cada uno.
    En el código que veo hay cosas que no me gusta y ya te las haré saber. No es que el código este mal sino que no es poco eficiente ya que envia demasiada información por el bus 485 haciendo que se complique el flujo de datos.

  2. Usar otros arduinos como esclavos y módulos reles simples siempre es una buena alternativa porque ademas te deja abierto el uso del mismo arduino para leer y compartir cosas.

3.1

1º- Que todos reciban el numero que se manda al mismo tiempo, por ejemplo un numero del 1 al 10 y yo haría que el Arduino 1 ejecute el código para abrir el solenoide si recibe un 1, el 2 si recibe un 2, etc..

Existe un modo en Modbus llamado brodcasting en el que el master le escribe a todos los esclavos pero solo es de ida. No existe retorno de parte de los esclavos. Por supuesto que no puede haber respuesta de los esclavos porque habría colisiones, es decir, como se priorizaria una respuesta de un esclavo frente a otro? es imposible.

3.2

2º- Direccionar de alguna forma cual es cada uno y mandarles constantemente un 0 o un 1 para que actúen o dejen de actuar sobre el solenoide.

En todo lo que propongas recuerda que no es conveniente enviar constantemente ordenes a RELES o válvulas. Lo correcto es enviar cambios de orden y nada mas. Hay un cambio, envío y luego no me comunico mas. Modbus advierte si el paquete no ha llegado asi que se sabe si se produce un error, pero no se sabe si la acción indicada se ha llevado o no acabo a menos que dispongas de un sensor que lo determine.

Luego continúo con mi respuesta atendiendo las consultas sobre los problemas que experimentas.

Buenos días, sigo avanzando en proyecto. De momento he conseguido hacer algo parecido a lo que intentaba desde un principio pero no estoy seguro de si será una solución real.

Antes de nada dejo aquí el link de la placa de Relé Modbus de la que hable anteriormente, aunque no acabase usándola en este proyecto seria interesante poder cambiarle la dirección para futuros proyectos.

"Existe un modo en Modbus llamado brodcasting en el que el master le escribe a todos los esclavos pero solo es de ida. No existe retorno de parte de los esclavos."

Respecto a eso, Realmente no necesito un retorno por parte de los esclavos, en caso de avería seguramente tampoco tendría las condiciones necesarias para recibir algún tipo de aviso como "fallo".
Actualmente tengo funcionando una maqueta de la siguiente forma:
Tengo instalados 1 arduino MEGA actuando como maestro y 2 arduinos UNO actuando como esclavos sobre 1 solenoide para abrir y cerrar.
Codigo MEGA:

void setup() 
{ 
  Serial.begin(9600);
   pinMode(2, INPUT_PULLUP);
   pinMode(3, INPUT_PULLUP);
   pinMode(4, INPUT_PULLUP);
   pinMode(5, INPUT_PULLUP);
   pinMode(6, INPUT_PULLUP);
   pinMode(7, INPUT_PULLUP);
   pinMode(8, INPUT_PULLUP);
   pinMode(9, INPUT_PULLUP);
   pinMode(10, INPUT_PULLUP);
   pinMode(11, INPUT_PULLUP);
   pinMode(12, INPUT_PULLUP);
   pinMode(13, INPUT_PULLUP);
} 
 
void loop() 
{ 
  int data; 

 if (digitalRead(2) == LOW) {
  data = 1;
  digitalWrite(LED_BUILTIN, HIGH);  
 }

  else {
    data = 11;
    digitalWrite(LED_BUILTIN, LOW);
  }

  Serial.write(data);
  delay(250);
  Serial.println(data); 

 if (digitalRead(3) == LOW) {
  data = 2;
  digitalWrite(LED_BUILTIN, HIGH);  
 }

  else {
    data = 12;
    digitalWrite(LED_BUILTIN, LOW);
  }
  
   Serial.write(data);
  delay(250);
  Serial.println(data); 

   if (digitalRead(4) == LOW) {
  data = 3;
  digitalWrite(LED_BUILTIN, HIGH);  
 }

  else {
    data = 13;
    digitalWrite(LED_BUILTIN, LOW);
  }
  
   Serial.write(data);
  delay(250);
  Serial.println(data);

   if (digitalRead(5) == LOW) {
  data = 4;
  digitalWrite(LED_BUILTIN, HIGH);  
 }

  else {
    data = 14;
    digitalWrite(LED_BUILTIN, LOW);
  }
  
   Serial.write(data);
  delay(250);
  Serial.println(data);

   if (digitalRead(6) == LOW) {
  data = 5;
  digitalWrite(LED_BUILTIN, HIGH);  
 }

  else {
    data = 15;
    digitalWrite(LED_BUILTIN, LOW);
  }
  
   Serial.write(data);
  delay(250);
  Serial.println(data);

   if (digitalRead(7) == LOW) {
  data = 6;
  digitalWrite(LED_BUILTIN, HIGH);  
 }

  else {
    data = 16;
    digitalWrite(LED_BUILTIN, LOW);
  }
  
   Serial.write(data);
  delay(250);
  Serial.println(data);

   if (digitalRead(8) == LOW) {
  data = 7;
  digitalWrite(LED_BUILTIN, HIGH);  
 }

  else {
    data = 17;
    digitalWrite(LED_BUILTIN, LOW);
  }
  
   Serial.write(data);
  delay(250);
  Serial.println(data);

 if (digitalRead(9) == LOW) {
  data = 8;
  digitalWrite(LED_BUILTIN, HIGH);  
 }

  else {
    data = 18;
    digitalWrite(LED_BUILTIN, LOW);
  }
  
   Serial.write(data);
  delay(250);
  Serial.println(data);

   if (digitalRead(10) == LOW) {
  data = 9;
  digitalWrite(LED_BUILTIN, HIGH);  
 }

  else {
    data = 19;
    digitalWrite(LED_BUILTIN, LOW);
  }
  
   Serial.write(data);
  delay(250);
  Serial.println(data);

   if (digitalRead(11) == LOW) {
  data = 10;
  digitalWrite(LED_BUILTIN, HIGH);  
 }

  else {
    data = 20;
    digitalWrite(LED_BUILTIN, LOW);
  }
  
   Serial.write(data);
  delay(250);
  Serial.println(data);

   if (digitalRead(12) == LOW) {
  data = 21;
  digitalWrite(LED_BUILTIN, HIGH);  
 }

  else {
    data = 31;
    digitalWrite(LED_BUILTIN, LOW);
  }
  
   Serial.write(data);
  delay(250);
  Serial.println(data);

   if (digitalRead(13) == LOW) {
  data = 22;
  digitalWrite(LED_BUILTIN, HIGH);  
 }

  else {
    data = 32;
    digitalWrite(LED_BUILTIN, LOW);
  }
  
   Serial.write(data);
  delay(250);
  Serial.println(data);
                           
}

Codigo arduino UNO:

int firstabrir = HIGH;
int firstcerrar = HIGH;

void setup() 
{ 
  Serial.begin(9600); 
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(2,OUTPUT);
  pinMode(4,OUTPUT);
} 
 
void loop() 
{  
  if (Serial.available()) 
  {
    int data = Serial.read(); 
    
 if (data == 1 and firstabrir == HIGH) {       //Posicion 1
    digitalWrite(2,HIGH);
    delay(65);
    digitalWrite(2,LOW);
    Serial.println("ABRIR");
    digitalWrite(LED_BUILTIN,HIGH);
    firstabrir = LOW;
    firstcerrar = HIGH;
  }

  
  if (data == 11 and firstcerrar == HIGH){   //Posicion 2
    digitalWrite(4,HIGH);
    delay(65);
    digitalWrite(4,LOW);
    Serial.println("CERRAR");
    digitalWrite(LED_BUILTIN,LOW);
    firstabrir = HIGH;
    firstcerrar = LOW;
  }
    Serial.println(data); 
  }


}

( el resto de arduinos esclavos conectados solo cambiarian el numero recibido en data para la condicion if )

Estan conectados a las placas MAX485 de la misma forma que en las imagenes de mi anterior post, ademas de que cada arduino esclavo tiene conectados 2 Relé para dar por uno orden de abrir y por otro orden de cerrar.

Ahora mis dudas son las siguientes:

1º- Se que en el código estoy utilizando "Serial.Write" pero los arduinos no se conectan entre ellos con TX y RX, si no con el A y B que salen de las placas TTL to RS485, entonces ¿Aunque utilice serial.Writte, realmente la comunicación es RS485? Lo digo porque la idea es que esta comunicación debe cubrir grandes distancias en el campo, ya he hecho proyectos similares con distancia utilizando modbus y no se si con este la distancia podría ser un problema.

2º- Seguramente el hecho de estar mandando constantemente la variable data cada 250ms no sea la mejor forma de optimizar el sistema, ¿ seria mejor crear una variable DATA para cada esclavo y solo enviarla cuando el arduino mega reciba la orden de mandar el dato sobre dicho esclavo ? cualquier forma de optimizar el codigo para que de los menos problemas posibles seria genial.

fernando_rb:
1º- Se que en el código estoy utilizando "Serial.Write" pero los arduinos no se conectan entre ellos con TX y RX, si no con el A y B que salen de las placas TTL to RS485, entonces ¿Aunque utilice serial.Writte, realmente la comunicación es RS485? Lo digo porque la idea es que esta comunicación debe cubrir grandes distancias en el campo, ya he hecho proyectos similares con distancia utilizando modbus y no se si con este la distancia podría ser un problema.

Estas intercambiando información por RS485 en texto plano.
Tienes que diferenciar entre protocolo y bus. El Bus es el medio físico por el cual se transmite la información, en tu caso es RS485 . El protocolo es un conjunto de reglas para transmitir la información, tu estas intercambiando información sin ningún protocolo.
Respondiendo a la pregunta si podrás cubrir grande distancias sin ningún protocolo: Probablemente no, Modbus tiene verificación de información (CRC), es muy probable que se corrompa la información.

Buenos días, hice pruebas en el campo con una distancia de 1500m aproximadamente y el envió de datos efectivamente se corrompe.

Debido a esto vuelvo a retomar el tema de los relés modbus, actualmente estoy trabajando con unas tarjetas de expansión que tengo de 4ED/4SD y con el siguiente código funcionan perfectamente.

#include <ModbusMaster.h>    //utilizamos la libreria modbusmaster (añadir libreria en programa-añadir libreria).

#define MAX485_DE      2    //PIN utilizado para elegir modo receptor(LOW GND)/transmisor(HIGH VCC)


ModbusMaster node;  //Definir objeto maestro.

void preTransmission()
{


  digitalWrite(MAX485_DE, 1);
  delay(10);
}

void postTransmission()
{
  digitalWrite(MAX485_DE, 0);
  delay(10);
}

void setup()
{

  
  pinMode(MAX485_DE, OUTPUT);
  
  // iniciar en modo receptor
  digitalWrite(MAX485_DE, 0);

  // Iniciamos comunicacion modbus 9600 baud rate.
  Serial.begin(9600);

  // Iniciamos puesto modbus  ( ID del esclavo, puerto)
    node.begin(1, Serial);
  
  // Configuracion voids para pasar de receptor a transmisor
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
  
}

void loop()
{


//declalro variables para alojar la lectura.
int entrada1;
int entrada2;
int entrada3;
int entrada4;




//lecturas de entradas
int Mdelay = 15;   // microdelay
node.readDiscreteInputs(0x0, 1);       // node."funcion"(registro inicial, numero de registros)
Serial.print("[ENTRADA1] ");
entrada1 = node.getResponseBuffer(0);  //Igualamos el valor de la respuesta buffer a la variable entrada1
Serial.print(entrada1); 
delay(Mdelay);
node.clearResponseBuffer();            //limpiamos el valor del buffer para siguientes lecturas


Serial.print("  ");
node.readDiscreteInputs(0x1, 1);
Serial.print("[ENTRADA2] ");
entrada2 = (node.getResponseBuffer(0));
Serial.print(entrada2);
delay(Mdelay);
node.clearResponseBuffer();


Serial.print("  ");
node.readDiscreteInputs(0x2, 1); 
Serial.print("[ENTRADA3] ");
entrada3 = (node.getResponseBuffer(0));
Serial.print(entrada3);
delay(Mdelay);
node.clearResponseBuffer();


Serial.print("  ");  
node.readDiscreteInputs(0x3, 1); 
Serial.print("[ENTRADA4] ");
entrada4 = (node.getResponseBuffer(0));  
Serial.print(entrada4);
delay(Mdelay);
node.clearResponseBuffer();

Serial.print("  ");  

//escribir salidas al leer entradas


if ( entrada1 == 1 ) {
  node.writeSingleCoil(0x0, 1);  // node."funcion"(registro,valor a escribir)
  node.writeSingleCoil(0x3, 1);
   
}
else{
  node.writeSingleCoil(0x0, 0); 
  node.writeSingleCoil(0x3, 0);

}

if ( entrada2 == 1 ) {
  node.writeSingleCoil(0x1, 1);
    node.writeSingleCoil(0x2, 1);  
}
else{
  node.writeSingleCoil(0x1, 0);
  node.writeSingleCoil(0x2, 0);

}
  

}

El problema es que estas tarjetas tienen un coste bastante elevado, por lo que estoy intentando hacer lo mismo con placas de relés modbus para arduino.
He adquirido este modelo porque permite cambiar la dirección con los pines al igual que el otro tipo de tarjeta que utilizo.
No encuentro manuales de registros ni post relacionados con este tipo de placa, la poca información que tengo son las fotos del anuncio de amazon. ¿Alguna idea?

Gracias.

RS-485 Tips, Tricks, Questions & Answers

Q: What is the maximum connection distance using RS-485 devices?
A: The maximum distance of RS-485 without using a repeater is 4000 feet (1220 meters) at baud rates up to 90Kbps.
Extend that distance by adding an RS-485 Repeater or Optically Isolated Repeater every 4000 fe

1200 mts igualmente es una distancia dificil de alcanzar.
Entonces 1500m quedan fuera de discusión.

Considera en todo caso un retransmisor, receptor-transmisor con su fuente o considerar una alimentación especial, que para evitar la caida de tensión podría ser por lazo de corriente.

El manual esta indicado en una respuesta que el autor le da a un cliente.
Manual Relay Board

Ver Customer Question & Answers link

Por lo demás hacer lo mismo con arduino es mas o menos simple, un NANO para mi gusto, un módulo Relay del tamaño que gustes. Fuente de alimentación y módulo 485, programación y listo.

Buenos días, lo primero muchas gracias a todos y sobre todo a Surbyte, me estas ayudando muchísimo, no me di cuenta de que ahí se encontraba este manual, ha sido muy útil.

Utilizando el manual y el programa "modbus Poll" utilizo todas las funciones mandando las tramas que vienen indicadas en el word. He intentado mandar ordenes a los mismos registros con la libreria modbusMaster pero no hay manera, posiblemente porque esta mande las tramas de distinta forma o algo por el estilo.

Estoy utilizando el siguiente código:

#include <ModbusMaster.h>    //utilizamos la libreria modbusmaster (añadir libreria en programa-añadir libreria).

#define MAX485_DE      2    //PIN utilizado para elegir modo receptor(LOW GND)/transmisor(HIGH VCC)


ModbusMaster node;  //Definir objeto maestro.

void preTransmission()
{


  digitalWrite(MAX485_DE, 1);
  delay(10);
}

void postTransmission()
{
  digitalWrite(MAX485_DE, 0);
  delay(10);
}

void setup()
{

  
  pinMode(MAX485_DE, OUTPUT);
  
  // iniciar en modo receptor
  digitalWrite(MAX485_DE, 0);

  // Iniciamos comunicacion modbus 9600 baud rate.
  Serial.begin(9600);

  // Iniciamos puesto modbus  ( ID del esclavo, puerto)
    node.begin(1, Serial);
  
  // Configuracion voids para pasar de receptor a transmisor
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
  
}

void loop()
{
//escribir

  node.writeSingleRegister(0x0001, 0x01);  // node."funcion"(registro,valor a escribir)

  delay(3000);

  node.writeSingleRegister(0x0001, 0x02);

  delay(3000);


}

Básicamente dentro del loop estoy intentando mandar las tramas del manual, he probado a escribir la direccion y el valor de mil formas y nada.

Channel 1 Open :01 06 00 01 01 00 D9 9A
Channel 1 Close :01 06 00 01 02 00 D9 6A

Esta librería no te da mas opción que dirección del registro y valor a escribir, por lo que supongo que no será suficiente. ¿Existe forma de mandar las tramas escribiéndolas yo a mano de forma limpia como se hace con Modbus Poll ? o si no ¿Cómo configurar de forma correcta para mandar las tramas del manual?

De esta forma podría mandar la trama del word en el momento que mas me convenga y así solucionaría mi problema.

Adjunto imágenes de la configuración de modbus poll con la que consigo actuar de forma correcta y las tramas del manual de la tarjeta de relés.

3.PNG

3.PNG

Utilizando el manual y el programa "modbus Poll" utilizo todas las funciones mandando las tramas que vienen indicadas en el word. He intentado mandar ordenes a los mismos registros con la libreria modbusMaster pero no hay manera, posiblemente porque esta mande las tramas de distinta forma o algo por el estilo.

No he trabajado con esa librería, pero algunas implementaciones de modbus no se ponen de acuerdo si el 0 es el primer registro, intenta desplazar un registro hacia arriba o abajo.

Buenas, gracias por el aporte PeterKant, es cierto pero justo en esta placa parece que esta direccionada tal cual pone en su manual empezando desde el registro 1.

No se como, ni porque, pero me he cambiado de mesa para trabajar mas cómodo, lo he cargado de la siguiente forma y funciona!! xd (quizás algún cable con un mal contacto, no se)

#include <ModbusMaster.h>    //utilizamos la libreria modbusmaster (añadir libreria en programa-añadir libreria).

#define MAX485_DE      2    //PIN utilizado para elegir modo receptor(LOW GND)/transmisor(HIGH VCC)


ModbusMaster node;  //Definir objeto maestro.

void preTransmission()
{


  digitalWrite(MAX485_DE, 1);
  delay(10);
}

void postTransmission()
{
  digitalWrite(MAX485_DE, 0);
  delay(10);
}

void setup()
{

  
  pinMode(MAX485_DE, OUTPUT);
  
  // iniciar en modo receptor
  digitalWrite(MAX485_DE, 0);

  // Iniciamos comunicacion modbus 9600 baud rate.
  Serial.begin(9600);

  // Iniciamos puesto modbus  ( ID del esclavo, puerto)
    node.begin(1, Serial);
  
  // Configuracion voids para pasar de receptor a transmisor
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
  
}

void loop()
{
//escribir


  node.writeSingleRegister(0x1, 0x0100);  // node."funcion"(registro,valor a escribir)

   

  delay(3000);

  
  node.writeSingleRegister(0x1, 0x0200);


  delay(3000);

}

Estoy ya cerca de conseguirlo, he preparado un programa con varios esclavos para mañana realizar pruebas en campo para ver como actúan estas placas a largas distancias. Tengo encargados repetidores de rs485 por si al final fuesen necesarios.

Igualmente me da la sensación de que a veces el código va un poco ralentizado y eso que ahora mismo solo tengo 2 esclavos en el, la idea es poner entre 10 y 20 dependiendo de la instalación.

#include <ModbusMaster.h>    //utilizamos la libreria modbusmaster (añadir libreria en programa-añadir libreria).

#define MAX485_DE      2    //PIN utilizado para elegir modo receptor(LOW GND)/transmisor(HIGH VCC)

int firstabrir1 = HIGH;
int firstcerrar1 = HIGH;
int firstabrir2 = HIGH;
int firstcerrar2 = HIGH;

ModbusMaster node;  //Definir objeto maestro.

void preTransmission()
{


  digitalWrite(MAX485_DE, 1);
  delay(10);
}

void postTransmission()
{
  digitalWrite(MAX485_DE, 0);
  delay(10);
}

void setup()
{

  pinMode(4, INPUT_PULLUP); 
  pinMode(5, INPUT_PULLUP); 
  
  pinMode(MAX485_DE, OUTPUT);
  
  // iniciar en modo receptor
  digitalWrite(MAX485_DE, 0);

  // Iniciamos comunicacion modbus 9600 baud rate.
  Serial.begin(9600);

  
  
  // Configuracion voids para pasar de receptor a transmisor
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
  
}

void loop()
{
//escribir

 if (digitalRead(4) == LOW and firstabrir1 == HIGH) {

  Serial.println("Abrir 1");
 // Iniciamos puesto modbus  ( ID del esclavo, puerto)
  node.begin(1, Serial);  
  node.writeSingleRegister(0x1, 0x0600);  // node."funcion"(registro,valor a escribir)

  firstabrir1 = LOW;
  firstcerrar1 = HIGH;
  delay(250);

}

 if (digitalRead(4) == HIGH and firstcerrar1 == HIGH) {
 
 
  Serial.println("Cerrar 1");
 // Iniciamos puesto modbus  ( ID del esclavo, puerto)
  node.begin(1, Serial);
  node.writeSingleRegister(0x2, 0x0600);
  
  firstabrir1 = HIGH;
  firstcerrar1 = LOW;
  delay(250);
}

 if (digitalRead(5) == LOW and firstabrir2 == HIGH) {

  Serial.println("Abrir 2");
 // Iniciamos puesto modbus  ( ID del esclavo, puerto)
  node.begin(2, Serial);  
  node.writeSingleRegister(0x1, 0x0600);  // node."funcion"(registro,valor a escribir)

  firstabrir2 = LOW;
  firstcerrar2 = HIGH;
  delay(250);

}

 if (digitalRead(5) == HIGH and firstcerrar2 == HIGH) {
 
 
  Serial.println("Cerrar 2");
 // Iniciamos puesto modbus  ( ID del esclavo, puerto)
  node.begin(2, Serial);
  node.writeSingleRegister(0x2, 0x0600);
  
  firstabrir2 = HIGH;
  firstcerrar2 = LOW;
  delay(250);
}

}

Mis conocimientos no son muy amplios así que acepta cualquier consejo para optimizar el código y que no se ralentice, un saludo.

Mi consejo es que logres un buen funcionamiento en las condiciones controladas de tu taller/laboratorio.
Sigue trabajando para evitar situaciones ralentizadas porque eso te va a generar mas dudas cuando se presenten otros problemas debido a la distancia si es que ocurren.

Recuerdo que si algo resulta tedioso es hacer coinicidir las direcciones de un manual con un programa. Como te dice @PeterKanTropus lo de sumar o restar 1. Hay situaciones enlas que debes considerar 4000 o 40000 como me pasa con un PLC muy especial. Le debo agregar 40000 y 1 o sea la direccion 0 es 0x40001
En otros casos era 0x4001 y luego cambiaron de modelo y tmb tuve que adaptar esto que te comento.
Todo desde Modbus Poll asi que ya ves.
Te puedes romper la cabeza y no darás nunca con la dirección.
Cuando encuentras eso todo funciona de maravillas y no hay retrasos ni cosas raras.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.