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

Well, I installed Arduino IDE 1.0.5 and try to establish connection with no success. Then I connect 2 Arduino Leonardos (so 1 Leonardo for master and 1 Leonardo for slave, instead of DUE for master) and get half of communication successful established. Then I tried to program Leonardos (master and slave) with IDE 1.5.2 and it is working the same way as with IDE 1.0.5.
Arduino IDE is not causing problems.

Looks like something is wrong on master (DUE) hardware part. I will try to figure this out but untill I find a solution, I will work with 2 Leonardos.

Here I am for now: I have changed libraries to work with Leonardo (Serial.xxx to Serial1.xxx) and IDE 1.5.2 (no parity and stop bits selection). I have successfuly establish connection in one way: Master->Slave. With potentiometer on master side I can regulate LED connected to PWM pin on slave side. Slave is responding to master request (watched on oscilloscope), but master somekind does not proccess informations that he gets. So I can not regulate LED on master side over potentiometer on slave side. Also master stops sending request to slave after 10 requests sended to slave (when retry_count is set to 5).

Problem is:

  1. master send request to slave,
  2. slave gets request (physical, measured with oscilloscope),
  3. slave process request,
  4. slave returns answer to master
  5. master gets answer (physical, measured with oscilloscope)
    6) master do not process slave answer

After 5 requests (10 actually: PRESET_MULTIPLE_REGISTERS - 5 times and READ_HOLDING_REGISTERS - 5 times), master stops sending request to slave, due to retry_count which is set to 5. If I set retry count to 5000000, it still stops sending requests.

What can be wrong?

Nothing new to show :frowning: I tried to use libraries with parity and stop bit options (no changes from original libraries), only thing I have changed is Serial.xxx to Serial1.xxx, so I can work with Leonardo (Leonardo for master and another Leonardo for slave).

Again same problem. Master can control slave, but cannot process answer from slave. Here is picture of communication from oscilloscope:

Oscilloscope settings:
Time - 5ms/div
RX channel - 2V/div
TX channel - 2V/div

From picture above we can see that answer from slave is a bit shorter than master request. I think this is all right, or maybe not? But anyway, this is what master gets as an answer from slave, but still does not react on this answer.

JuanB: on what hardware were you testing this library? I realy don't think that hardware can cause this problem, since master can control slave, but who knows.

And many thanks for all help!

Hi JUGmobile,
I tested the libraries on the Duemilanove. Imust admit I did not test the arduino master/slave examples with two Duemilanove's since individually they tested fine. Are you using 680Ohm pull up and pull down resistors?

Hi JuanB,
Well I haven't tryed with pull up/down resistors. Now I connected 680E: A line to Vcc and B line to ground and unfortunately it's still not working.

Have you got an option to test this library on 2 Arduinos? I don't know what can cause this problem, but hardware part looks ok, since everything looks normal when watching signals on osciloscope.

Thank you for your time!
Jakob

Hi Jakob,

I have another 328 lying around somewhere, I will hook it up on a bread board and connect them. Give me a few days...

In the mean time, try to remove a packet. Try just requesting a read function (F3) from the slave and see if you can get the LED to vary when turning the slave pot. Then use just F16 to request a write to the slave and see if the master pot varies the slave LED.

Use the two Read sketches together and the two Write sketches together.

SimpleModbusMasterArduinoRead.ino

#include <SimpleModbusMaster.h>

#define baud 9600
#define timeout 1000
#define polling 200 
#define retry_count 5
#define TxEnablePin 2 
#define LED 9

enum
{
  PACKET1,
  TOTAL_NO_OF_PACKETS 
};

Packet packets[TOTAL_NO_OF_PACKETS];
packetPointer packet1 = &packets[PACKET1];
unsigned int readRegs[1];

void setup()
{
  modbus_construct(packet1, 1, READ_HOLDING_REGISTERS, 0, 1, readRegs);
  modbus_configure(baud, SERIAL_8N2, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS);
  pinMode(LED, OUTPUT);
}

void loop()
{
  modbus_update();
  analogWrite(LED, readRegs[0]/4); 
}

SimpleModbusSlaveArduinoRead.ino

#include <SimpleModbusSlave.h>

#define  LED 9 

enum 
{     
  ADC_VAL,            
  HOLDING_REGS_SIZE 
};

unsigned int holdingRegs[HOLDING_REGS_SIZE];

void setup()
{
  modbus_configure(9600, SERIAL_8N2, 1, 2, HOLDING_REGS_SIZE, holdingRegs);    
  pinMode(LED, OUTPUT);
}

void loop()
{
  modbus_update();
  holdingRegs[ADC_VAL] = analogRead(A0); 
}

SimpleModbusMasterArduinoWrite.ino

#include <SimpleModbusMaster.h>

#define baud 9600
#define timeout 1000
#define polling 200 
#define retry_count 5
#define TxEnablePin 2 
#define LED 9

enum
{
  PACKET1,
  TOTAL_NO_OF_PACKETS
};

Packet packets[TOTAL_NO_OF_PACKETS];
packetPointer packet1 = &packets[PACKET1];
unsigned int writeRegs[1];

void setup()
{
  modbus_construct(packet1, 1, PRESET_MULTIPLE_REGISTERS, 0, 1, writeRegs);
  modbus_configure(baud, SERIAL_8N2, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS);
  pinMode(LED, OUTPUT);
}

void loop()
{
  modbus_update();
  writeRegs[0] = analogRead(A0);
}

SimpleModbusSlaveArduinoWrite.ino

#include <SimpleModbusSlave.h>

#define  LED 9 

enum 
{     
  PWM_VAL,        
  HOLDING_REGS_SIZE
};

unsigned int holdingRegs[HOLDING_REGS_SIZE]; 

void setup()
{
  modbus_configure(9600, SERIAL_8N2, 1, 2, HOLDING_REGS_SIZE, holdingRegs);    
  pinMode(LED, OUTPUT);
}

void loop()
{
  modbus_update();  
  analogWrite(LED, holdingRegs[PWM_VAL]/4); 
}

Jakob,

Try a 10k resistor pull-up on the Rx pin to Vcc. Another user has found that noise triggered the Rx receive interrupt on his driver ic.

More info,

The SimpleModbusMasterArduino and SimpleModbusSlaveArduino examples were tested by another arduinoist using a Mega as the master and a Micro as the slave with great success.

Now I can say hurray!

Looks like I had same problems as "another user". I connected 10kE resistor from RX on master side to VCC and now it's working flawlessly! Again thank you very much for all the help!

Have a nice day,
Jakob

Awesome!

Just to finalize for further reviewing of this thread; Does the example code work successfully using the Mega/Leonardo or/and Leo/Leo?

Well, few things need to be changed for Leonardo and for Due.
Leonardo as master:
In SimpleModbusMaster.cpp few lines of code needs to be changed. Since Leonardo uses Serial.xxx command for communicating over USB with computer, and Serial1.xxx for TX1/RX1 for communication with other arduinos (including this modbus protocol), the Serial.xxx needs to be changed to Serial1.xxx.

Leonardo as slave:
In SimpleModbusSlave.cpp few lines of code needs to be changed. Exactly the same solution. Serial.xxx needs to be changed to Serial1.xxx.

Due as master:
Due only works with IDE 1.5.x. IDE 1.5.x does not support different parity and stop bits configuration so few lines of code needs to be changed in SimpleModbusMaster.cpp from this:

void modbus_configure(long baud, 
                                unsigned char byteFormat,
                                unsigned int _timeout, 
                                unsigned int _polling, 
                                unsigned char _retry_count, 
                                unsigned char _TxEnablePin, 
                                Packet* _packets, 
                                unsigned int _total_no_of_packets)
{ 
   Serial.begin(baud, byteFormat);
   *****
   ***
   *

to this:

void modbus_configure(long baud, 
                                unsigned int _timeout, 
                                unsigned int _polling, 
                                unsigned char _retry_count, 
                                unsigned char _TxEnablePin, 
                                Packet* _packets, 
                                unsigned int _total_no_of_packets)
{ 
   Serial.begin(baud, byteFormat);
   *****
   ***
   *

and in SimpleModbusMaster.h from this:

void modbus_configure(long baud, 
				unsigned char byteFormat,
				unsigned int _timeout, 
				unsigned int _polling, 
                                *****
                                ***
                                *

to this:

void modbus_configure(long baud,
				unsigned int _timeout, 
				unsigned int _polling, 
                                *****
                                ***
                                *

And byteFormat also needs to be removed from example code.

Due as slave:
Exactly same issue with IDE 1.5.x: byteFormat needs to be removed from example code, SimpleModbusSlave.cpp and from SimpleModbusSlave.h. This also has to be done for programming any other arduino with IDE 1.5.x.

I haven't tested Due-Leonardo configuration yet, cause hardware incompatibility (Due is working with 3.3V logic and Leonardo with 5V), but I have found a perfect solution for that. You can easily use 5V RS485 transceivers with 3.3V logic microcontrollers with simple solution. Details can be found in following PDF document: How to interface a 5V Transceiver to a 3V Controller.

Leonardo-Leonardo configuration is working good with your libraries, but Master and Slave libraries has to be changed. I have not tested Mega-Leonardo configuration because I don't have any Mega board, but I think it should work fine (of course on leonardo side, libraries has to be changed).

Have a nice day,
Jakob

Amm and one another question: is there a possibility to tell something to all slaves at the same time? I mean Master say "Lets light the LED on pin 13" and all slaves instantly light the LED on pin 13.

Use id = 0 with function 16. This is used for broadcasting.

Superb, thank you!

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.