I'm trying to implement Writing Multiple Registers (0x10) using the Modbus Structure on a Controllino Mega MCU.
#include <Controllino.h> /* Usage of CONTROLLINO library allows you to use CONTROLLINO_xx aliases in your sketch. */
#include "ModbusRtu.h" /* Usage of ModBusRtu library allows you to implement the Modbus RTU protocol in your sketch. */
/*
CONTROLLINO - Modbus RTU protocol Master example for MAXI and MEGA, Version 01.00
The sketch is relevant only for CONTROLLINO variants MAXI and MEGA (because of necessity of RS485 interface)!
This sketch is intended as an example of the communication between devices via RS485 with utilization the ModbusRTU protocol.
In this example the CONTROLLINO is used as the Modbus master!
For more information about the Modbus protocol visit the website: http://modbus.org/
Modbus master device periodically reads Modbus 16bit registers (provided by the slave) and prints the current state to the debug Serial:
0 - analog CONTROLLINO_A0 value (0 - 1024)
1 - digital CONTROLLINO_D0 value (0/1)
2 - Modbus messages received
3 - Modbus messages transmitted
Modbus master device periodically writes and toggles Modbus 16bit registers:
4 - relay CONTROLLINO_R0 (0/1)
5 - relay CONTROLLINO_R1 (0/1)
6 - relay CONTROLLINO_R2 (0/1)
7 - relay CONTROLLINO_R3 (0/1)
To easily evaluate this example you need a second CONTROLLINO as Modbus slave running DemoModbusRTUSlave example sketch.
Please note that both CONTROLLINOs need 12/24V external supply and you need to interconnect GND, -, + signals of RS485 screw terminal.
Modbus Master-Slave library for Arduino (ModbusRtu.h) was taken from the website: https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino
It was necessary to modify setting of the PORTJ for pins DE and RE control. These pins are located at the PORJ and on the pins PIN6(DE) and PIN5(RE).
IMPORTANT INFORMATION!
Please, select proper target board in Tools->Board->Controllino MAXI/MEGA before Upload to your CONTROLLINO.
(Please, refer to https://github.com/CONTROLLINO-PLC/CONTROLLINO_Library if you do not see the CONTROLLINOs in the Arduino IDE menu Tools->Board.)
Created 30 March 2017
by David
https://controllino.biz/
(Check https://github.com/CONTROLLINO-PLC/CONTROLLINO_Library for the latest CONTROLLINO related software stuff.)
*/
// This MACRO defines Modbus master address.
// For any Modbus slave devices are reserved addresses in the range from 1 to 247.
// Important note only address 0 is reserved for a Modbus master device!
#define MasterModbusAdd 0
#define SlaveModbusAdd 1
// This MACRO defines number of the comport that is used for RS 485 interface.
// For MAXI and MEGA RS485 is reserved UART Serial3.
#define RS485Serial 3
// The object ControllinoModbuSlave of the class Modbus is initialized with three parameters.
// The first parametr specifies the address of the Modbus slave device.
// The second parameter specifies type of the interface used for communication between devices - in this sketch is used RS485.
// The third parameter can be any number. During the initialization of the object this parameter has no effect.
Modbus ControllinoModbusMaster(MasterModbusAdd, RS485Serial, 0);
// This uint16 array specified internal registers in the Modbus slave device.
// Each Modbus device has particular internal registers that are available for the Modbus master.
// In this example sketch internal registers are defined as follows:
// (ModbusSlaveRegisters 0 - 3 read only and ModbusSlaveRegisters 4 - 7 write only from the Master perspective):
// ModbusSlaveRegisters[0] - Read an analog value from the CONTROLLINO_A0 - returns value in the range from 0 to 1023.
// ModbusSlaveRegisters[1] - Read an digital value from the CONTROLLINO_D0 - returns only the value 0 or 1.
// ModbusSlaveRegisters[2] - Read the number of incoming messages - Communication diagnostic.
// ModbusSlaveRegisters[3] - Read the number of number of outcoming messages - Communication diagnostic.
// ModbusSlaveRegisters[4] - Sets the Relay output CONTROLLINO_R0 - only the value 0 or 1 is accepted.
// ModbusSlaveRegisters[5] - Sets the Relay output CONTROLLINO_R1 - only the value 0 or 1 is accepted.
// ModbusSlaveRegisters[6] - Sets the Relay output CONTROLLINO_R2 - only the value 0 or 1 is accepted.
// ModbusSlaveRegisters[7] - Sets the Relay output CONTROLLINO_R3 - only the value 0 or 1 is accepted.
uint16_t ModbusSlaveRegisters[40];
// This is an structe which contains a query to an slave device
modbus_t ModbusQuery[10];
uint8_t myState; // machine state
uint8_t currentQuery; // pointer to message query
unsigned long WaitingTime;
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(115200);
Serial.println("-----------------------------------------");
Serial.println("CONTROLLINO Modbus RTU Master Test Sketch");
Serial.println("-----------------------------------------");
Serial.println("");
// ModbusQuery 0: read registers
ModbusQuery[0].u8id = SlaveModbusAdd; // slave address
ModbusQuery[0].u8fct = 0x06; // function code (this one is registers read)
ModbusQuery[0].u16RegAdd = 0x200D; // start address in slave
ModbusQuery[0].u16CoilsNo = 1; // number of elements (coils or registers) to write
ModbusQuery[0].au16reg = ModbusSlaveRegisters; // pointer to a memory array in the CONTROLLINO
ModbusSlaveRegisters[0] = 0x0003;
ModbusQuery[1].u8id = SlaveModbusAdd; // slave address
ModbusQuery[1].u8fct = 0x06; // function code (this one is write a single register)
ModbusQuery[1].u16RegAdd = 0x2080; // start address in slave
ModbusQuery[1].u16CoilsNo = 1; // number of elements (coils or registers) to write
ModbusQuery[1].au16reg = ModbusSlaveRegisters+4; // pointer to a memory array in the CONTROLLINO
ModbusSlaveRegisters[4] = 0x01F4;
ModbusQuery[2].u8id = SlaveModbusAdd; // slave address
ModbusQuery[2].u8fct = 0x06; // function code (this one is write a single register)
ModbusQuery[2].u16RegAdd = 0x2081; // start address in slave
ModbusQuery[2].u16CoilsNo = 1; // number of elements (coils or registers) to write
ModbusQuery[2].au16reg = ModbusSlaveRegisters+8; // pointer to a memory array in the CONTROLLINO
ModbusSlaveRegisters[8] = 0x01F4;
ModbusQuery[3].u8id = SlaveModbusAdd; // slave address
ModbusQuery[3].u8fct = 0x06; // function code (this one is write a single register)
ModbusQuery[3].u16RegAdd = 0x2082; // start address in slave
ModbusQuery[3].u16CoilsNo = 1; // number of elements (coils or registers) to write
ModbusQuery[3].au16reg = ModbusSlaveRegisters+12; // pointer to a memory array in the CONTROLLINO
ModbusSlaveRegisters[12] = 0x01F4;
ModbusQuery[4].u8id = SlaveModbusAdd; // slave address
ModbusQuery[4].u8fct = 0x06; // function code (this one is write a single register)
ModbusQuery[4].u16RegAdd = 0x2083; // start address in slave
ModbusQuery[4].u16CoilsNo = 1; // number of elements (coils or registers) to write
ModbusQuery[4].au16reg = ModbusSlaveRegisters+16; // pointer to a memory array in the CONTROLLINO
ModbusSlaveRegisters[16] = 0x01F4;
ModbusQuery[5].u8id = SlaveModbusAdd; // slave address
ModbusQuery[5].u8fct = 0x06; // function code (this one is write multiple register)
ModbusQuery[5].u16RegAdd = 0x200E; // start address in slave
ModbusQuery[5].u16CoilsNo = 1; // number of elements (coils or registers) to write
ModbusQuery[5].au16reg = ModbusSlaveRegisters+20; // pointer to a memory array in the CONTROLLINO
ModbusSlaveRegisters[20] = 0x0008;
ModbusQuery[6].u8id = SlaveModbusAdd; // slave address
ModbusQuery[6].u8fct = 0x10; // function code (this one is write multiple register)
ModbusQuery[6].u16RegAdd = 0x2088; // start address in slave
ModbusQuery[6].u16CoilsNo = 2; // number of elements (coils or registers) to write
ModbusQuery[6].au16reg = ModbusSlaveRegisters+28; // pointer to a memory array in the CONTROLLINO
ModbusSlaveRegisters[24] = 0x0009;
//ModbusQuery[7].u8id = SlaveModbusAdd; // slave address
//ModbusQuery[7].u8fct = 0x06; // function code (this one is write multiple register)
//ModbusQuery[7].u16RegAdd = 0x2089; // start address in slave
//ModbusQuery[7].u16CoilsNo = 1; // number of elements (coils or registers) to write
//ModbusQuery[7].au16reg = ModbusSlaveRegisters+28; // pointer to a memory array in the CONTROLLINO
//ModbusSlaveRegisters[28] = 0x0009;
ModbusQuery[8].u8id = SlaveModbusAdd; // slave address
ModbusQuery[8].u8fct = 0x06; // function code (this one is write multiple register)
ModbusQuery[8].u16RegAdd = 0x200E; // start address in slave
ModbusQuery[8].u16CoilsNo = 1; // number of elements (coils or registers) to write
ModbusQuery[8].au16reg = ModbusSlaveRegisters+32; // pointer to a memory array in the CONTROLLINO
ModbusSlaveRegisters[32] = 0x0007;
ControllinoModbusMaster.begin( 115200 ); // baud-rate at 115200
ControllinoModbusMaster.setTimeOut( 5000 ); // if there is no answer in 5000 ms, roll over
WaitingTime = millis() + 1000;
myState = 0;
currentQuery = 0;
}
The query I am having trouble implementing is [6], where multiple registers need to be written.
I have shown the output I required below:
01 10 2088 0002 04 0009 0009
And this is the output I am getting:
01 10 2088 0002 04 00
There seems to be something wrong with my input method, would be much appreciated if it could be pointed out what.