4
\$\begingroup\$

I'm having some troubles trying to query a Modbus server with an Arduino through RS485.

I've already succeeded in querying a software Modbus server running on my PC through the USB/COM port using the ModbusMaster libray, hence it shouldn't be a software issue.

I read about TTL and level conversions and I put on a circuit like this on a breadboard:

enter image description here

Using the same firmware/sketch that worked for the software server, I connected the Arduino pin TX and RX to the max485 and A and B to the Modbus server and I issued several requests.

I can see the signals converted by the MAX485 (CPA1114) though the oscilloscope and it seems to be right. The LED on the Modbus server lights on as it sees a Modbus transaction. Still, what I read as result of the request is always 0xE0 (invalid server id) or 0xE2 (timeout).

I queried the server with the same equal request using another tool (a RS485/USB converter and CAS Modbus Scanner), and it gives the expected results, that is data 0x01.

This is the code I'm running on an Arduino Ethernet (with a display for debug purpose):

#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);
  
}

These are the request signals emitted by the Arduino, that always fail to get a data response, and the other tool, that always succeed:

Arduino request signal
Arduino request signal

USB/RS485 converter signal
USB/RS485 converter signal

Overlap of the two signals
Overlap of the two signals

Is there something wrong with the request signal? Am I making any mistakes in the circuit or the code?

Any pointers would be greatly appreciated.


As suggested by Kvegaoro, I got it working by editing the ModbusMaster library in order to switch the D3 pin to the right status at the right moment. For doing so I used some code I found on this post (italian) in the Arduino forum.

This is the edit I've done in ModbusMaster.cpp, function ModbusMasterTransaction, starting at line 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;

Note that the D3 pin is then hard-coded in the library so this is not a good design, if someone is going to need this would adjust it better. It works though!

\$\endgroup\$
2

3 Answers 3

4
\$\begingroup\$

I think you have an issue with you line driving RE and DE because you set the D3 line high to transmit, then you issue a modbus function 3 (read holding registers). After this you check if the request was a success and after this you set the D3 line low and you read the response from the library buffer from the node. The issues stands that a modbus transaction includes the master querying the slave and the slave responding which seems to be taken care of by the node.readHoldingRegisters() fucntion therefore the master releasing the RS485 bus should happen within this fucntion not after it.
What I guess its the problem, its that the modbus library you used is intended for RS232 as the physical layer therefore you might have to modify the library so the RS485 bus is released as soon as the master completely finishes sending the query Hope this helps

\$\endgroup\$
3
  • \$\begingroup\$ Thank you, I'm going to work on the library according to your suggestion \$\endgroup\$
    – etuardu
    Nov 17, 2012 at 8:55
  • \$\begingroup\$ I'm setting your answer as accepted because it ideed identified the problem and now I got it working by putting the RE-DE driving logic into the function as you suggested. I've edited the question to include this edit I've done. \$\endgroup\$
    – etuardu
    Nov 17, 2012 at 10:52
  • \$\begingroup\$ I did exactly what you did. I am still facing time out error. On PC i am able to get slave's reply but not on arduino. Kindly tell me what should i do ? My schematic is like yours iam using MAX485 IC A goes to '-' and B goes to slaves '+' I have tried interchanging the A B too did'nt work out. I am sending the data frame 01 03 05 00 00 05 85 05 and receiving no reply response. I tried a basic code for trouble shooting it failed too. Where should i add pinMode(3, OUTPUT) in header file modbusmaster.cpp or in my code in void setup(). Waiting for your reply \$\endgroup\$
    – user23069
    Apr 25, 2013 at 19:05
1
\$\begingroup\$

Thank you very much! You should change in the ModbusMaster.ccp as below:

  // 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();
\$\endgroup\$
0
\$\begingroup\$

It exist a short interval, when the slave is in a response_waiting state and the master is not yet sending, so the line is in undefined state because nobody drives it.This may produce spurious unwanted signals. You must tie the A and B lines to Vcc and Gnd with some 1k resistors.This will force a defined state, even if all nodes are idle(HiZ).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.