33 *
44 * Description: This file implements the methods of the MBModbusRTUSlave class.
55 * It supports Modbus RTU protocol for register reading (0x03) and writing (0x06).
6- * Provides LED control and flexible baud rate adjustments.
6+ * Provides flexible baud rate adjustments and RS485 transceiver support .
77 * Author: S.Mersin (electrocoder) <[email protected] > (Assisted by Grok) 8- * Date: March 07 , 2025
9- * Version: 1.0 .0
8+ * Date: April 08 , 2025
9+ * Version: 1.1 .0
1010 * License: MIT License
11- *
11+ *
1212 * Note: This library uses the Arduino Serial port to provide Modbus RTU slave functionality.
1313 * All registers except the LED register are updated with random values.
1414 */
1515
1616#include " MBModbusRTUSlave.h"
1717
18- MBModbusRTUSlave::MBModbusRTUSlave (uint8_t slaveAddress, uint8_t ledPin, uint8_t ledRegisterIndex, uint16_t registerCount) {
18+ MBModbusRTUSlave::MBModbusRTUSlave (uint8_t slaveAddress, HardwareSerial *serialPort, uint8_t rs485ControlPin, uint16_t registerCount)
19+ {
1920 _slaveAddress = slaveAddress;
20- _ledPin = ledPin;
21- _ledRegisterIndex = ledRegisterIndex;
21+ _modbusBaudRate = 9600 ;
22+ _serialPort = serialPort;
23+ _rs485ControlPin = rs485ControlPin;
2224 _registerCount = registerCount;
23- _baudRate = 9600 ; // Default baud rate
2425
25- // Create dynamic register array
2626 modbusRegisters = new uint16_t [_registerCount];
27-
28- // Fill the registers with initial values
2927 modbusRegisters[0 ] = 0 ;
3028 modbusRegisters[1 ] = 5678 ;
3129 modbusRegisters[2 ] = 90 ;
32- for (int i = 3 ; i < _registerCount; i++) {
30+ for (int i = 3 ; i < _registerCount; i++)
31+ {
3332 modbusRegisters[i] = 0 ;
3433 }
3534}
3635
37- void MBModbusRTUSlave::begin (long baudRate) {
38- _baudRate = baudRate;
39- pinMode (_ledPin, OUTPUT);
40- digitalWrite (_ledPin, LOW);
41- Serial.begin (_baudRate, SERIAL_8N1);
42- while (!Serial)
43- ;
36+ MBModbusRTUSlave::~MBModbusRTUSlave ()
37+ {
38+ delete[] modbusRegisters; // Delete registers
4439}
4540
46- void MBModbusRTUSlave::update () {
47- // We assign random values to all registers except the LED register
48- for (int i = 0 ; i < _registerCount; i++) {
49- if (i != _ledRegisterIndex)
50- modbusRegisters[i] = random (1 , 10000 );
51- }
41+ void MBModbusRTUSlave::begin (long modbusBaudRate)
42+ {
43+ _modbusBaudRate = modbusBaudRate;
44+ pinMode (_rs485ControlPin, OUTPUT);
45+ digitalWrite (_rs485ControlPin, LOW);
46+ _serialPort->begin (_modbusBaudRate, SERIAL_8N1);
47+ while (!_serialPort)
48+ ;
49+ }
5250
53- if (Serial.available () >= 8 ) {
54- for (int i = 0 ; i < 8 ; i++) {
55- requestBuffer[i] = Serial.read ();
51+ bool MBModbusRTUSlave::readRegisters ()
52+ {
53+ digitalWrite (_rs485ControlPin, LOW); // Receiver
54+ if (_serialPort->available () >= 8 )
55+ {
56+ for (int i = 0 ; i < 8 ; i++)
57+ {
58+ requestBuffer[i] = _serialPort->read ();
5659 }
5760
58- if (requestBuffer[0 ] == _slaveAddress) {
59- if (checkCRC (requestBuffer, 6 )) {
60- if (requestBuffer[1 ] == 0x03 ) {
61- processReadHoldingRegisters ();
62- } else if (requestBuffer[1 ] == 0x06 ) {
63- processWriteSingleRegister ();
64- }
61+ if (requestBuffer[0 ] == _slaveAddress && checkCRC (requestBuffer, 6 ))
62+ {
63+ if (requestBuffer[1 ] == 0x03 )
64+ {
65+ processReadHoldingRegisters ();
66+ }
67+ else if (requestBuffer[1 ] == 0x06 )
68+ {
69+ processWriteSingleRegister ();
6570 }
71+ while (_serialPort->available ())
72+ _serialPort->read ();
73+ return true ;
6674 }
75+ }
76+ return false ;
77+ }
78+
79+ void MBModbusRTUSlave::writeFloatRegister (uint16_t registerAddress, float value)
80+ {
81+ if (registerAddress < _registerCount - 1 )
82+ {
83+ uint32_t floatBits;
84+ memcpy (&floatBits, &value, sizeof (float ));
85+ modbusRegisters[registerAddress] = (floatBits >> 16 ) & 0xFFFF ;
86+ modbusRegisters[registerAddress + 1 ] = floatBits & 0xFFFF ;
87+ }
88+ }
89+
90+ void MBModbusRTUSlave::writeRegister (uint16_t registerAddress, uint16_t value)
91+ {
92+ if (registerAddress < _registerCount)
93+ {
94+ modbusRegisters[registerAddress] = value;
95+ }
96+ }
6797
68- while (Serial.available ()) Serial.read ();
98+ uint16_t MBModbusRTUSlave::getRegister (uint16_t registerAddress)
99+ {
100+ if (registerAddress < _registerCount)
101+ {
102+ return modbusRegisters[registerAddress];
69103 }
104+ return 0 ;
105+ }
70106
71- digitalWrite (_ledPin, modbusRegisters[_ledRegisterIndex] == 1 ? HIGH : LOW);
107+ float MBModbusRTUSlave::getFloatRegister (uint16_t registerAddress)
108+ {
109+ if (registerAddress < _registerCount - 1 )
110+ {
111+ uint32_t floatBits = ((uint32_t )modbusRegisters[registerAddress] << 16 ) | modbusRegisters[registerAddress + 1 ];
112+ float value;
113+ memcpy (&value, &floatBits, sizeof (float ));
114+ return value;
115+ }
116+ return 0.0 ;
72117}
73118
74- void MBModbusRTUSlave::processReadHoldingRegisters () {
119+ void MBModbusRTUSlave::processReadHoldingRegisters ()
120+ {
75121 uint16_t startAddress = (requestBuffer[2 ] << 8 ) | requestBuffer[3 ];
76122 uint16_t registerCount = (requestBuffer[4 ] << 8 ) | requestBuffer[5 ];
77123
78- responseBuffer[0 ] = _slaveAddress;
79- responseBuffer[1 ] = 0x03 ;
80- responseBuffer[2 ] = registerCount * 2 ;
81-
82- for (int i = 0 ; i < registerCount; i++) {
83- uint16_t regValue = modbusRegisters[startAddress + i];
84- responseBuffer[3 + i * 2 ] = (regValue >> 8 ) & 0xFF ;
85- responseBuffer[4 + i * 2 ] = regValue & 0xFF ;
86- }
124+ if (startAddress + registerCount <= _registerCount)
125+ { // Register check
126+ responseBuffer[0 ] = _slaveAddress;
127+ responseBuffer[1 ] = 0x03 ;
128+ responseBuffer[2 ] = registerCount * 2 ;
129+
130+ for (int i = 0 ; i < registerCount; i++)
131+ {
132+ uint16_t regValue = modbusRegisters[startAddress + i];
133+ responseBuffer[3 + i * 2 ] = (regValue >> 8 ) & 0xFF ;
134+ responseBuffer[4 + i * 2 ] = regValue & 0xFF ;
135+ }
87136
88- uint16_t crc = calculateCRC (responseBuffer, 3 + registerCount * 2 );
89- responseBuffer[3 + registerCount * 2 ] = crc & 0xFF ;
90- responseBuffer[4 + registerCount * 2 ] = (crc >> 8 ) & 0xFF ;
137+ uint16_t crc = calculateCRC (responseBuffer, 3 + registerCount * 2 );
138+ responseBuffer[3 + registerCount * 2 ] = crc & 0xFF ;
139+ responseBuffer[4 + registerCount * 2 ] = (crc >> 8 ) & 0xFF ;
91140
92- Serial.write (responseBuffer, 5 + registerCount * 2 );
141+ digitalWrite (_rs485ControlPin, HIGH);
142+ _serialPort->write (responseBuffer, 5 + registerCount * 2 );
143+ _serialPort->flush ();
144+ digitalWrite (_rs485ControlPin, LOW);
145+ }
93146}
94147
95- void MBModbusRTUSlave::processWriteSingleRegister () {
148+ void MBModbusRTUSlave::processWriteSingleRegister ()
149+ {
96150 uint16_t registerAddress = (requestBuffer[2 ] << 8 ) | requestBuffer[3 ];
97151 uint16_t registerValue = (requestBuffer[4 ] << 8 ) | requestBuffer[5 ];
98152
99- if (registerAddress < _registerCount) {
153+ if (registerAddress < _registerCount)
154+ {
100155 modbusRegisters[registerAddress] = registerValue;
101156 }
102157
103- for (int i = 0 ; i < 6 ; i++) {
158+ for (int i = 0 ; i < 6 ; i++)
159+ {
104160 responseBuffer[i] = requestBuffer[i];
105161 }
106162 responseBuffer[6 ] = requestBuffer[6 ];
107163 responseBuffer[7 ] = requestBuffer[7 ];
108164
109- Serial.write (responseBuffer, 8 );
165+ digitalWrite (_rs485ControlPin, HIGH);
166+ _serialPort->write (responseBuffer, 8 );
167+ _serialPort->flush ();
168+ digitalWrite (_rs485ControlPin, LOW);
110169}
111170
112- uint16_t MBModbusRTUSlave::calculateCRC (uint8_t *buffer, uint8_t length) {
171+ uint16_t MBModbusRTUSlave::calculateCRC (uint8_t *buffer, uint8_t length)
172+ {
113173 uint16_t crc = 0xFFFF ;
114- for (uint8_t pos = 0 ; pos < length; pos++) {
174+ for (uint8_t pos = 0 ; pos < length; pos++)
175+ {
115176 crc ^= (uint16_t )buffer[pos];
116- for (uint8_t i = 8 ; i != 0 ; i--) {
117- if ((crc & 0x0001 ) != 0 ) {
177+ for (uint8_t i = 8 ; i != 0 ; i--)
178+ {
179+ if ((crc & 0x0001 ) != 0 )
180+ {
118181 crc >>= 1 ;
119182 crc ^= 0xA001 ;
120- } else {
183+ }
184+ else
185+ {
121186 crc >>= 1 ;
122187 }
123188 }
124189 }
125190 return crc;
126191}
127192
128- bool MBModbusRTUSlave::checkCRC (uint8_t *buffer, uint8_t length) {
193+ bool MBModbusRTUSlave::checkCRC (uint8_t *buffer, uint8_t length)
194+ {
129195 uint16_t receivedCRC = (buffer[length + 1 ] << 8 ) | buffer[length];
130196 uint16_t calculatedCRC = calculateCRC (buffer, length);
131197 return (receivedCRC == calculatedCRC);
132198}
133199
134- // Setter methods
135- void MBModbusRTUSlave::setSlaveAddress ( uint8_t slaveAddress) {
200+ void MBModbusRTUSlave::setSlaveAddress ( uint8_t slaveAddress)
201+ {
136202 _slaveAddress = slaveAddress;
137203}
138204
139- void MBModbusRTUSlave::setLedPin (uint8_t ledPin) {
140- _ledPin = ledPin;
141- pinMode (_ledPin, OUTPUT);
205+ void MBModbusRTUSlave::setModbusBaudRate (long modbusBaudRate)
206+ {
207+ _modbusBaudRate = modbusBaudRate;
208+ _serialPort->begin (_modbusBaudRate, SERIAL_8N1);
142209}
143210
144- void MBModbusRTUSlave::setLedRegisterIndex ( uint8_t ledRegisterIndex) {
145- if (ledRegisterIndex < _registerCount) {
146- _ledRegisterIndex = ledRegisterIndex ;
147- }
211+ void MBModbusRTUSlave::setSerialPort (HardwareSerial *serialPort)
212+ {
213+ _serialPort = serialPort ;
214+ _serialPort-> begin (_modbusBaudRate, SERIAL_8N1);
148215}
149216
150- void MBModbusRTUSlave::setBaudRate (long baudRate) {
151- _baudRate = baudRate;
152- Serial.begin (_baudRate, SERIAL_8N1);
153- }
217+ void MBModbusRTUSlave::setRS485ControlPin (uint8_t rs485ControlPin)
218+ {
219+ _rs485ControlPin = rs485ControlPin;
220+ pinMode (_rs485ControlPin, OUTPUT);
221+ digitalWrite (_rs485ControlPin, LOW);
222+ }
223+
224+ uint16_t MBModbusRTUSlave::getRegisterCount ()
225+ {
226+ return _registerCount;
227+ }
0 commit comments