Skip to content

Commit 2c3983b

Browse files
committed
added rs485ControlPin
1 parent 81bd8fb commit 2c3983b

File tree

4 files changed

+229
-108
lines changed

4 files changed

+229
-108
lines changed

README.md

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ The `MBModbusRTUSlave` library allows Arduino devices to function as Modbus RTU
1717

1818
### Version
1919
- **1.0.0** (Released: March 07, 2025)
20+
- **1.1.0** (Released: April 08, 2025)
2021

2122
### Author
2223
- S.Mersin (electrocoder) <[email protected]> (Assisted by Grok)
@@ -50,23 +51,62 @@ The `MBModbusRTUSlave` library allows Arduino devices to function as Modbus RTU
5051

5152
## Usage
5253

54+
- Define the register count in your Arduino code:
55+
5356
### Basic Example
54-
This example initializes a Modbus slave with default settings and controls an LED based on register 5.
57+
This example initializes a Modbus slave with default settings and controls.
5558

5659
```cpp
5760
#include <MBModbusRTUSlave.h>
5861
59-
long modbusBaudRate = 9600; // Customizable baud rate
60-
MBModbusRTUSlave modbus(0x01, 13, 5); // Slave address: 0x01, LED pin: 13, LED register: 5
62+
#define RXD2 16 // ESP32 Serial2
63+
#define TXD2 17 // ESP32 Serial2
64+
65+
long mymodbusBaudRate = 9600; // Customizable baud rate
66+
const uint16_t myRegisterCount = 20;
67+
MBModbusRTUSlave modbus(0x01, &Serial2, 26, myRegisterCount); // Slave address: 0x01, Serial port name: Serial2, RS485 Module Pin: 26, Register count: 10
68+
69+
unsigned long previousMillis = 0;
70+
const long interval = 1000;
6171
6272
void setup() {
63-
modbus.begin(modbusBaudRate);
73+
74+
Serial.begin(9600); // DEBUG message
75+
76+
Serial2.begin(9600, SERIAL_8N2, RXD2, TXD2);
77+
pinMode(26, OUTPUT);
78+
79+
modbus.begin(mymodbusBaudRate);
6480
Serial.println("Modbus started");
81+
6582
}
6683
6784
void loop() {
68-
modbus.update();
85+
86+
unsigned long currentMillis = millis();
87+
if (currentMillis - previousMillis >= interval) {
88+
89+
previousMillis = currentMillis;
90+
91+
modbus.writeFloatRegister(0, 123.45); // Float method
92+
modbus.writeRegister(2, 66); // Uint16_t method
93+
94+
}
95+
96+
// Read Register
97+
if (modbus.readRegisters()) {
98+
Serial.println("Modbus to read");
99+
}
100+
101+
// Read Float and Integer Register
102+
Serial.print(modbus.getFloatRegister(0));
103+
Serial.print(" ");
104+
Serial.print(modbus.getRegister(2));
105+
Serial.println("");
106+
107+
delay(10);
69108
}
109+
70110
```
71111
72112
### Modbus Commands

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=MBModbusRTUSlave
2-
version=1.0.0
2+
version=1.1.0
33
author=S.Mersin (electrocoder) <[email protected]>
44
maintainer=S.Mersin (electrocoder) <[email protected]>
55
sentence=Modbus RTU protocol (function codes `0x03` and `0x06`). This library is a slave implementation of the Modbus RTU protocol.

src/MBModbusRTUSlave.cpp

Lines changed: 148 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3,151 +3,225 @@
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

Comments
 (0)