Help with ModBus RTU Master-Slave: SimpleModbus [SOLVED]

Successfully established connection between Leonardo (as Master) and Due (as Slave) with example code provided with libraries. BAS70 schottky diode is working perfectly well!

But somekind, I can not establish connection between Due (as Master) and Leonardo (as Slave). I'll try to research this problem soon.

Updated SimpleModbusMaster to V10. It now supports function 1, 2 and 15 with broadcasting also on 15. I have also altered the modbus_configure() method to allow the selection of different Serial instances (hardware serial ports).

I must say I have helped allot of users with the hardware side of the modbus protocol so here is a list of pre-flight checks:

  1. 120ohm termination resistors on either end of the bus line.
  2. 680ohm pull up and pull down resistors on bus line. Usually half way on the bus line depending on your layout.
    Using a MAX487 which has a quarter unit load (48k vs standard 12k) the pull up and down resistor combination can theoretically drive 48 nodes.
    Any voltage between -200mV and 200mV is not defined.
  3. 10k pull up resistor from the Rx line (MAX487 driver pin DI) to Vcc.
  4. Make sure the slave supports the correct function.
  5. Make sure about the correct address.
  6. Both master and slave driver ic's must run on the same voltage usually 5V.
  7. If the slave is not responding initially try increasing the timeout and polling values. You can also increase the retry count to help in debugging initially.
    Writing (Function 16) usually takes longer than reading.
  8. Use 2x twisted pair cable with shield on long distance communication where possible. The one pair you use for communication and the other either for 0V
    or 0V and Vcc supply.
    Contrary to popular believe RS485 is a 3 wire topology. You need a common reference (0V).
  9. Connect a 100ohm 0.5W resistor in series between each node’s 0V and the bus line 0V to avoid excessive unbalanced current draw.
  10. The only bad questions are no questions and then... frustration and smoke :wink:

Great update, but library does not compile successfully on IDE 1.5.2 (hope arduino team make an update on that soon!). The problem is again parity and now the hardwareserial.h added too.

And I'm still trying to figure out why communication is only working when Leonardo is master and Due is slave and not in the opposite way (Due as master and Leonardo as slave). I have checked all of your points from first to double nine (the very last one makes sense) :slight_smile: I have checked all points except 2nd (only about MAX487 part -> way too expensive). I do not know what can cause this problem. I'm still on example code provided with libraries and will be using them till I find a solution for problem.

So what is the problem: Hardware seems ok (or maybe not, again!), since everything works fine when Leo as master and Due as slave. But when Due is master and send a message to Leonardo as slave, Leonardo does not respond to it. Leonardo does get the message (at least phisicaly), but TX on Leonardo just stays on 5V all the time. So master (due) continue sending messages to the slave, till retry_count counts to deifined nr.

Hi Jakob,

You are not alone with this kind of problem, take a look at these threads:

http://forum.arduino.cc/index.php?topic=151014.0

http://forum.arduino.cc/index.php?topic=153928.0

Well this was genius! Exactly the solution I needed. I added a delay function of 3ms immediately after Serial.flush command in master library and now it works like a charm. I'm still not fully satisfied with this solution (delay command) so I will research this problem a bit more.

JuanB, I don't know how to thank you for all your help.

No problem Jakob, glad I could be of help :wink:

Hi,
I'm newbie to arduino.

I'm having a modbus enabled meter which has kWh value in register 286. I have a python code to read the register the meter and i know the packet formatting also.

Can you please guide me how to read the register from this meter using arduino.

I have arduino Leonardo.

I tried simple modbus library with RS-485 chip from Maxim MAX485.

My connections, i followed from this post : http://aglasspool.wordpress.com/2010/03/23/arduino-heatmiser-via-rs485/

But used simple modbus to read data.

I get some strange characters after i start the program. And the com light on the meter also doesn't blink.

Can you please help me..

Thanks in advance.

Follow the connection on the simpleModbus site. Use V10. Make sure you use a 10k pull up indicated on the drawing. What type of meter is it? I will help you with the code..

Thanks for the reply.

I'm using different meters.
The one i'm reading is Fineco Meters from china. they provide only kWh which is register 286 and no. of words to read is 2

I've ElMeasure meter also LG119. Address map : http://www.elmeasure.com/downloads/mod_lgplus.pdf
In elmeasure it says register 40159 but from my python code im reading address as 158 to get Wh reading instead of 40158 and no. of words to read is 2

Schneider SmartLink ACTI 9. Address Map : http://download.schneider-electric.com/files?p_File_Id=44883058&p_File_Name=DOCA0004EN-03.pdf
Pg. 60
I'm reading register 14204 and 14208 from my python code to get kW and kWh and no. of words to read is 4 for each address.
Schneider adjusts the baud rate itself, no need to wirte.

Now from my computer i'm reading via serial configuration 9600, 8E1

I need to read the values from arduino leonardo. I've ordered this breakout board for better operation http://www.ebay.com/itm/271200250359?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l2649

This is my code which i have burned inside arduino

#include <SimpleModbusMaster.h>
#define baud 9600
#define timeout 1000
#define polling 2 
#define retry_count 50

#define TxEnablePin 2 
#define LED 13

enum
{
  PACKET1,
  TOTAL_NO_OF_PACKETS,
};

Packet packets[TOTAL_NO_OF_PACKETS];
packetPointer packet1 = &packets[PACKET1];
unsigned int readRegs[4];
void setup()
{
  /// Schneider Modbus Slave Id 1 and start register 14204 and length 4
  modbus_construct(packet1, 1, READ_HOLDING_REGISTERS, 14204, 4, readRegs); 
  ///// Starting serial for Leonardo
  Serial.begin(9600);
  while (!Serial) { ; }
  
  modbus_configure(&Serial1, baud, SERIAL_8E1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS);
  pinMode(LED, OUTPUT);
}

void loop()
{
  modbus_update();
  
  if (Serial1.available()){
    /// Write the received data from Serial 1 to Serial
    Serial.write(Serial1.read());
    delay(1000);
  }
  analogWrite(LED, readRegs[0]>>2);
}

On the Leo you can only use the Serial1 object. Although you have done this you cannot access the Serial1 object methods as this will conflict with the library. The information should be stored in the array you initialized the packet to, in this case readRegs[4]. This array contains the unsigned int values read from the slave. Since modbus only specifies unit16 values you will have to read 2 registers per float value. You will need to shift the two consecutive unsigned integers together to form the float32 value. You can then use Serial (USB) to transmit the two registers to the PC.

So the readRegs[4] contains the 4 words read from the slave.
readRegs[0] 1st word
readRegs[1] 2nd word
readRegs[2] 3rd word
readRegs[3] 4th word

Actually i want to read the registers and store the data on SD Card.
Arduino will read the data periodically and update the file by over writing the entries in the file.
The file will act as a sort of database.
As of now just for debugging i am printing the output to Serial1.

Yes, readRegs[] contains the requested registers information.

According to the arduino product page you must use Serial for USB transmission and Serial1 for UART (modbus) on the Leo.

Hello,

I tried with the schematics from simple modbus. Didn't Work.

Tried a breakout board for RS-485. Didn't work.

Serial port hangs never enters the if condition where it checks if hardware serial is available using breakout board.

Reading output of hardware serial. Giving junk values without even connecting wires.

Please help. Thanks

Hi meetjeremy,

Again, you can not access the Serial1's objects methods directly. You must transmit the contents of readRegs[] using Serial.

If you see the third attachment in my previous post. I have done that.

Still no output :frowning:

The third attachment still uses Serail1.available() and the other one uses Serial1.read(). This wont work.

Use Serial.println(readRegs[]) or something similar like you already did to transmit the received values from Serial1 (the modbus connection). Again you cannot use Serial1.available() since it will most of the time be empty depending when you read it. The library reads the received information and stores it in the assigned register array, in this case readRegs[]. This is the only way of interfacing with the information received.

If you want to know if the request packet is successful than access the packets following information counters like this:
packet1->requests;
packet1->successful_requests;
packet1->failed_requests;
packet1->exception_errors;

Also try not to use delay() with values larger than 100ms. It will affect the polling and timeout values.

If you want to periodically send the received information from readRegs[] to Serial (USB) than rather use millis() in a timely manner or check if the value linked to the regdRegs[] index has changed.

Hello JuanB,

Thanks for the reply.

I printed this

void loop()
{
  modbus_update();
  //if (Serial1.available()){
    /// Write the received data from Serial 1 to Serial
    //Serial.println(Serial1.read());
    //Serial.println(readRegs[]);
    Serial.println(packet1->requests);
    Serial.println(packet1->successful_requests);
    Serial.println(packet1->failed_requests);
    Serial.println(packet1->exception_errors);
    //Serial.println(readRegs[1]);
  //}
  analogWrite(LED, readRegs[0]>>2);
}

but i'm getting

50
0
50
0

that is requests made 50 but all failed requests.

Even the comm. light on the meter is not blinking.

Hi meetjeremy, since the information is scattered could you please mail me your complete sketch to bester.juan@gmail.com.

Maybe I have asked this but did you connect the driver ic (or break out board) according to the RS485 connection schematic on the SimpleModbus site?

What arduino are you using?

Hello JaunB,

Thanks for the reply.

I'm using Leonardo for this project.

Yes i have connected the circuit according to the schematics.

I have sent you the code in your mail.