Closed gerrygralton closed 11 months ago
I am noticing a couple of things in your code.
What processor are you using?
An STM32 F4xx chip. It shouldn't make any difference but I'd be interested if you don't manage to reproduce this on other hardware.
It appears you are configuring holding registers, not input registers.
Ah, whoops. The error appears when using either input or holding registers. That was just me fiddling to reproduce the error. I'll edit the code for consistency.
I am not seeing the issue when running the following code on an Arduino Uno.
#include <SoftwareSerial.h>
#include <ModbusRTUSlave.h>
const uint8_t rxPin = 10;
const uint8_t txPin = 11;
const uint8_t dePin = 13;
SoftwareSerial mySerial(rxPin, txPin);
ModbusRTUSlave modbus(mySerial, dePin);
const uint16_t numInputRegisters = 4;
uint16_t inputRegisters[numInputRegisters];
void setup() {
modbus.configureInputRegisters(inputRegisters, numInputRegisters);
modbus.begin(1, 38400, SERIAL_8N1);
inputRegisters[0] = 0x002A;
inputRegisters[1] = 0x0000;
inputRegisters[2] = 0x0808;
inputRegisters[3] = 0xFFFF;
}
void loop() {
modbus.poll();
}
When requesting 4 input registers, this is the response I get: 01 04 08 00 2A 00 00 08 08 FF FF 2D DD
.
When requesting 5 input registers, this is the response I get: 01 84 02 C2 C1
, which is the appropriate exception response.
So if I use your code the response I get is
Asking for 4 registers works as expected but 5 registers dumps a never ending stream of repeated bytes after printing the exception code. The first modbus tool I used, mbpoll, stopped listening after receiving the exception code but the bus was clearly full.
This is a screengrab from IoNinja. Blue is my request and green is the MCU's response.
I think I see what is going on here.
When I use RS-485, I normally connect the DE and RE pins of the driver together, so when it is transmitting it is not receiving. I see in the initial code you posted, you have an RE pin setup.
It looks like whenever a response is transmitted, the library also processes the transmitted message as though it were a request from the master device.
When you request 4 input registers, the library recognizes the function code, but it always expects 8 bytes with that function code, so it ignores the message.
However, when you request 5 input registers, the library sends and exception response: 01 84 02 C2 C1
(02 - ILLEGAL DATA ADDRESS). Then it sees the 01
in the receiving buffer and assumes the message there is addressed to it, and that 84
is the function code, so it responds with with the exception response code: 01 84 01 82 C0
(01 - ILLEGAL FUNCTION).
And it continues to respond to its own exception responses with exception responses.
I've added this bit of code to the end of the _writeResponse
function to quickly clear out the receiving buffer after transmitting.
while(_serial->available()) {
_serial->read();
}
This should prevent the issue you've been having.
Thanks Chris! This does look like it has fixed the issue. It would be great if you could release this to Arduino libraries.
Would this issue be better served by adding an RE pin option to the library? I've noticed that the ArduinoRS485 library seems to have that functionality and it seems like it could be quite useful here too.
If a master node sends a request for more than the number of available registers, this library seems to send a very unexpected response. It just returns a very large, never ending stream of data. Using the code below, with 4 declared input registers, if 5 or more registers are requested by the master the error occurs.