Arduino como cliente Modbus con MAX485 no obtiene ninguna respuesta

Tengo algunos problemas al intentar consultar un servidor Modbus con un Arduino a través de RS485.

Ya logré consultar un servidor Modbus de software que se ejecuta en mi PC a través del puerto USB/COM usando la biblioteca ModbusMaster , por lo tanto, no debería ser un problema de software.

Leí sobre TTL y conversiones de nivel y puse un circuito como este en una placa de prueba:

ingrese la descripción de la imagen aquí

Usando el mismo firmware/boceto que funcionó para el servidor de software, conecté el pin TX y RX de Arduino al max485 y A y B al servidor Modbus y emití varias solicitudes.

Puedo ver las señales convertidas por el MAX485 (CPA1114) a través del osciloscopio y parece estar bien. El LED del servidor Modbus se enciende cuando detecta una transacción Modbus. Aún así, lo que leo como resultado de la solicitud es siempre 0xE0(identificación de servidor no válida) o 0xE2(tiempo de espera).

Pregunté al servidor con la misma solicitud igual usando otra herramienta (un convertidor RS485/USB y un escáner CAS Modbus), y da los resultados esperados, es decir, datos 0x01.

Este es el código que estoy ejecutando en un Arduino Ethernet (con una pantalla para fines de depuración):

#include <ModbusMaster.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 4, 5, 6, 7);

ModbusMaster node(1);

void setup() {

  pinMode(3, OUTPUT);
  node.begin(19200);
  lcd.begin(16, 2);

}

void loop() {

  uint16_t m_startAddress=1;
  uint8_t m_length=1;
  uint8_t result;

  digitalWrite(3, HIGH); // TX
  result = node.readHoldingRegisters(m_startAddress, m_length);

  lcd.clear();

  if (result == node.ku8MBSuccess) {
    lcd.print("DATA:");
    digitalWrite(3, LOW); // RX
    for (uint8_t j = 0; j < m_length; j++) lcd.print( node.getResponseBuffer(j), HEX );
  } else {
    lcd.print("ERR ");
    lcd.print(result, HEX);
  }
  
  delay(500);
  
}

Estas son las señales de solicitud emitidas por Arduino, que siempre fallan en obtener una respuesta de datos, y la otra herramienta, que siempre tiene éxito:

Señal de solicitud de Arduino
Señal de solicitud de Arduino

Convertidor de señal USB/RS485
Convertidor de señal USB/RS485

Superposición de las dos señales.
Superposición de las dos señales.

¿Hay algún problema con la señal de solicitud? ¿Estoy cometiendo algún error en el circuito o en el código?

Cualquier sugerencia sería muy apreciada.


Como sugirió Kvegaoro, lo hice funcionar editando la biblioteca ModbusMaster para cambiar el pin D3 al estado correcto en el momento correcto. Para ello utilicé un código que encontré en este post (italiano) en el foro de Arduino.

Esta es la edición que hice en ModbusMaster.cpp, function ModbusMasterTransaction, comenzando en la línea 746:

  // code edited to work with MAX485:
  // transmit request
  UCSR0A=UCSR0A |(1 << TXC0);  
  Serial.flush();
  digitalWrite(3, HIGH);

  for (i = 0; i < u8ModbusADUSize; i++)
  {
#if defined(ARDUINO) && ARDUINO >= 100
    MBSerial.write(u8ModbusADU[i]);
#else
    MBSerial.print(u8ModbusADU[i], BYTE);
#endif
  }
  while (!(UCSR0A & (1 << TXC0)));
  digitalWrite(3, LOW);
  // --
  
  u8ModbusADUSize = 0;

Tenga en cuenta que el pin D3 está codificado en la biblioteca, por lo que este no es un buen diseño, si alguien lo necesita, lo ajustaría mejor. ¡Aunque funciona!

Le sugiero que la biblioteca SimpleModbus para Arduino sea la elección perfecta code.google.com/p/simple-modbus
electronics.stackexchange.com/questions/49097/… Esta respuesta podría estar relacionada

Respuestas (3)

Creo que tiene un problema con su línea que maneja RE y DE porque configura la línea D3 alta para transmitir, luego emite una función modbus 3 (leer registros de espera). Después de esto, verifica si la solicitud fue exitosa y luego establece la línea D3 en un nivel bajo y lee la respuesta del búfer de la biblioteca del nodo. El problema es que una transacción modbus incluye que el maestro consulte al esclavo y que el esclavo responda, lo que parece ser atendido por la función node.readHoldingRegisters(), por lo tanto, el maestro que libera el bus RS485 debería ocurrir dentro de esta función, no después.
Lo que supongo que es el problema, es que la biblioteca modbus que usó está diseñada para RS232 como capa física, por lo tanto, es posible que deba modificar la biblioteca para que el bus RS485 se libere tan pronto como el maestro termine de enviar la consulta. Espero que esto ayude.

Gracias, voy a trabajar en la biblioteca de acuerdo a su sugerencia.
Estoy configurando su respuesta como aceptada porque identificó el problema y ahora lo hice funcionar al poner la lógica de conducción RE-DE en la función como sugirió. He editado la pregunta para incluir esta edición que he hecho.
Hice exactamente lo que hiciste. Todavía estoy enfrentando un error de tiempo de espera. En la PC puedo obtener la respuesta del esclavo pero no en arduino. Por favor dime que debo hacer? Mi esquema es como el tuyo, estoy usando MAX485 IC A va a '-' y B va a esclavos '+' He intentado intercambiar el AB tampoco funcionó. Estoy enviando el marco de datos 01 03 05 00 00 05 85 05 y no recibo respuesta. Probé un código básico para solucionar problemas, también falló. ¿Dónde debo agregar pinMode(3, OUTPUT) en el archivo de encabezado modbusmaster.cpp o en mi código en void setup(). Esperando su respuesta

¡Muchas gracias! Debe cambiar ModbusMaster.ccp de la siguiente manera:

  // flush receive buffer before transmitting request
  while (MBSerial->read() != -1);
  digitalWrite(22, HIGH); //mantuy
  // transmit request
  for (i = 0; i < u8ModbusADUSize; i++)
  {
#if defined(ARDUINO) && ARDUINO >= 100
    MBSerial->write(u8ModbusADU[i]);
#else
    MBSerial->print(u8ModbusADU[i], BYTE);
#endif
  }

  u8ModbusADUSize = 0;
  MBSerial->flush();    // flush transmit buffer

  delayMicroseconds(3650); //mantuy
  digitalWrite(22, LOW); //mantuy
  // loop until we run out of time or bytes, or an error occurs
  u32StartTime = millis();

Existe un breve intervalo, cuando el esclavo está en un estado de espera de respuesta y el maestro aún no está enviando, por lo que la línea está en un estado indefinido porque nadie la controla. Esto puede producir señales espurias no deseadas. Debe unir las líneas A y B a Vcc y Gnd con algunas resistencias de 1k. Esto forzará un estado definido, incluso si todos los nodos están inactivos (HiZ).