Modbus Serial Master Jamodi
Hello guys!I'm working on an arduino project that require bulletproof communication between few arduinos (up to 30 or more, up to 100m) in disruptive environment (like near frequency inverter). I have one master device, that is communicating with few slaves. The master can send information-data, to the slaves, or read info-data from them. In project each slave will have few pushbuttons and an display (7-segment or graphic display). When the pushbutton is pressed on slave, the information of that pushbutton has to be transmited to the master. Also master device can send information to the slaves, so slaves can change information on display. Display will show only numbers and maybe few signs.
That's about it.My main goals are:. Bulletproof communication. Real time response. Low price. No delays for main codeReal time in my case means up to 1sec to address all slaves and get response from them.For the communication standard I choosed RS485, which is the best option for my project, I suppose, and have few advantages over CAN, SPI, Ethernet, I2C. On top of that I need a protocol for communication. There is a lot of libraries on the web for arduino that implement RS485 communication into arduino.
I'm a little afraid, that these libraries aren't really bulletproof + many of them uses delay function that is not helpful at all for my main code. After some time investigating communication between arduinos I decided to stick with the ModBus protocol.
Since ModBus is a little complicated for me and my knowledge I'm asking here for help.I'm still at the begining phase of programming this. I have found a ModBus library for arduino, called SimpleModbus, that contains master and slave example code. The whole library project can be found here:.For my master device I choose, and for the slaves.
For RS485 transceiver I choose SN65HVD75D from Texas Instruments, which is working at 3.3V, just like DUE and Leonardo. Current configurationFor the beginning I'm trying to establish communication only between master and one slave device. I haven't connect all the pushbuttons and displays, because firstly I want succesfully establish communication betwen arduinos using ModBus protocol. The hardware is the easiest part of design. Just arduino board, few ICs, breadboard and some wires. The hardware part is working flawlessly (for now ).So I have connected everything and now I'm stuck with programming.
I will go trough most parts of the code and will try to explain what I do understand and what I do not. All the code and libraries are available here:MASTER: SimpleModbusMasterExample.
Code:#include #define baud 9600#define timeout 1000#define polling 200 // the scan rate// If the packets internal retry register matches// the set retry count then communication is stopped// on that packet. To re-enable the packet you must// set the 'connection' variable to true.#define retrycount 5// used to toggle the receive/transmit pin on the driver#define TxEnablePin 2Few lines of code that defines some parameters. Timeout is time in ms that defines how much is max. Time for master to wait, till slave responds. If slave wouldn't respond, master would call next slave.Polling defines how fast will master call slaves (but I don't know what exactly nr.
200 means).Retrycount is counter, that defines max. Of unsuccessful tryes of calling one slave. If slave don't respond 5 times in row, the master will stop calling him.TxEnablePin is just a digital output for /RE-DE pins on RS485 transmitter that defines direction (transmit or receive data). Code:// Create an array of Packets to be configuredPacket packetsTOTALNOOFPACKETS;// Create a packetPointer to access each packet// individually. This is not required you can access// the array explicitly. PacketsPACKET1.id = 2;// This does become tedious though.packetPointer packet1 = &packetsPACKET1;packetPointer packet2 = &packetsPACKET2;// The data from the PLC will be stored in the regs arrayunsigned int regs10;Packet pack.
Is an array of packets. With line packets1 = 0; I probably write a zero value to the PACKET2. I'm not sure if I'm correct?packetPointer is just an pointer that points to the corresponding packet.regs10 array is, well I don't know what. Hi Jakob,The library is written following a state machine principal. There are 3 states running in the back ground (not at the same time obviously).
Calling modbusupdate checks the 3 states and thus calling this function frequently in your code will result in a quicker turnaround.To communicate with a slave you will need to establish the id, the function you want to use (reading or writing, function 3 or 16), the starting address you want to read from and the amount of registers you want to read.The packets you create with the enum instructions are just the index number you will use to explicitly refer to that specific packet. The TOTALNUMBEROFPACKETS is the number amount for the array of packets namely. Code: // Create a packetPointer to access each packet// individually. This is not required you can access// the array explicitly. PacketsPACKET1.id = 2;// This does become tedious though.packetPointer packet1 = &packetsPACKET1;The regs array is any named unsigned int array. This is the array that will contain the slaves response information you requested (when using function 3) or it could be the array of data you would want to write to the slave. These arrays can be different arrays when assigning them to a packet.
You could use 20 different arrays on 20 different packets.modbusconstuct is a function that does the assigning of packet information for you so you don't have to use pointer notation when putting together a packet.P.s. The master and slave examples in the library folder were not design to communicate with each other.
The SimpleModbusMaster example I used to communicate with an LSIS GM7 plc and the SimpleModbusSlave example was the slave to the GM7 plc and various other testing software.Some more info I extracted from an email I sent to a fellow arduinist:The library works on a state machine principal. The state machine is updated every call to modbusupdate. Frequent calls in a large program is better. The SM has 3 states 2 of which is timing related. One is the timeout delay which allows the slave to respond within a certain amount of time and the other one is the turn around delay which is basically the polling rate of each packet. The timeout delay needs to be as long as the slowest anticipated response of a slave. As the amount of slaves increase the turn around delay can be decreased since more slaves equal more latency in response.
The turn around delay is what I call 'a breather delay'. For example, if you have one slave and you poll it it takes 100ms to respond, as soon as your master detects a successful response it will poll the slave again but the slave has not yet returned to its 'listening state' which results in a non response which in turn will result in a timeout error. In this instance I would set the timeout to 300-500ms and the polling delay to 100ms. In general modbus is not a fast protocol and few commercial slaves respond so quickly. I have found that 500-1000ms timeout works the best and depending on the distance and amount of slaves a polling delay of 100-200ms.Let me know if you need any other help. With this examples everything become so clear.
It is actually simpler to communicate over this modbus protocol than I thought (thanks to you and your libraray). But I still haven't establish communication between my DUE and Leonardo.
Modbus Serial Master Jamodi System
Modbus Serial Master Jamodi Download
I had to changed my hardware part a little since I figured out that Leonardo is working on 5V logic not 3.3V (don't know why I thought Leonardo is on 3.3V logic). So now hardware part is working, and one more thing I had to change, I hope I did it correct:Since Arduino IDE 1.5.2 (which is neccessary for DUE) do not support different parity and stop bits options, I had to make a little changes in libraries. So this is what I changed so far:Master libraries SimpleModbusMaster.cppIn modbusconfigure I have deleted byteFormat, from this.
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 retrycount 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 master5) master gets answer (physical, measured with oscilloscope)6) master do not process slave answerAfter 5 requests (10 actually: PRESETMULTIPLEREGISTERS - 5 times and READHOLDINGREGISTERS - 5 times), master stops sending request to slave, due to retrycount which is set to 5.
If I set retry count to 5000000, it still stops sending requests.What can be wrong? Oscilloscope settings:Time - 5ms/divRX channel - 2V/divTX channel - 2V/divFrom 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!