Ok, here is a bit of code written for my UNO that writes to a single register and also writes to multiple registers in one message:
// Modbus device simulated using ModRSsim2 available from https://sourceforge.net/projects/modrssim2/
//
#include <ModbusMaster.h>
#include <AltSoftSerial.h>
#define MAX485_DE 6
#define MAX485_RE_NEG 7
AltSoftSerial swSerial;
ModbusMaster node;
// Put the MAX485 into transmit mode
void preTransmission()
{
digitalWrite(MAX485_RE_NEG, 1);
digitalWrite(MAX485_DE, 1);
}
// Put the MAX485 into receive mode
void postTransmission()
{
digitalWrite(MAX485_RE_NEG, 0);
digitalWrite(MAX485_DE, 0);
}
void setup() {
Serial.begin( 115200 );
// configure the MAX485 RE & DE control signals and enable receive mode
pinMode(MAX485_RE_NEG, OUTPUT);
pinMode(MAX485_DE, OUTPUT);
digitalWrite(MAX485_RE_NEG, 0);
digitalWrite(MAX485_DE, 0);
// Modbus communication runs at 9600 baud (change to suit your sensor)
swSerial.begin(9600);
// Modbus slave ID of NPK sensor is 1
node.begin(1, swSerial);
// Callbacks to allow us to set the RS485 Tx/Rx direction
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
}
void loop() {
uint8_t result;
// empty the transmit registers
node.clearTransmitBuffer();
node.writeSingleRegister( 2, 1000 );
printModbusError( result );
// write the 3 values 1, 2 & 3 to registers 7, 8 & 9
node.setTransmitBuffer(0x00, 1);
node.setTransmitBuffer(0x01, 2);
node.setTransmitBuffer(0x02, 3);
result = node.writeMultipleRegisters(0x0007, 3);
printModbusError( result );
Serial.println();
delay(5000);
}
// print out the error received from the Modbus library
void printModbusError( uint8_t errNum )
{
switch ( errNum ) {
case node.ku8MBSuccess:
Serial.println(F("Success"));
break;
case node.ku8MBIllegalFunction:
Serial.println(F("Illegal Function Exception"));
break;
case node.ku8MBIllegalDataAddress:
Serial.println(F("Illegal Data Address Exception"));
break;
case node.ku8MBIllegalDataValue:
Serial.println(F("Illegal Data Value Exception"));
break;
case node.ku8MBSlaveDeviceFailure:
Serial.println(F("Slave Device Failure"));
break;
case node.ku8MBInvalidSlaveID:
Serial.println(F("Invalid Slave ID"));
break;
case node.ku8MBInvalidFunction:
Serial.println(F("Invalid Function"));
break;
case node.ku8MBResponseTimedOut:
Serial.println(F("Response Timed Out"));
break;
case node.ku8MBInvalidCRC:
Serial.println(F("Invalid CRC"));
break;
default:
Serial.println(F("Unknown Error"));
break;
}
}
The line of code:
node.writeSingleRegister( 2, 1000 );
results in the following bytes appearing on the RS485 bus:
01 06 00 02 03 E8 28 B4 00
This is the correct message for the writeSingleRegister command if you ignore the trailing 00.
The lines of code:
node.setTransmitBuffer(0x00, 1);
node.setTransmitBuffer(0x01, 2);
node.setTransmitBuffer(0x02, 3);
result = node.writeMultipleRegisters(0x0007, 3);
results in the following bytes appearing on the RS485 bus:
01 10 00 07 00 03 06 00 01 00 02 00 03 8b 5b
This is the correct message for the writeMultipleRegisters command.
However, I also saw a lot of messages like this one when using the writeMultipleRegisters command:
40 04 07 00 03 06 00 01 00 02 00 03 8b 5b
The first 2 bytes are garbage, and should be the 3 bytes 01 10 00.
So, even on my UNO, there seems to be an issue with the writeMultipleRegisters command.