This modbus slave library uses callbacks to handle modbus requests. Handler functions are called on modbus request, and the users can implement them in their sketch.
Register a handler function:
slave.cbVector[CB_READ_REGISTERS] = ReadAnalogIn;
Implement it:
void ReadAnalogIn(uint8_t fc, uint16_t address, uint16_t length) {
for (int i = 0; i < length; i++)
slave.writeRegisterToBuffer(i, analogRead(address + i));
}
And thats it, your sketch is modbus enabled. (see the full examples for more detail)
- Install
- Competabilty
- Callback vector - Slots - Handler function - Function codes - Reading and writing to the request buffer
- Examples - handle "Force Single Coil" as arduino digitalWrite - handle "Read Input Registers" as arduino analogRead
Download the zip package, and install it into your Arduino IDE. See the Arduino tutorial about installing 3rd party libraries: https://www.arduino.cc/en/Guide/Libraries#toc4
- FC1 "Read Coil Status"
- FC2 "Read Input Status"
- FC3 "Read Holding Registers"
- FC4 "Read Input Registers"
- FC5 "Force Single Coil"
- FC6 "Preset Single Register"
- FC15 "Force Multiple Coils"
- FC16 "Preset Multiple Registers"
- The default serial port is Serial, but any class that inhirets from Stream can be used. To set a different Serial class, explicitly set the Stream in the Modbus class constuctor.
Users register handler functions into the callback vector.
The callback vector has 4 slots for request handlers:
- slave.cbVector[CB_READ_COILS] - called on FC1 and FC2
- slave.cbVector[CB_WRITE_COILS] - called on FC5 and FC15
- slave.cbVector[CB_READ_REGISTERS] - called on FC3 and FC4
- slave.cbVector[CB_WRITE_REGISTERS] - called on FC6 and FC16
Handler functions must return unit8_t and take:
- uint8_t fc - request function code
- uint16_t address - first register / first coil address
- uint16_t length - length of data
Return codes:
- STATUS_OK = 0,
- STATUS_ILLEGAL_FUNCTION,
- STATUS_ILLEGAL_DATA_ADDRESS,
- STATUS_ILLEGAL_DATA_VALUE,
- STATUS_SLAVE_DEVICE_FAILURE,
- STATUS_ACKNOWLEDGE,
- STATUS_SLAVE_DEVICE_BUSY,
- STATUS_NEGATIVE_ACKNOWLEDGE,
- STATUS_MEMORY_PARITY_ERROR,
- STATUS_GATEWAY_PATH_UNAVAILABLE,
- STATUS_GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND
- FC_READ_COILS = 1
- FC_READ_DISCRETE_INPUT = 2
- FC_READ_REGISTERS = 3
- FC_READ_INPUT_REGISTERS = 4
- FC_WRITE_COIL = 5
- FC_WRITE_REGISTER = 6
- FC_WRITE_MULTIPLE_COILS = 15
- FC_WRITE_MULTIPLE_REGISTERS = 16
- int readCoilFromBuffer(int offset) : read one coil value from the request buffer.
- uint16_t readRegisterFromBuffer(int offset) : read one register value from the request buffer.
- void writeCoilToBuffer(int offset, int state) : write one coil state into the answer buffer.
- void writeRegisterToBuffer(int offset, uint16_t value) : write one register value into the answer buffer.
#include <ModbusSlave.h>
// implicitly set stream to use the Serial serialport
Modbus slave(1, 8); // [stream = Serial,] slave id = 1, rs485 control-pin = 8
void setup() {
// register one handler functions
// if a callback handler is not assigned to a modbus command
// the default handler is called.
// default handlers return a valid but empty replay.
slave.cbVector[CB_WRITE_COILS] = writeDigitlOut;
// start slave at baud 9600 on Serial
Serial.begin( 9600 ); // baud = 9600
slave.begin( 9600 );
}
void loop() {
// listen for modbus commands con serial port
slave.poll();
}
// Handel Force Single Coil (FC=05)
uint8_t writeDigitlOut(uint8_t fc, uint16_t address, uint16_t length) {
if (slave.readCoilFromBuffer(0) == HIGH) {
digitalWrite(address, HIGH);
} else {
digitalWrite(address, LOW);
}
return STATUS_OK;
}
#include <ModbusSlave.h>
// explicitly set stream to use the Serial serialport
Modbus slave(Serial, 1, 8); // stream = Serial, slave id = 1, rs485 control-pin = 8
void setup() {
// register handler functions
slave.cbVector[CB_READ_REGISTERS] = ReadAnalogIn;
// start slave at baud 9600 on Serial
Serial.begin( 9600 ); // baud = 9600
slave.begin( 9600 );
}
void loop() {
// listen for modbus commands con serial port
slave.poll();
}
// Handel Read Input Registers (FC=04)
uint8_t ReadAnalogIn(uint8_t fc, uint16_t address, uint16_t length) {
// we only answer to function code 4
if (fc != FC_READ_INPUT_REGISTERS) return;
// write registers into the answer buffer
for (int i = 0; i < length; i++) {
slave.writeRegisterToBuffer(i, analogRead(address + i));
}
return STATUS_OK;
}