From 760b1e3ae5f1b5fdf86a91d962e56d2c3b924a66 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 31 Oct 2024 09:07:54 +0100 Subject: [PATCH 1/2] Feature: class ModbusRTUDelay allows for calculation of minimum inter-frame breaks. More information can be found in https://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf, 2.5.1.1 MODBUS Message RTU Framing. --- .../ModbusRTUClientParameters.ino | 12 +---- keywords.txt | 4 ++ src/ArduinoModbus.h | 1 + src/ModbusRTUDelay.h | 50 +++++++++++++++++++ 4 files changed, 56 insertions(+), 11 deletions(-) create mode 100644 src/ModbusRTUDelay.h diff --git a/examples/RTU/ModbusRTUClientParameters/ModbusRTUClientParameters.ino b/examples/RTU/ModbusRTUClientParameters/ModbusRTUClientParameters.ino index 91b9ec4..3d50882 100644 --- a/examples/RTU/ModbusRTUClientParameters/ModbusRTUClientParameters.ino +++ b/examples/RTU/ModbusRTUClientParameters/ModbusRTUClientParameters.ino @@ -16,23 +16,13 @@ constexpr auto baudrate { 19200 }; -// Calculate preDelay and postDelay in microseconds as per Modbus RTU Specification -// -// MODBUS over serial line specification and implementation guide V1.02 -// Paragraph 2.5.1.1 MODBUS Message RTU Framing -// https://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf -constexpr auto bitduration { 1.f / baudrate }; -constexpr auto wordlen { 9.6f }; // try also with 10.0f -constexpr auto preDelayBR { bitduration * wordlen * 3.5f * 1e6 }; -constexpr auto postDelayBR { bitduration * wordlen * 3.5f * 1e6 }; - void setup() { Serial.begin(9600); while (!Serial); Serial.println("Modbus RTU Client Toggle w/ Parameters"); - RS485.setDelays(preDelayBR, postDelayBR); + RS485.setDelays(ModbusRTUDelay::preDelay(baudrate), ModbusRTUDelay::postDelay(baudrate)); // start the Modbus RTU client in 8E1 mode if (!ModbusRTUClient.begin(baudrate, SERIAL_8E1)) { diff --git a/keywords.txt b/keywords.txt index 845bdb3..b30c910 100644 --- a/keywords.txt +++ b/keywords.txt @@ -7,6 +7,7 @@ ####################################### ArduinoModbus KEYWORD1 +ModbusRTUDelay KEYWORD1 ModbusRTUClient KEYWORD1 ModbusRTUServer KEYWORD1 ModbusRTUClient KEYWORD1 @@ -21,6 +22,9 @@ poll KEYWORD2 end KEYWORD2 setTimeout KEYWORD2 +preDelay KEYWORD2 +postDelay KEYWORD2 + beginTransmission KEYWORD2 write KEYWORD2 endTransmission KEYWORD2 diff --git a/src/ArduinoModbus.h b/src/ArduinoModbus.h index 41f1615..deaed3e 100644 --- a/src/ArduinoModbus.h +++ b/src/ArduinoModbus.h @@ -20,6 +20,7 @@ #ifndef _ARDUINO_MODBUS_H_INCLUDED #define _ARDUINO_MODBUS_H_INCLUDED +#include "ModbusRTUDelay.h" #include "ModbusRTUClient.h" #include "ModbusRTUServer.h" diff --git a/src/ModbusRTUDelay.h b/src/ModbusRTUDelay.h new file mode 100644 index 0000000..929e287 --- /dev/null +++ b/src/ModbusRTUDelay.h @@ -0,0 +1,50 @@ +/* + This file is part of the ArduinoModbus library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _MODBUS_RTU_DELAY_H_INCLUDED +#define _MODBUS_RTU_DELAY_H_INCLUDED + +class ModbusRTUDelay +{ +public: + /* Do not allow construction or copying. */ + ModbusRTUDelay() = delete; + ModbusRTUDelay(ModbusRTUDelay const &) = delete; + + /* Calculate __minimum__ preDelay and postDelay in + * microseconds as per Modbus RTU Specification. + * + * MODBUS over serial line specification and implementation guide V1.02 + * Paragraph 2.5.1.1 MODBUS Message RTU Framing + * https://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf + */ + static unsigned long const preDelay(unsigned long const baudrate) + { + double const bit_duration = 1. / baudrate; + double const word_len = 9.6f; // try also with 10.0f + double const pre_delay_us = bit_duration * word_len * 3.5f * 1e6; + return static_cast(pre_delay_us); + } + static unsigned long const postDelay(unsigned long const baudrate) + { + return preDelay(baudrate); + } +}; + +#endif /* _MODBUS_RTU_DELAY_H_INCLUDED */ From f6f91274424429e9fe77561b688981ed9eaa6e44 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 31 Oct 2024 13:14:59 +0100 Subject: [PATCH 2/2] Directly set standard-conforming RTU delays inside Modbus library. --- .../ModbusRTUClientParameters/ModbusRTUClientParameters.ino | 2 -- src/ArduinoModbus.h | 1 - src/ModbusRTUClient.cpp | 4 ++++ src/ModbusRTUServer.cpp | 5 +++++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/examples/RTU/ModbusRTUClientParameters/ModbusRTUClientParameters.ino b/examples/RTU/ModbusRTUClientParameters/ModbusRTUClientParameters.ino index 3d50882..ec30e0d 100644 --- a/examples/RTU/ModbusRTUClientParameters/ModbusRTUClientParameters.ino +++ b/examples/RTU/ModbusRTUClientParameters/ModbusRTUClientParameters.ino @@ -22,8 +22,6 @@ void setup() { Serial.println("Modbus RTU Client Toggle w/ Parameters"); - RS485.setDelays(ModbusRTUDelay::preDelay(baudrate), ModbusRTUDelay::postDelay(baudrate)); - // start the Modbus RTU client in 8E1 mode if (!ModbusRTUClient.begin(baudrate, SERIAL_8E1)) { Serial.println("Failed to start Modbus RTU Client!"); diff --git a/src/ArduinoModbus.h b/src/ArduinoModbus.h index deaed3e..41f1615 100644 --- a/src/ArduinoModbus.h +++ b/src/ArduinoModbus.h @@ -20,7 +20,6 @@ #ifndef _ARDUINO_MODBUS_H_INCLUDED #define _ARDUINO_MODBUS_H_INCLUDED -#include "ModbusRTUDelay.h" #include "ModbusRTUClient.h" #include "ModbusRTUServer.h" diff --git a/src/ModbusRTUClient.cpp b/src/ModbusRTUClient.cpp index 2b35227..9e31a27 100644 --- a/src/ModbusRTUClient.cpp +++ b/src/ModbusRTUClient.cpp @@ -26,6 +26,8 @@ extern "C" { #include "ModbusRTUClient.h" +#include "ModbusRTUDelay.h" + ModbusRTUClientClass::ModbusRTUClientClass() : ModbusClient(1000) { @@ -42,6 +44,8 @@ ModbusRTUClientClass::~ModbusRTUClientClass() int ModbusRTUClientClass::begin(unsigned long baudrate, uint16_t config) { + _rs485->setDelays(ModbusRTUDelay::preDelay(baudrate), ModbusRTUDelay::postDelay(baudrate)); + modbus_t* mb = modbus_new_rtu(_rs485, baudrate, config); if (!ModbusClient::begin(mb, 0x00)) { diff --git a/src/ModbusRTUServer.cpp b/src/ModbusRTUServer.cpp index 95cc0b8..836ba7b 100644 --- a/src/ModbusRTUServer.cpp +++ b/src/ModbusRTUServer.cpp @@ -26,6 +26,9 @@ extern "C" { #include "ModbusRTUServer.h" +#include "ModbusRTUDelay.h" + + ModbusRTUServerClass::ModbusRTUServerClass() { } @@ -40,6 +43,8 @@ ModbusRTUServerClass::~ModbusRTUServerClass() int ModbusRTUServerClass::begin(int id, unsigned long baudrate, uint16_t config) { + _rs485->setDelays(ModbusRTUDelay::preDelay(baudrate), ModbusRTUDelay::postDelay(baudrate)); + modbus_t* mb = modbus_new_rtu(_rs485, baudrate, config); if (!ModbusServer::begin(mb, id)) {