cmb27 / modbusrtuslave Goto Github PK
View Code? Open in Web Editor NEWThis is an Arduino library that implements the slave/server logic of the Modbus RTU protocol.
License: MIT License
This is an Arduino library that implements the slave/server logic of the Modbus RTU protocol.
License: MIT License
Great library, all very clear for a simple application. However I've ran into a problem attempting to read/write modbus over serial over usb. I am using a Pro Micro clone. At the PC end I am using qmodmaster.
I can't quite track it down and I was hoping you could shed some light on it.
I have cut down your ModbusRTUSlaveExample.h code so that it just writes a couple of values to the Input Registers and to the Holding Registers, also the one coil is connected to the internal led.
I am not using software serial as i want to use the hardware usb serial. e.g.
ModbusRTUSlave modbus(Serial);
It all works perfectly providing i adopt the following magic spell-
If I miss steps 2 and 3 then the qmodmaster will connect to the port and I can see the tx/rx leds blink once, but attempting to read or write results in a timeout (even if I extend the timeout period to 1second)
I have tried different serial speeds and configurations with the modbus.begin statement to no avail. I also tried putting in a Serial.begin statement which didn't help either.
Any ideas please?
Thanks
I tried this library with ESP32 and found it to be incompatible with ESP32. Can you fix it to be compatible with ESP 32?
Hello Hope your doing well I request you please tell me how do i assign or write address in the program to my slave ardiuno controller whether it is holding address, input register, input status or coil status please support me for the same
What Exception response codes have you defined?
They do not appear conforming to the Modbus spec.
The library sourcecode uses magic values, but that keeps them unexplained.
Hi Chris,
I recently tried to integrate this library for the Raspberry Pi Pico (RP2040) to facilitate Modbus communication. However, despite my best efforts, I've encountered timeout errors, seems like I never receive an answer on the line.
In light of your expertise in this domain, I sended an invitation to my repository. Would you be available to spare a moment and have a quick look at the code I've developed?
Your assistance would be greatly appreciated.
Thank you for considering my request.
From the code and sample, it appears that all uses of register addresses start at zero and end at { numCoils, numDiscreteInputs, numHoldingRegisters, numInputRegisters }
This is not common practice on Modbus.
How did you envision this?
Now there isn't any checking on valid/invalid addresses, and not the proper exception frame can be send when master uses out-of-range addresses.
Hello, @CMB27
Is it possible to use the library with an Arduino Leonardo and the Serial USB?
regards,
Add comments to library code.
Possibly use doxygen.
Hello,
Nice lib you've made, I really like it.
I had some issues trying to communicate in 8E1. I constantly had CRC errors on my debug Modbus RTU console.
I've figure out that the config was in fact not 8E1 but 8N1 (as by default). I've had a look at the code and couldn't find where the parity check is done or written. Is it done somewhere else ? I only had a look in the begin method.
Could you resolve this ?
I'm sorry I couldn't get directly into your code and try resolve.
Regards,
Maxim
Class contains 6 function pointers. These pointers aren't zeroed, nor tested before calling.
Strange things will happen when e.g. no coils are configured and master performs a Modbus Read Coils.
Rename example program.
Possibly make variants of example program, demonstrating customization.
What pins are used for transmit enable and receive enable?
Also what are the UNO pins for TX RX?
minor: rename MobusRTUSlave.cpp to ModbusRTUSlave.cpp
Hi Chris,
I have been working on simple modbus communication but, I haven't succeeded yet. I need your help.
I want to write boolean value from slave and read it from master.
I have two Arduino nano and two TTL rs485 converter.
Both Arduino pin connection;
R0 to RX(D0)
DI to TX(D1)
DE and RE to D2
A to A
B to B
Where is problem? Could you help me?
Slave code
#include "NewPing.h"
#include <ModbusRTUSlave.h>
#define TRIGGER_PIN 9
#define ECHO_PIN 10
#define MAX_DISTANCE 400
#define TRESHOLD_DISTINCE 30 //100
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
float duration, distance;
#define SERIAL_BAUD 38400
#define SERIAL_CONFIG SERIAL_8N1
#define SLAVE_ID 1
#define TXEN 2
ModbusRTUSlave slave(Serial, TXEN);
bool discreteInputs[1];
bool oldStatus = false;
bool newStatus = false;
void setup() {
discreteInputs[0] = false;
Serial.begin( SERIAL_BAUD, SERIAL_8E1 ); // 19200 baud, 8-bits, even, 1-bit stop
slave.configureCoils(discreteInputs, 1);
slave.begin(SLAVE_ID, SERIAL_BAUD, SERIAL_8E1);
}
void loop() {
distance = sonar.ping_cm();
Serial.print("DIST ");
// Send results to Serial Monitor
distance = distance == 0? 400 : distance;
if (distance >= 400 || distance <= 2) {
Serial.print("- |");
} else {
Serial.print(distance);
Serial.print(" | ");
}
if (distance < TRESHOLD_DISTINCE) {
Serial.print(" PARK F | ");
newStatus = true;
} else {
Serial.print(" PARK E | ");
newStatus = false;
}
if (oldStatus != newStatus) {
oldStatus = newStatus;
discreteInputs[0] = newStatus;
}
slave.poll();
Serial.println();
delay(1000);
}
Master code
#include <ModbusRTUMaster.h>
#define SERIAL_BAUD 38400
#define SERIAL_CONFIG SERIAL_8N1
#define TXEN 2
ModbusRTUMaster modbus(Serial, TXEN);
bool discreteInputs[1];
void setup() {
Serial.begin(SERIAL_BAUD);
modbus.begin(SERIAL_BAUD);
}
void loop() {
modbus.readCoils(1, 0, discreteInputs, 1);
uint8_t reesponse = modbus.getExceptionResponse();
Serial.print( reesponse );
Serial.print(" |");
Serial.print(discreteInputs[0]);
Serial.print(" |");
Serial.println();
delay(1000);
}
Best regards,
Seref
If a master node sends a request for more than the number of available registers, this library seems to send a very unexpected response. It just returns a very large, never ending stream of data. Using the code below, with 4 declared input registers, if 5 or more registers are requested by the master the error occurs.
#include <ModbusRTUSlave.h>
#define de PB15
#define re PB14
HardwareSerial rs485_serial(PC7, PC6);
ModbusRTUSlave modbus(rs485_serial, de);
const uint16_t numInputRegisters = 4;
uint16_t inputRegisters [numInputRegisters] = {0};
void setup() {
pinMode(re, OUTPUT);
pinMode(de, OUTPUT);
rs485_serial.begin(19200, SERIAL_8E1);
modbus.begin(1, 19200, SERIAL_8E1);
modbus.configureInputRegisters(inputRegisters, numInputRegisters);
inputRegisters[0] = (uint16_t) 100;
inputRegisters[1] = (uint16_t) 34;
}
void loop() {
modbus.poll();
}
Hi @CMB27
First, Im new in ModbusRTU, frogive me if this is stupid question.
How I can catch when have data changed, i dont want read all data continously
Thank for your useful library
But how i can send and read 32 bit float?
I try send from MCU two 16 bit and config modbus read in 32 bit float but it not working.
Sorry cause my dummy, thanks
First of all: Thank you for providing such a great ModBus-RTU library!
My issue:
I would like to get to know in my code, when a register was written in order to respond to the new "parameter" (in my case) due to the fact that the Arduino serves as a data translator between different protocols.
Is there already a possibility to get to know the register type as well as the register ID?
(I used Version 1 where it was possible, but I would like to upgrade to the newest version of the library)
Could you add a configuration parameter - response delay? The first byte of the response is lost periodicallly.
There seems to be a compile problem with data types for some ARM based boards like RP2040 and STM32.
The example below is Arduino 2 using ModbusRTUSlave
Arduino library V1.0.5 for example file Coils_HardwareSerial.ino
for board Raspberry Pi Pico
using the Arduino Mbed OS RP2040 Boards
core:
C:\Users\xxxx\AppData\Local\Temp\.arduinoIDE-unsaved202364-14620-1k0o4kz.tzqx\Coils_HardwareSerial\Coils_HardwareSerial.ino: In function 'void setup()':
C:\Users\xxxx\AppData\Local\Temp\.arduinoIDE-unsaved202364-14620-1k0o4kz.tzqx\Coils_HardwareSerial\Coils_HardwareSerial.ino:80:54: error: invalid conversion from 'char (*)(unsigned int)' to 'ModbusRTUSlave::BoolRead {aka signed char (*)(short unsigned int)}' [-fpermissive]
modbus.configureCoils(numCoils, coilRead, coilWrite);
^
In file included from C:\Users\xxxx\AppData\Local\Temp\.arduinoIDE-unsaved202364-14620-1k0o4kz.tzqx\Coils_HardwareSerial\Coils_HardwareSerial.ino:28:0:
c:\proj\Arduino\libraries\ModbusRTUSlave\src/ModbusRTUSlave.h:15:10: note: initializing argument 2 of 'void ModbusRTUSlave::configureCoils(uint16_t, ModbusRTUSlave::BoolRead, ModbusRTUSlave::BoolWrite)'
void configureCoils(uint16_t numCoils, BoolRead coilRead, BoolWrite coilWrite);
^~~~~~~~~~~~~~
C:\Users\xxxx\AppData\Local\Temp\.arduinoIDE-unsaved202364-14620-1k0o4kz.tzqx\Coils_HardwareSerial\Coils_HardwareSerial.ino:80:54: error: invalid conversion from 'boolean (*)(unsigned int, boolean) {aka bool (*)(unsigned int, bool)}' to 'ModbusRTUSlave::BoolWrite {aka bool (*)(short unsigned int, bool)}' [-fpermissive]
modbus.configureCoils(numCoils, coilRead, coilWrite);
^
In file included from C:\Users\xxxx\AppData\Local\Temp\.arduinoIDE-unsaved202364-14620-1k0o4kz.tzqx\Coils_HardwareSerial\Coils_HardwareSerial.ino:28:0:
c:\proj\Arduino\libraries\ModbusRTUSlave\src/ModbusRTUSlave.h:15:10: note: initializing argument 3 of 'void ModbusRTUSlave::configureCoils(uint16_t, ModbusRTUSlave::BoolRead, ModbusRTUSlave::BoolWrite)'
void configureCoils(uint16_t numCoils, BoolRead coilRead, BoolWrite coilWrite);
^~~~~~~~~~~~~~
exit status 1
Compilation error: invalid conversion from 'char (*)(unsigned int)' to 'ModbusRTUSlave::BoolRead {aka signed char (*)(short unsigned int)}' [-fpermissive]
Similar compile problems also for STM32. Would be good to support the newer ARM based processors as AVR has supply chain issues and is old/expensive technology.
Hello,
I try to use the library on an arduino Mega 2560 @ 16MHz.
Here ist the example file modified for my application.
Changes:
#include "Arduino.h"
/*
ModbusRTUSlaveExample
This example demonstrates how to setup and use the ModbusRTUSlave library.
It is intended to be used with a second board running ModbusRTUMasterExample from the ModbusRTUMaster library.
Circuit:
- A pushbutton switch from pin 2 to GND
- A pushbutton switch from pin 3 to GND
- A LED from pin 5 to GND with a 330 ohm series resistor
- A LED from pin 6 to GND with a 330 ohm series resistor
- A LED from pin 7 to GND with a 330 ohm series resistor
- A LED from pin 8 to GND with a 330 ohm series resistor
- The center pin of a potentiometer to pin A0, and the outside pins of the potentiometer to 5V and GND
- The center pin of a potentiometer to pin A0, and the outside pins of the potentiometer to 5V and GND
!!! If your board's logic voltage is 3.3V, use 3.3V instead of 5V; if in doubt use the IOREF pin !!!
- Pin 10 to pin 11 of the master/client board
- Pin 11 to pin 10 of the master/client board
- GND to GND of the master/client board
A schematic and illustration of the circuit is in the extras folder of the ModbusRTUSlave library.
- Pin 13 is set up as the driver enable pin. This pin will be HIGH whenever the board is transmitting.
Created: 2023-07-22
By: C. M. Bulliner
Modified: 2023-07-29
By: C. M. Bulliner
*/
#include <SoftwareSerial.h>
#include <ModbusRTUSlave.h>
const byte ledPins[4] = {47, 46, 45, 43};
const byte buttonPins[2] = {15, 14};
const byte potPins[2] = {A0, A1};
const uint8_t rxPin = 0;
const uint8_t txPin = 1;
const uint8_t dePin = 2;
SoftwareSerial mySerial(rxPin, txPin);
ModbusRTUSlave modbus(mySerial, dePin); // serial port, driver enable pin for rs-485 (optional)
bool coils[2];
bool discreteInputs[2];
uint16_t holdingRegisters[2];
uint16_t inputRegisters[2];
void setup() {
pinMode(ledPins[0], OUTPUT);
pinMode(ledPins[1], OUTPUT);
pinMode(ledPins[2], OUTPUT);
pinMode(ledPins[3], OUTPUT);
pinMode(buttonPins[0], INPUT_PULLUP);
pinMode(buttonPins[1], INPUT_PULLUP);
pinMode(potPins[0], INPUT);
pinMode(potPins[1], INPUT);
modbus.configureCoils(coils, 2); // bool array of coil values, number of coils
modbus.configureDiscreteInputs(discreteInputs, 2); // bool array of discrete input values, number of discrete inputs
modbus.configureHoldingRegisters(holdingRegisters, 2); // unsigned 16 bit integer array of holding register values, number of holding registers
modbus.configureInputRegisters(inputRegisters, 2); // unsigned 16 bit integer array of input register values, number of input registers
modbus.begin(1, 9600); // slave id, baud rate, config (optional)
}
void loop() {
discreteInputs[0] = !digitalRead(buttonPins[0]);
discreteInputs[1] = !digitalRead(buttonPins[1]);
inputRegisters[0] = map(analogRead(potPins[0]), 0, 1023, 0, 255);
inputRegisters[1] = map(analogRead(potPins[1]), 0, 1023, 0, 255);
modbus.poll();
digitalWrite(ledPins[0], coils[0]);
digitalWrite(ledPins[1], coils[1]);
analogWrite(ledPins[2], holdingRegisters[0]);
analogWrite(ledPins[3], holdingRegisters[1]);
}
From a Modbus terminal program I generate a modbus message to write a single coil (0) to value 1.
This is sent from the PC to the Arduino 2560 via a USB --> RS485 adapter.
On the Board the RS485 is decoded to TTL using a MAX487.
At the output of this converter the signal is fed directly into (physical) PIN 2 = Arduino PIN 0.
Here is a Scope measurement directly on the processor pin:
What is the result:
Therefore I conclude, that the library is initializing correctly. When I select another (wrong) pin in the sketch, the dirctional pin stays on high (there is a 10k pullup resistor).
But then ... nothing happens. No response is being generated on TX0, The direction is not changed on the directional pin. The board is not reacting at all.
Questions:
Regards
Alexander
hi sir
Pico board used receive data from plc id 01 t0 06
recive interval -100ms
Modbus library support minimum 300ms duration working
how to read data 100ms speed?
example your code
#include <ModbusRTUSlave.h>
ModbusRTUSlave modbus(Serial1, 255); // serial port, driver enable pin for rs-485
uint16_t holdingRegisters[2];
union {
uint16_t bytes[2];
float x;
} Float_data_1;
void setup() {
modbus.configureHoldingRegisters(holdingRegisters, 2); // unsigned 16 bit integer array of holding register values, number of holding registers
modbus.begin(1, 9600);
Serial.begin(9600);
}
void loop() {
modbus.poll();
// Split holdingRegisters[0] and holdingRegisters[1]
Float_data_1.bytes[0] = holdingRegisters[1];
Float_data_1.bytes[1] = holdingRegisters[0];
Serial.println(Float_data_1.x); // Print the float value
}
hir sir
****read unsigned holding register working fine below codeusing Pico rp2040
how to read 32bit float value ?
please help me
#include <ModbusRTUSlave.h>
ModbusRTUSlave modbus(Serial1, 255); // serial port, driver enable pin for rs-485
uint16_t holdingRegisters[2];
void setup() {
modbus.configureHoldingRegisters(holdingRegisters, 2); // unsigned 16 bit integer array of holding register values, number of holding registers
modbus.begin(1, 9600);
}
void loop() {
modbus.poll();
Serial.println(holdingRegisters[0]);
delay(100);
}
Hi, I am trying found a ideal RTU modbus library. Now, I am trying an example, on Arduino Mega 2560 ( Later on ESP32 ). As a master is a PC with QModBus. Between PC and Ardino is a converter with Tx En. On any ask from a PC, I get some data, but always with CRC Error.
#include <ModbusRTUSlave.h>
const byte buttonPins[2] = {2, 3};
const byte ledPins[4] = {5, 6, 7, 8};
//HardwareSerial RS485(1);
ModbusRTUSlave modbus( Serial1 , 13 ); // serial port, driver enable pin for rs-485
bool coils[2];
bool discreteInputs[2];
uint16_t holdingRegisters[2];
uint16_t inputRegisters[2];
void setup() {
Serial1.begin( 9600 );
pinMode(buttonPins[0], INPUT_PULLUP);
pinMode(buttonPins[1], INPUT_PULLUP);
pinMode(ledPins[0], OUTPUT);
pinMode(ledPins[1], OUTPUT);
pinMode(ledPins[2], OUTPUT);
pinMode(ledPins[3], OUTPUT);
modbus.configureCoils(coils, 2); // bool array of coil values, number of coils
modbus.configureDiscreteInputs(discreteInputs, 2); // bool array of discrete input values, number of discrete inputs
modbus.configureHoldingRegisters(holdingRegisters, 2); // unsigned 16 bit integer array of holding register values, number of holding registers
modbus.configureInputRegisters(inputRegisters, 2); // unsigned 16 bit integer array of input register values, number of input registers
modbus.begin( 1 , 9600);
}
void loop() {
inputRegisters[0] = 500;
inputRegisters[1] = 550;
discreteInputs[0] = !digitalRead(buttonPins[0]);
discreteInputs[1] = !digitalRead(buttonPins[1]);
modbus.poll();
analogWrite(ledPins[0], holdingRegisters[0]);
analogWrite(ledPins[1], holdingRegisters[1]);
digitalWrite(ledPins[2], coils[0]);
digitalWrite(ledPins[3], coils[1]);
}
Hi Chris,
it has to do something with Stream library - flush returns before write is completed I guess.
With enable pin I had to insert additional delay when going to low with pin.
I implemented a while loop with chartimeout variable in case flush ends too early.
I tested it with my UNO Rev4 minima only and DFRobot RS485 shield (BTW shield in auto mode it works perfectly without any changes to library)
void ModbusRTUSlave::_writeResponse(uint8_t len) {
unsigned long startTime = 0;
if (_buf[0] != 0) {
uint16_t crc = _crc(len);
_buf[len] = lowByte(crc);
_buf[len + 1] = highByte(crc);
if (_dePin != NO_DE_PIN) digitalWrite(_dePin, HIGH);
startTime = micros();
_serial->write(_buf, len + 2);
_serial->flush();
while (micros() - startTime < (_charTimeout * (len + 2)));
if (_dePin != NO_DE_PIN) digitalWrite(_dePin, LOW);
while(_serial->available()) {
_serial->read();
}
}
}
Regards,
Michal
I kept getting exception code 2 on reading input registers despite everything else working out. finally on inspection of the library code I found the culprit on line 185 of ModbusRTUSlave.cpp. The line reads
else if (quantity > _numDiscreteInputs || startAddress > (_numInputRegisters - quantity)) _exceptionResponse(2);
how ever changing it to
else if (quantity > _numInputRegisters || startAddress > (_numInputRegisters - quantity)) _exceptionResponse(2);
fixed the issue for me and the library is working perfectly now.
There's an error on Line 190 in ModbusRTUSlave.cpp inside the _processReadInputRegisters()
function. It currently reads:
else if (quantity > _numDiscreteInputs || startAddress > (_numInputRegisters - quantity)) _exceptionResponse(2);
and it should read:
else if (quantity > _numInputRegisters || startAddress > (_numInputRegisters - quantity)) _exceptionResponse(2);
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.