Go Down

Topic: Help with ModBus RTU Master-Slave: SimpleModbus [SOLVED] (Read 259392 times) previous topic - next topic

JuanB

Awesome!

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

JUGmobile

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:
Code: [Select]
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:
Code: [Select]
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:
Code: [Select]
void modbus_configure(long baud,
unsigned char byteFormat,
unsigned int _timeout,
unsigned int _polling,
                                *****
                                ***
                                *

to this:
Code: [Select]
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

JUGmobile

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.

JuanB

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


JUGmobile

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.

JuanB

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.
9. The only bad questions are no questions and then... frustration and smoke ;-)

JUGmobile

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) :) 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.

JuanB

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


JUGmobile

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.

JuanB


meetjeremy

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.
Gabriel Jeremy Jeldo
meetjeremy@gmail.com

JuanB

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..

meetjeremy

#28
Aug 23, 2013, 06:28 pm Last Edit: Aug 23, 2013, 06:46 pm by meetjeremy Reason: 1
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
Gabriel Jeremy Jeldo
meetjeremy@gmail.com

meetjeremy

#29
Aug 23, 2013, 06:42 pm Last Edit: Aug 23, 2013, 06:44 pm by meetjeremy Reason: 1
This is my code which i have burned inside arduino

Code: [Select]
#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);
}
Gabriel Jeremy Jeldo
meetjeremy@gmail.com

Go Up