Arduino como maestro modbus con MAX485 no recibe ninguna respuesta

2

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

Ya he logrado consultar un esclavo Modbus de software que se ejecuta en mi PC a través del puerto USB / COM usando el Libray de ModbusMaster , por lo tanto, no debería ser un problema de software.

Leí sobre TTL y las conversiones de nivel y coloco un circuito como este en una placa de pruebas:

Usandoelmismofirmware/esquemaquefuncionóparaelsoftwareesclavo,conectéelpinyelRXdearduinoalmax485yAyBalesclavomodbusyemitívariassolicitudes.

PuedoverlasseñalesconvertidasporelMAX485(CPA1114)atravésdelosciloscopioyparecesercorrecto.Elleddelesclavomodbusseenciendecuandoveunatransacciónmodbus.Sinembargo,loqueleícomoresultadodelasolicitudessiempre0xE0(iddeesclavonoválido)o0xE2(tiempodeespera).

Consultéalesclavoconlamismasolicitudutilizandootraherramienta(unconvertidorRS485/USByunescánerModbusCAS),ydalosresultadosesperados,esdecir,datos0x01.

EsteeselcódigoqueestoyejecutandoenunArduinoEthernet(conunapantallaparafinesdedepuración):

#include<ModbusMaster.h>#include<LiquidCrystal.h>LiquidCrystallcd(12,11,4,5,6,7);ModbusMasternode(1);voidsetup(){pinMode(3,OUTPUT);node.begin(19200);lcd.begin(16,2);}voidloop(){uint16_tm_startAddress=1;uint8_tm_length=1;uint8_tresult;digitalWrite(3,HIGH);//TXresult=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 el Arduino, que siempre fallan en obtener una respuesta de datos, y la otra herramienta, que siempre tiene éxito:


señaldesolicitudArduino


señal del convertidor USB / RS485


Superposicióndelasdosseñales

¿Hayalgúnproblemaconlaseñaldesolicitud?¿Estoycometiendoalgúnerrorenelcircuitooenelcódigo?

Cualquierpunteroseríamuyapreciado.

EDIT:

SegúnlosugeridoporKvegaoro,lohicefuncionareditandolabibliotecaModbusMasterparacambiarelpinD3alestadocorrectoenelmomentoadecuado.Parahacerlo,utilicéuncódigoqueencontréen esta publicación (italiano) en El foro de Arduino.

Esta es la edición que he hecho en ModbusMaster.cpp , función 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 no es un buen diseño. Si alguien lo necesita, lo ajustará mejor. ¡Aunque funciona!

    
pregunta etuardu

3 respuestas

3

Creo que tiene un problema con la conducción de línea RE y DE porque establece que la línea D3 es alta para transmitir, luego emite una función de modbus 3 (lea los registros de espera). Después de esto, verifica si la solicitud fue exitosa y, después de esto, estableció la línea D3 baja y leyó la respuesta del búfer de la biblioteca desde el nodo. El problema es que una transacción de modbus incluye al maestro que consulta al esclavo y al esclavo que responde, lo que parece estar a cargo de 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 de eso. > Creo que el problema es que la biblioteca de modbus que usaste está diseñada para RS232 como capa física, por lo tanto, es posible que tengas que modificar la biblioteca para que el bus RS485 se libere tan pronto como el maestro termine de enviar la consulta. Espero que esto ayude

    
respondido por el Kvegaoro
1

Muchas gracias! Debe cambiar en el ModbusMaster.ccp como se muestra a continuación:

  // 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();
    
respondido por el mantuy
0

Existe un breve intervalo, cuando el esclavo está en un estado de respuesta en espera y el maestro aún no está enviando, por lo que la línea está en estado indefinido porque nadie la maneja. Esto puede producir señales espurias no deseadas. Debe vincular 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).

    
respondido por el Iosif Szilagyi

Lea otras preguntas en las etiquetas