Hi everybody, I am an electronic engineer and I am working with official ArduinoModbus library on my project (this is the link: ArduinoModbus - Arduino Reference). I am having communication problems when I have multiple slave devices. The following happens to me:
If I execute 10 read/writes operations with the slave with id = 1, all 10 operations are successful, when I try to send a message to the slave with id = 2, I get a timeout error on the first message, and I can't write to this device with id = 2 until a long time elapses (I did the test with 5s), after I can communicate with the slave with id = 2, I can continue the communication, then, I have this timing problem again when I try to communicate with the slave with id 1. Specifically: when I am communicating with any slave, I successfully query every 200ms, when I try to communicate with a different slave, I have to wait a long time, I need to communicate quickly with several slaves, just as I do it with a single slave device, my system requirements don't allow for delays, I can't delay the system 5 seconds every time I switch devices, because I constantly need to survey several of them. One important note, I'm using Serial1.flush() after modbus instructions to make sure the serial transmission is finished, and I still have this timing problem.
I've been searching the forum for days, there are several people with the same problem but I can't find a solution.
If anybody has had the same problem and has a solution, please let me know. Thanks in advance and have a nice day
Please show how you do this - please insert the code
As @b707 already wrote, post your code!
What Arduino board are you using? The ArduinoModbus library isn't suited for the AVR line of Arduinos as it's quite wasteful with memory and the AVR Arduinos don't have that much memory.
Additionally that library doesn't implement the inter-message pause, the calling sketch has to do that but that's not documented. So you need a short delay between messages to conform to the standard. If you communicate only with one device it knows by parsing the message when a message starts and when it ends but the passive slaves must know when the next message starts and that's detected by this pause. It's defined to be at least 3.5 characters at the current speed. So at standard parameters this is 38500 / baudrate milliseconds (p.e. at 9600 baud this is roughly 4ms).
The 5 seconds you measured are probably just a random value when the synchronization got that bad that a pause was detected at the right bit/byte position.
//NOTE: I AM USING ARDUINO MEGA. MODBUS USES SERIAL3. I AM USING THE LIBRARY ArduinoModbus, YOU CAN FIND IT HERE:
//ArduinoModbus - Arduino Reference
//THANK YOU VERY MUCH FOR YOUR REPLY
//--------------------------------------------------------------------------------------------------
//CALLER CODE (I am calling a function inside modObj object, I put that function below this section)
//---------------------------------------------------------------------------------------------------
//SENDING DATA TO SLAVE WITH ID = 1
hReg16[12] = systemSettings.xTogglePol;
hReg16[14] = systemSettings.zTogglePol;
modObj.modbusWriteHregs16(1, 129, &hReg16[12], 4); //81H = 129 //this communication message is successful
hReg16[17] = systemSettings.veXIndexPulseDir;
hReg16[19] = systemSettings.veZIndexPulseDir;
modObj.modbusWriteHregs16(1, 134, &hReg16[17], 3); //this communication message is successful
hReg16[0] = systemSettings.xGearRatio;
hReg16[2] = systemSettings.zGearRatio;
hReg16[4] = systemSettings.xRapidSamples;
hReg16[6] = systemSettings.zRapidSamples;
systemSettings.minFeed = MINMLFREQ;
hReg16[8] = (systemSettings.xDrivePpr * systemSettings.xGearRatio * systemSettings.minFeed) / (60 * systemSettings.xPitchScrew); //X Feed Rate;
hReg16[10] = (systemSettings.zDrivePpr * systemSettings.zGearRatio * systemSettings.minFeed) / (60 * systemSettings.zPitchScrew); //Z Feed Rate;
hReg16[12] = systemSettings.xFeedSamples;
hReg16[14] = systemSettings.zFeedSamples;
modObj.modbusWriteHregs16(1, 1280, &hReg16[0], 15); //this communication message is successful
hReg16[0] = 0;
modObj.modbusWriteHregs16(1, 848, &hReg16[0], 1); //this communication message is successful
Serial3.flush(); //this is to guarantee end of serial port communication
//delay(5000); //If I remove this delay, I got timeout error when I try to communicate with slave ID = 3
//SENDING DATA TO SLAVE WITH ID = 3
hReg16[0] = 1;
modObj.modbusWriteHregs16(3, 0, &hReg16[0], 1); //this communication is successful just if I add a previous long delay
//From here the communication with the slave with id = 3 is successful,
//and I have the same timeout problem again when I communicate with the slave device with id = 1,
//the problem is only during the exchange of communication with the slaves
//-----------------------------------------------------------------------
//modbusWriteHregs16 function:
//-----------------------------------------------------------------------
void ModbusProgramming::modbusWriteHregs16(uint8_t slaveId, uint16_t offset, uint16_t *value, uint16_t numregs)
{
Serial.print(F("Writing Holding Registers values ... "));
if(ModbusRTUClient.beginTransmission((int)slaveId, HOLDING_REGISTERS, (int)offset, (int)numregs)){
for (int i = 0; i < (int)numregs; i++) {
ModbusRTUClient.write((unsigned int)value[i]);
}
if (ModbusRTUClient.endTransmission()) {
Serial.println(F("success"));
} else {
Serial.print(F("failed! "));
Serial.println(ModbusRTUClient.lastError());
}
} else {
Serial.print(F("failed! "));
Serial.println(ModbusRTUClient.lastError());
}
}
I have attached the code, I can't put the whole code because it is a huge system, I am just showing the problematic part. Please, review it when you have some time. Thank you very much
If you want it, I can do a simple system with basic communication test, just one master and 2 slaves, and post here the project (hardware and software), anyway the one I need is to solve the library issue, my project is too long to be posted here, I just need to solve the delay issue, and this can be done with a single project.
Read the forum guidelines to see how to properly post your code.
Please go back and fix your original post.
I have attached the code, I can't put the whole code because it is a huge system, I am just showing the problematic part. Please, review it when you have some time. Thank you very much
If you want it, I can do a simple system with basic communication test, just one master and 2 slaves, and post here the project (hardware and software), anyway the one I need is to solve the library issue, my project is too long to be posted here, I just need to solve the delay issue, and this can be done with a single project.
If your simple system clearly demonstrates the problem, then please post the code here instead of your "huge system".
Also, take note of the advice given in post #3.
As I already mentioned, that combination is not recommended. You will have memory problems too fast. You should consider changing the library to something more thrifty than ArduinoModbus with regard to memory, p.e. ModbusMaster.
As to your code: it's not complete code, the relevant parts are not posted and you didn't use code tags which makes it almost unreadable.
Create a minimal sketch that shows your problem and post that complete code. If the problem shows up only in your full code, post all code, you may attach it if it's size is that big.
Ok, thanks to every body, I am going to post here my sample code.
The idea is simple, try to get successful messages from serial port (You need to read Serial 0 debug messages). You will note that by removing comments from delay(5000) lines, all messages are successful, if you comment those delays, communication fails every time we change form slave 1 to slave 2 and vice versa
//MASTER PROGRAM
#include <ArduinoRS485.h> // ArduinoModbus depends on the ArduinoRS485 library
#include <ArduinoModbus.h>
void setup() {
Serial.begin(9600);
while (!Serial);
Serial.println("Modbus RTU Client");
// start the Modbus RTU client
if (!ModbusRTUClient.begin(9600)) {
Serial.println("Failed to start Modbus RTU Client!");
while (1);
}
}
void loop() {
for (int i = 0; i < 10; i++) {
Serial.print("Writing slave 1 ... ");
if(ModbusRTUClient.beginTransmission(1, HOLDING_REGISTERS, 0, 10)){
for (int i = 0; i < 10; i++) {
ModbusRTUClient.write(i);
}
if (ModbusRTUClient.endTransmission()) {
Serial.println(F("success"));
} else {
Serial.print(F("failed! "));
Serial.println(ModbusRTUClient.lastError());
}
} else {
Serial.print(F("failed! "));
Serial.println(ModbusRTUClient.lastError());
}
}
//delay(5000);
for (int i = 0; i < 10; i++) {
Serial.print("Writing slave 2 ... ");
if(ModbusRTUClient.beginTransmission(2, HOLDING_REGISTERS, 0, 10)){
for (int i = 0; i < 10; i++) {
ModbusRTUClient.write(i);
}
if (ModbusRTUClient.endTransmission()) {
Serial.println(F("success"));
} else {
Serial.print(F("failed! "));
Serial.println(ModbusRTUClient.lastError());
}
} else {
Serial.print(F("failed! "));
Serial.println(ModbusRTUClient.lastError());
}
}
//delay(5000);
}
//SLAVE 1 PROGRAM
#include <ArduinoRS485.h> // ArduinoModbus depends on the ArduinoRS485 library
#include <ArduinoModbus.h>
void setup() {
Serial.begin(9600);
Serial.println("Modbus RTU Server LED");
// start the Modbus RTU server, with (slave) id 1
if (!ModbusRTUServer.begin(1, 9600)) {
Serial.println("Failed to start Modbus RTU Server!");
while (1);
}
// configure a single holding reg at address 0x00
ModbusRTUServer.configureHoldingRegisters(0x00, 10);
}
void loop() {
// poll for Modbus RTU requests
ModbusRTUServer.poll();
}
//SLAVE2 PROGRAM
#include <ArduinoRS485.h> // ArduinoModbus depends on the ArduinoRS485 library
#include <ArduinoModbus.h>
void setup() {
Serial.begin(9600);
Serial.println("Modbus RTU Server LED");
// start the Modbus RTU server, with (slave) id 2
if (!ModbusRTUServer.begin(2, 9600)) {
Serial.println("Failed to start Modbus RTU Server!");
while (1);
}
// configure a single holding reg at address 0x00
ModbusRTUServer.configureHoldingRegisters(0x00, 10);
}
void loop() {
// poll for Modbus RTU requests
ModbusRTUServer.poll();
}
Have you only tried with 5000ms delay? Have you tried to pause for 5ms instead?
yes yes, even I have tested one second in my system, and it is not successful, anyway this application doesn't allow any delay, I need it as fast as possible
That pause is not optional, it's mandatory!
Have you tried 5ms or just 5s and 1s?
Doing tests, the most that I have been able to reduce the delay is 2 seconds (with one second and a half, I get an error), but this is too much for my application. I need to do it as fast as possible.
Thanks to everyone for your replies, If any of you have had the same problem, or know about one solution, please let me know. I'm also open to using other libraries, but they must be well debugged, something like the official Arduino one, because I also have to interact with commercial devices that use modbus, I can't have future problems
What slaves do you have on your bus? If you need to pause for 1.5 seconds there is something wrong with your slaves or the hardware. Post a wiring diagram and links to the slaves you have on the bus!
The ModbusMaster library is probably used much more often than the ArduinoModbus library which is designed for the MKR series of Arduinos.
Modbus Test.pdf (177.8 KB)
In this PDF you can see the test hardware. The Master Tx pin is directly connected to the Rx pins of the slaves, each slave respond only if the message contains his id. The Tx pins of the slaves are connected to the Rx pin of the master through a 3-state buffer, only one of these buffers will be active at a time, depending on which slave device is responding to the modbus message (it is like a bus).
What chip do you use for this tri-state buffer?
For the slaves I would use smarmengols library. You might even use that one for both sides as it knows about master and slave but is a bit less convenient in the master role than ModbusMaster.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.