There are a lot of things it could be; I’m going to post 2 lists of suggestions
1st:
Let me help you troubleshoot this Modbus RTU communication issue. The “Illegal function” error typically occurs when the slave device doesn’t support or isn’t properly configured for the requested function code.
Here are a few potential issues and solutions:
- Function Code Configuration:
Make sure your code explicitly enables write functions. The ModbusRTUSlave library might need specific configuration for write operations. Try adding permission settings:
// Add after configuring registers in setup()
modbus.configureWriteHoldingRegistersCallback(true); // Enable write to holding registers
modbus.configureWriteCoilsCallback(true); // Enable write to coils
- Register Address Range:
Verify that the QModmaster is trying to write to addresses within your configured range. You’ve defined:
- 2 coils (addresses 0-1)
- 3 holding registers (addresses 0-2)
Make sure your write attempts are within these ranges.
- Serial Communication Parameters:
Your code uses 8N1 (8 data bits, no parity, 1 stop bit), verify that:
- QModmaster is configured with the same parameters (8N1)
- Link-150 gateway is configured with matching parameters
- The baud rate (9600) matches across all devices
- Gateway Configuration:
Check the Schneider Link-150 settings:
- Verify the TCP/IP to RTU mapping is correct
- Ensure the Modbus slave ID (1 in your code) matches the gateway configuration
- Check if any response timeout settings need adjustment
- Try removing continuous writes:
Your loop is constantly updating holdingRegisters[0] and [1]. Try a simpler test:
void loop() {
// Remove or comment out the random writes
// holdingRegisters[0] = rand();
// holdingRegisters[1] = rand();
modbus.poll();
}
- Debug with Serial Monitor:
Add some debugging to see what’s happening:
#include <ModbusRTUSlave.h>
#define MODBUS_SERIAL Serial
#define DEBUG_SERIAL Serial1 // Use a second serial port for debugging if available
ModbusRTUSlave modbus(MODBUS_SERIAL, 8);
// ... rest of your declarations ...
void setup() {
modbus.configureCoils(coils, 2);
modbus.configureDiscreteInputs(discreteInputs, 2);
modbus.configureHoldingRegisters(holdingRegisters, 3);
modbus.configureInputRegisters(inputRegisters, 2);
// Enable write callbacks
modbus.configureWriteHoldingRegistersCallback(true);
modbus.configureWriteCoilsCallback(true);
MODBUS_SERIAL.begin(9600, SERIAL_8N1);
modbus.begin(1, 9600, SERIAL_8N1);
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.begin(115200);
DEBUG_SERIAL.println("Modbus RTU Slave Started");
#endif
}
void loop() {
modbus.poll();
#ifdef DEBUG_SERIAL
// Print register values periodically
static unsigned long lastPrint = 0;
if (millis() - lastPrint > 1000) {
DEBUG_SERIAL.print("HR0:");
DEBUG_SERIAL.print(holdingRegisters[0]);
DEBUG_SERIAL.print(" HR1:");
DEBUG_SERIAL.println(holdingRegisters[1]);
lastPrint = millis();
}
#endif
}
If these steps don’t resolve the issue, we could also:
- Try a different Modbus RTU library to rule out library-specific issues
- Use a logic analyzer to capture the RS485 communication
- Test with a different Modbus master software to isolate if it’s a QModmaster-specific issue
2nd:
The error “Illegal function” indicates that the Modbus master (QModMaster in your case) is attempting to use a function code that the slave device does not support. The most likely reasons for this behavior in your setup are:
1. Unsupported Write Functions
The Modbus slave library may not have write support enabled or properly configured for holding registers and coils. Verify the library documentation to confirm that the ModbusRTUSlave
library supports these write operations. Some libraries require additional configuration to handle writes.
2. Incorrect Configuration of Modbus Functions
Ensure the Modbus slave is correctly configured to allow writing to the holding registers and coils. In your code, the configurations for the data tables (coils and holding registers) appear correct, but the issue could still be in how the library handles write requests.
3. Address Mismatch
Verify that the addresses in QModMaster match the ones defined in your code:
- Holding registers are addressed from
0
in your code.
- Coils are addressed from
0
as well.
If the master sends a request to an address outside the range you’ve defined, the slave will reject it with an “Illegal function” error.
4. Faulty Gateway Conversion
Your setup uses a Schneider Link-150 RS485-to-Ethernet gateway. While the reading of registers and coils works fine, ensure that the gateway is properly configured to forward write commands to the RS485 bus without modification.
5. QModMaster Configuration
Double-check how the write operation is configured in QModMaster:
- Use function code 6 (Write Single Register) or 16 (Write Multiple Registers) for holding registers.
- Use function code 5 (Write Single Coil) or 15 (Write Multiple Coils) for coils.
If you accidentally use a read-only function code for writing, you will see this error.
Suggested Fixes
-
Enable Write Handling in the Library:
Some Modbus libraries require explicit function handlers to manage write requests. Check if you need to add a callback or enable write functions explicitly.
-
Debug Logging:
Add debugging to your code to log the requests received by the slave. This can help verify whether write requests are reaching the slave and how they’re being processed.
-
Verify Gateway Settings:
Ensure the Schneider Link-150 is not filtering or modifying write requests. You may need to consult the device’s manual or configuration software to ensure proper operation.
-
Test with Simplified Setup:
Connect the Arduino directly to the PC (bypassing the gateway) using an RS485-to-USB adapter. Test write functions to isolate whether the issue lies in the gateway.
Example Debugging Code
You can add debug prints to see how requests are being processed:
void loop() {
modbus.poll();
if (modbus.isNewRequest()) {
Serial.print("New Modbus request received. Function code: ");
Serial.println(modbus.getFunctionCode());
}
}
This will help identify whether the slave receives and processes write requests correctly.