Git Product home page Git Product logo

emelianov / modbus-esp8266 Goto Github PK

View Code? Open in Web Editor NEW

This project forked from andresarmento/modbus-esp8266

503.0 34.0 183.0 530 KB

Most complete Modbus library for Arduino. A library that allows your Arduino board to communicate via Modbus protocol, acting as a master, slave or both. Supports network transport (Modbus TCP) and Serial line/RS-485 (Modbus RTU). Supports Modbus TCP Security for ESP8266/ESP32.

License: Other

C++ 88.80% C 11.08% CMake 0.12%
arduino-library modbus-tcp esp8266 esp32 modbus-master modbus-slave modbus-rtu modbus-client modbus-server modbus-serial modbus modbus-protocol modbus-library modbus-tcp-security

modbus-esp8266's Introduction

Modbus Library for Arduino

ModbusRTU, ModbusTCP and ModbusTCP Security

For detailes on the library usage visit documentation section.

Features

Notes

  1. The offsets for registers are 0-based. So be careful when setting your supervisory system or your testing software. For example, in ScadaBR offsets are 0-based, then, a register configured as 100 in the library is set to 100 in ScadaBR. On the other hand, in the CAS Modbus Scanner offsets are 1-based, so a register configured as 100 in library should be 101 in this software.
  2. RS-485 transivers based on MAX-485 is working on at least up to 115200. XY-017/XY-485 working only up to 9600 for some reason.

For more information about Modbus see:

Last Changes

// 4.1.1
+ Protocol: Fix wrong error code responce on non-existent register
+ ModbusTCP: Fix potential memory leak
+ API: cbEnable/cbDisable functionality extended
+ ESP-IDF: CMakeList.txt added
+ Examples: TCP-to-RTU fixed
// 4.1.0
+ API: Raw Modbus frame processing functionality
+ ModbusRTU: Precise inter-frame interval control
+ Examples: True ModbusRTU to ModbusTCP Server bridge
+ Examples: ModbusRTU respond to multiple ID from single device
+ ModbusRTU: Add direction control pin for Stream
+ STL: Add Reg count limitation to vector limit of 4000 (for ESP8266 and ESP32)
+ Settings: Added MODBUSIP_CONNECTION_TIMEOUT (ESP32 only)
+ Settings: Set MODBUSIP_MAX_CLIENTS = 8 for ESP32
+ ModbusTCP: Make using DNS names optional feature
+ ModbusRTU: Add separate RE/DE pins control optional feature
+ API: Drop support of Ethernet library v1
+ Examples: Teknic ClearCore ArduinoWrapper examples added
+ Examples: ModbusTCP to ModbusRTU example added
+ ModbusRTU: Flush extra delay optional feature
// 4.0.0
+ Support of all Arduino boards
+ ModbusTLS: ESP8266 Client/Server and ESP32 Client
+ ModbusTCP: ModbusEthernet - WizNet W5x00, ENC28J60 Ethernet library support
+ 0x14 - Read File Records function
+ 0x15 - Write File Records function
+ Examples: FW update over Modbus fullfunctional example
+ 0x16 - Write Mask Register function+ Test: 0x16
+ 0x17 - Read/Write Registers function
+ ModbusRTU: ESP32 SoftwareSerial support
+ Build with no STL dependency (switchable)
+ API: ModbusIP => ModbusTCP
+ API: Access control callback for individual Modbus function
+ API: Master/Slave => Client/Server according to [PRESS RELEASE](https://modbus.org/docs/Client-ServerPR-07-2020-final.docx.pdf)
+ Lot of code refacting and small fixes

Roadmap

// 4.2.0
- API: Alternative CRC calulation (reduced memory footprint)
- ModbusRTU: Static buffer allocation
- Test: Frame accuracy to specefication
- Buffer/packet size limitation support
- Slave/Server: slavePDU use early exit by return where possible
- Master/Client: Check frame size against header data where possible
- Master/Client: Additional responce data validation
- Free global registers and callbacks on remove last Modbus instance
- Test: push/pull functions
- ModbusTCP: Refactor connect by dns name (using native implementation for ESP32 etc)
// 4.3.0
- ModbusTLS: ESP32 Server
- Test: TLS ESP32 Server
- Test: TLS ESP32 Client
- Examples: TLS Certificate test Role extension and Alt-Name
- Examples: TLS Add example explanation
- ModbusTCP: ModbusAsyncTCP
- API: Extend API to allow custom Modbus commands
- Examples: Basic file operations
- Examples: Revising

Contributions

https://github.com/emelianov/modbus-esp8266

[email protected]

Original version:

https://github.com/andresarmento/modbus-esp8266

https://github.com/andresarmento/modbus-arduino

prof (at) andresarmento (dot) com

License

The code in this repo is licensed under the BSD New License. See LICENSE.txt for more info.

modbus-esp8266's People

Contributors

alepiva avatar alexbarcelo avatar andresarmento avatar arekkubacki avatar basisbit avatar brainelectronics avatar emelianov avatar emerout avatar escherstair avatar gonzabrusco avatar lmartorella avatar mako777 avatar per1234 avatar peterembedded avatar rob040 avatar tienhuyiot avatar vondraussen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

modbus-esp8266's Issues

Modbus RTU

Hello,

do you plan to make Modbus RTU support? I couldn't find a stably working library.

Problem reading multiple non-sequential addresses RTU

Hello, first congratulations on the work!
I am communicating an ESP8266 (NodeMCU) via RTU with a device that is running on RS485 or RS232.
When I send read multiple regs in a single request sequential everything goes perfectly, as in the code:

`uint16_t res[100];

void loop() {
if (!mb.slave()) {
mb.readHreg(10, 50, &res[0], 100, cbWrite);
for (int i = 0; i < dados; i++) {
Serial.println(res[i]);
res[i] = 0;
}
}
mb.task();
yield();
}

But, I have problems when I want to read at specific addresses, how can I read single regs?
Here is an example, I want to read the regs at addresses 50, 100 and 300 of the same slave

uint16_t res[1];
uint16_t esc[1];
uint16_t tes[1];

void loop() {
if (!mb.slave()) {
mb.readHreg(10, 50, &res[0], 1, cbWrite);
Serial.println(res[0]);
mb.readHreg(10, 100, &esc[0], 1, cbWrite);
Serial.println(esc[0]);
mb.readHreg(10, 300, &tes[0], 1, cbWrite);
Serial.println(tes[0]);
}
mb.task();
yield();
}`

Thank you very much!

bool ModbusIP::disconnect(IPAddress ip) returns nothing

Got compilation error on this version when tried to compile on VS17+VisualMicro:
ModbusIP_ESP8266.cpp: 410:1: error: no return statement in function returning non-void [-Werror=return-type]
and that's TRUE :-(
bool ModbusIP::disconnect(IPAddress ip) { int8_t p = getSlave(ip); if (p != -1) client[p]->stop(); }

and it is compiled correctly under Arduino IDE... :-)

ESP32S not working with modbus TCP Server

Hi, im trying to make TCP server to work with a client in Java, i have tested that client with the EasyModbusTCP simulator,
my device is a ESP32S (NodeMCU-32S) the server starts correctly, i am debuggin with the callback fuctions and the
connection from the client is arriving, but the read on the register is not working.

The test is based on the Test Holding Register example, i just changed it to Input Register.

Regards

`
#ifdef ESP8266
#include <ESP8266WiFi.h>
#else //ESP32
#include <WiFi.h>
#endif
#include <ModbusIP_ESP8266.h>

//ModbusIP object
ModbusIP mb;

bool cbConn(IPAddress ip) {
Serial.println(ip);
return true;
}

uint16_t cbMod(TRegister* reg, uint16_t val){

Serial.println("Val: "+val);
return true;
}

void setup() {
Serial.begin(115200);

WiFi.begin("anynet", "1245787845");

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());

mb.onConnect(cbConn);
mb.onGetIreg(0,cbMod);
mb.onGetIreg(1,cbMod);
mb.onGetIreg(2,cbMod);
mb.server();
mb.addIreg(1, 0);
mb.addIreg(2, 17151);

}

void loop() {
//Call once inside loop() - all magic here
mb.task();
delay(10);
}`

Read a flow sensor with modbus RTU

Hello togehter,

First of all, I'm a newbie in programming ESP32 with Arduino IDE. My target is to read the air flow from the a sensor with the modbus protocol.

I found out the following details for Modbus-configuration:

Transmission speed: 9600 BAUD
Start bit: 1
Data bits: 8
Stop bit: 2
parity: no
adress: 247 (no LED reaction on sensor fo communcation, I used 0)
Function: 03 (read holding register)
register: 0x0000 - 0x0001
value-format: float32

I use this code with Arduino IDE on M5Stack-Core with PLC-module:

#include <ModbusRTU.h>
uint32_t res = 0;
ModbusRTU mb;

void setup() {
Serial.begin(115200);
Serial2.begin(9600, SERIAL_8N2, 16, 17);
mb.begin(&Serial2);
mb.master();
}

void loop() {
mb.readHreg(0, 0, (uint16_t*)&res, 2, nullptr);
mb.task();
delay(100);
res = (res>>16) | (res<<16);
Serial.println(res);
}

Can you help me with that issue?

Modbus TCP

how to read value from register? on code masterSimpleRead write mb.readHreg, but on Serial.print just show Number aregister RES only and value on Reg on Res is empty/blank

static IPfor ESP8266

I need to use static IP for ESP8266 and add the following commands:
staticIP224_60(192,168,1,60);
IPAddress gateway224_60(192,168,1,1);
IPAddress subnet224_60(255,255,255,0);
void setup() { Serial.begin(9600);
WiFi.config(staticIP224_60, gateway224_60, subnet224_60) what is the wrong?

after that ESP connected with router but plc and modbus poll software both not connected with ESP and give error "time out" IPAddress.
Can you help me?

[documentation improvement] Supplying multiple registers from callback when running as slave

I couldn't really find in the documentation on how to use the callbacks in combination to using a multiple of registers, and it took me some time before i got this working. Maybe it is an idea to add some example to the documentation?

For reference, this is how i did it:

// To define something that has multiple registers, like an ip address:
mbIPSlave.addIreg(1000, 0, 4);
// Adding the callback with 4 registers, will mean that the same callback will be called once for every register.
mbIPSlave.onGetIreg(1000, cbReadWiFiIP, 4); 

And the callback itself:

uint16_t cbReadWiFiIP(TRegister *reg, uint16_t val)
{

    switch (reg->address.address)
    {
    case MB_ADDR_IP:
        // Get the first octet of the local ip address (uint8_t), and cast it to uint16_t
        val = static_cast<uint16_t>(WiFi.localIP()[0]);
        break;
    case MB_ADDR_IP + 1:
        val = static_cast<uint16_t>(WiFi.localIP()[1]);
        break;
    case MB_ADDR_IP + 2:
        val = static_cast<uint16_t>(WiFi.localIP()[2]);
        break;
    case MB_ADDR_IP + 3:
        val = static_cast<uint16_t>(WiFi.localIP()[3]);
        break;
    default:
        break;
    }
    return val;
}

ESP8266 MEMORY ADDRESS

Thank you for this library.
I have ESP8266 programmed to operate at MODBUS TCP / IP and PLC (LSIS) connected to router by Ethernet MODBUS. I made connection between them successfully (using P2P service found in PLC) through router, but the connection produce error. P2P service used to make connection between LSIS devices and other devices. This service requires inter the read and write memory address for ESP8266 with condition that the address must has 5 digit. Knowing that I use simple diode connection on GPIO pin-14. The problem is when I search for ESP8266 memory map addresses, I find it (0x60000360) 8 digit and this return error from PLC side. I dont know how to make reduction for ESP8266 register address .
Please help me.

Unable to get response with Modbus poll and ESP32 (as a RTU slave)

Hello,
First of all thank you for the library ,i think it's a detailed library.

I,m using ESP32 with arduino IDE .I try to use RTU_SLAVE.ino with UART2.I design a board and connect GPIO16,17 (Uart 2) to MAX3485 .but this examlpe doesn't work.what is the problem?
here is my code i just change the uart:
`
#include <ModbusRTU.h>

#define REGN 10
#define SLAVE_ID 1

ModbusRTU mb;

void setup() {
Serial2.begin(9600, SERIAL_8N1);
mb.begin(&Serial2);
mb.slave(SLAVE_ID);
mb.addHreg(REGN);
mb.Hreg(REGN, 100);

}

void loop() {
mb.task();
yield();
}`

I must be missing a simple thing here...

First of all, thank you for your work in putting this library together. I'm a controls engineer and PLC programmer and am on ly over here in C++ Land when I have to be (like now). I (using an ESP8266 as the master/client) am trying to understand how to read multiple, contiguous holding registers from a PLC. I started with your MasterSimpleRead example and I am able to read any single register, but I cannot understand how to do multiples. If I tack on another input parameter onto the "mb.readHReg" call at line 49 and set it to 2 for example I compile OK and run but, of course, only one register value comes back. I'm thinking that my syntax is OK, but that I'm using an incorrect variable type to put the 2 registers of data into. Should I be using an array of 16 bit words instead of a single word, and if so, how? My apologies for asking a question that might be an obvious thing to a C++ guy, but I'm stumped here today.

Using TCP and RTU with common Registers

First of all I find this tool extremely helpful and thank you very much for providing it.

I am currently working on a project where I would like to enable access to Modbus registers via Modbus TCP as well as via RTU simultaneously (parallel operation). This allows a flexible and comfortable use.

My question:
To save resources I would like to create the Modbus registers only once (addHreg, addCoil, addIsts, addIreg). Is that possible? If so, what do I have to consider?

Help please

I have a plc to ip 192.168.1.200 and id 3. I need to read the holding registry on 30775 address, but is a 32 bit value?? How i can do it??

Modbus TCP client Write Multiple Register --- strange behavior ---

Hi emelianov,

thanks for sharing this library...
I have tested an ESP32 with the following program, I am very happy to see that it works very well. I tried several modbus TCP client (master) and unfortunately I discovered a problem.

When I write from client bit1 true, with a polling time of 0.1 seconds, the reading of the state of this bit is not stable, in the sense that sometimes it works well, but very often it starts to malfunction. The strange behavior is that only when I read (in the arduino program) the bit1 of the first word 110 that is not written to 1 by the client is read to 0 by the arduino program see bitRead (TgrPak_RX.CMD, 1)

If I change the BIT1 with any other word BIT, it works perfectly even with 0.1 second polling.

I do not understand where the problem is, could you help me?

`#ifdef ESP8266
#include <ESP8266WiFi.h>
#else
#include <WiFi.h>
#endif
#include <ModbusIP_ESP8266.h>

// Modbus Registers Offsets (0-9999)
const int TEST_HREG = 100;
//ModbusIP object
ModbusIP mb;

const int LED_PIN = 2;

typedef struct
{
uint16_t CMD; // Word di comando (16 bit comandi)
unsigned long Tempo; // Tempo in millisecondi
uint16_t ris1; // Riserva
uint16_t ris2; // Riserva
}
TelegrammaDef_TX;
TelegrammaDef_TX TgrPak_TX;

typedef struct
{
uint16_t CMD; // Word di comando (16 bit comandi)
unsigned long Tempo; // Tempo in millisecondi
uint16_t ris1; // Riserva
uint16_t ris2; // Riserva
}
TelegrammaDef_RX;
TelegrammaDef_RX TgrPak_RX;

// NETWORK: Static IP details...
IPAddress ip(192, 168, 2, 191);
IPAddress gateway(192, 168, 2, 1);
IPAddress subnet(255, 255, 255, 0);

static bool MFP1 ; // Merker Fronte di salita
unsigned long MemoTempo;
uint16_t buff_TX[sizeof(TgrPak_TX)/2];
uint16_t buff_RX[sizeof(TgrPak_RX)/2];

void setup() {
Serial.begin(74880);
pinMode(LED_PIN,OUTPUT);

// Static IP Setup Info Here...
WiFi.config(ip, gateway, subnet);
WiFi.begin("SSID", "password");

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());

mb.begin();
mb.addHreg(TEST_HREG, 0x0000, 20);
}

void loop() {
//Call once inside loop() - all magic here
mb.task();

// Write
uint16_t word_app=TgrPak_TX.Tempo>>16;
mb.Hreg(100, TgrPak_TX.CMD);
mb.Hreg(101, word_app);
mb.Hreg(102, (uint16_t)TgrPak_TX.Tempo);

// Read
TgrPak_RX.CMD = mb.Hreg(110);

// Watchdog
if(bitRead(TgrPak_RX.CMD, 0)) bitSet(TgrPak_TX.CMD, 0);
else bitClear(TgrPak_TX.CMD, 0);

// Test 1
if(bitRead(TgrPak_RX.CMD, 1)){
bitSet(TgrPak_TX.CMD, 1);
digitalWrite(LED_PIN, HIGH);
}
else {
bitClear(TgrPak_TX.CMD, 1);
digitalWrite(LED_PIN, LOW);
}

if(!MFP1 && bitRead(TgrPak_RX.CMD, 1)){
MemoTempo = millis();
MFP1=true;
}
if(!bitRead(TgrPak_RX.CMD, 1)) MFP1=false;
if(MFP1) TgrPak_TX.Tempo = millis() - MemoTempo ;

} // Loop`

modbus TCP/IP network

Hi,
I want try to build my own modbus TCP/IP network over wifi using ESP8266(as master and slaves).
I want to use 8 slaves with connected temperature sensors.
Master should read data from each slave every 300ms and print them on serial.
Can I do it with your library?
I cant find any example ...
thank you
pptsk

Usage of std:function / std::bind

Hello, first of all the library is great ... it saved me hours of hard work
The only thing i wasn't able to figure out how to handle is about the way cbTransaction is declared

typedef bool (*cbTransaction)(Modbus::ResultCode event, uint16_t transactionId, void* data); // Callback skeleton for requests

I work with classes/objects, in fact this library too, but i was not able to use an object method as cbTransaction callback. I used to work with std:function and std::bind for this pourpose.
I do something like this when working with callbacks:

this->onReadCallback = std::bind(&MyClass::onRead, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
this->modbus = new ModbusRTU();
// modbus initialization ... bla bla
// then ...
this->modbus->readHreg(1, 300, this->regValue, 1, this->onReadCallback);

Is there any way to do it with the current declaration/definition of cbTransaction ?

Thanks

Why #define MB_MAX_REGS 32 ?

Why the number of registers is hard limited to 32? Do you expect perfromance problems for more registers on ESP8266?

Write multiple holding register, func 16

Hi, I'm having difficulties with writing to multiple registers. I'm using mb.writeHreg function and testing the transfer with Modbus slave Windows utility. Function is transferring every even number correctly, but odd numbers are random and they're changing. Please find screenshot and code bellow. Thanks for advice

mb

` #include <ESP8266WiFi.h>
#include <ModbusIP_ESP8266.h>

// Modbus Registers Offsets
const int REG = 256; // Modbus register offset
const int COUNT = 19; // Count of Coils

IPAddress remote(192, 168, 1, 10); // Address of Modbus Slave device

//ModbusIP object
ModbusIP mb;

void setup() {
Serial.begin(74880);

WiFi.begin("xxxx", "xxxx");

mb.master();
}

uint16_t res1,res2,res3,res4 = 0;
uint16_t zero = 0;
uint16_t res[COUNT] = {3232,3211,3039,3732,3030,4531,3643,3631,3639,4236,3944,4242,3535,3842,3436,3833,3631,3746,0};;

void loop() {
if (mb.isConnected(remote)) { // Check if connection to Modbus Slave is established
mb.writeHreg(remote, REG, res, COUNT);

mb.readHreg(remote, 16448, &res1);  
mb.readHreg(remote, 16449, &res2);  
mb.readHreg(remote, 16450, &res3);
mb.readHreg(remote, 16451, &res4);   

} else {
mb.connect(remote); // Try to connect if no connection
}

mb.task();
delay(100);

Serial.println(res1);
Serial.println(res2);
Serial.println(res3);
Serial.println(res4);

}`

MODBUS RTU Master receive \0

Hi,

I try to read some info (fan name) from a modbus rtu slave in the setup() of a sketch and I'm doing this to do some testing:

uint16_t fanType[6] = {0, 0, 0, 0, 0, 0};
char fanType_hex[2];
String fanTypeName = "";

Serial2.begin(19200, SERIAL_8E1, RXD, TXD);
mb.begin(&Serial2, RXTXEnablePin);
mb.master();

if (!mb.slave()) {
mb.readHreg(SLAVE_ID, FanType, fanType, 6, NULL);
// I think I need to wait here as this is done in setup()
while (mb.slave()) mb.task();

for (int8_t i = 0; i <= 5; i++) {
  Serial.println(fanType[i], HEX);
  fanType[i] = (fanType[i]>>8 | fanType[i]<<8);
  Serial.println((fanType[i]>>8) &0xFF);
  Serial.println(fanType[i] & 0xFF);
  sprintf(fanType_hex, "%02X", fanType[i]); 
  Serial.println(fanType_hex);
  fanTypeName += fanType_hex;
}

Serial.println(fanTypeName);
}

I receive 6 uint16_t values as expected, but one of the values is "missing".

This is the result:

334B
75
51
4B33
3200
0
50
32
3035
53
48
3530
5252
82
82
5252
3130
48
49
3031
0
0
0
00
4B333235305252303100

The second uint16_t is: 3200 (00 = \0) but if I read it with another MODBUS RTU controller I can see the value is really 3247 ("2G") which is part of the model name of the slave.

Any insights into why this can be?

Thank you in advance.

MODBUSIP_UNIT is Hardcoded

Hello,
the MODBUSIP_UNIT is hardcoded to 255, is it possible to change the code that at a read (Hreg, Ireg) the Unit is passed to the function?
I have a Victron Solarsystem where a single IP has many Units, so hardcoded is a problem as i need to read from many different Units to collect my data.
Regards,
Sander van Noort

ESP32 as a slave But it had no response

hi,
i studied some days ,ESP32 as a master ,the sysem was good,use modbus slave can see the communication result.
but now i use the ESP32 as a slave ,use modbus poll as a master ,it had faults,timeout error.
I used MAX485,so I seted the baud 115200.

`#include <ModbusRTU.h>
#include <HardwareSerial.h>
#define REGN 10
#define SLAVE_ID 1
#define BAUD 115200

ModbusRTU mb;
HardwareSerial mySerial1(1);
void setup() {
//Serial.begin(9600, SERIAL_8N1);
mySerial1.begin(BAUD,SERIAL_8N1,5,18);
#if defined(ESP32) || defined(ESP8266)
mb.begin(&mySerial1,16);//16 is the control pin
#else
mb.begin(&mySerial1,16);
mb.setBaudrate(BAUD);
#endif
mb.slave(SLAVE_ID);
mb.addHreg(REGN);
mb.Hreg(REGN, 100);

}

void loop() {
mb.task();
yield();
}`
thanks!

Not obvious examples.

Hi! First of all thanks for this amasing lib. I don't have the luck to try it out because some minor things.

I have a sample sketch:

#include <ModbusRTU.h>
ModbusRTU mb;

bool cbWrite(Modbus::ResultCode event, uint16_t transactionId, void* data) {
  String Cucc = String(event);
  Cucc += "id: ";
  Cucc += String(transactionId);
  //Cucc += "Data: ";
  //Cucc += String(data);
  Send_Async(Cucc,"~ModBus");
  return true;
}

void Pupu(){
  Serial.begin(115200, SERIAL_8N1);
  mb.begin(&Serial,5);
  mb.master();
}

long proba = millis();
void Proba(){
  if(millis() - proba >= 1000){
    proba = millis();
    //mb.readHreg(11,0,&Start_In_Reg_Address,Reg_Count,cbWrite);
    if (!mb.slave()) {
      mb.writeHreg(11,Start_In_Reg_Address,255,1,cbWrite);
    }
  }
  mb.task();
}

void setup(){
  Pupu();
}

void loop(){
  Proba();
}

I want to understand the multi reads and multi writes.
So i'am using esp32 and in my understanding the writing multi reg needs an address, a start reg address, a value to write to the regs and a register count.

This sketch gives me an error:

src\main.cpp:28:57: error: invalid conversion from 'int' to 'uint16_t* {aka short unsigned int*}' [-fpermissive]

Would you be so kind and help me in this situation?

Oh and i also don't understand the void* data in the callback. O_o

RTU on ESP32 not working reliable if mb.task is called too often

If I call the mb.task() function in the void loop() on every loop (and have nearly no other code in the loop) the receiver often fails (but not always).

To better debug it, i added some Serial.prints into the mb.task function:

void ModbusRTU::task() {
	#ifdef ESP32
	if (_len == 0)
		// portENTER_CRITICAL(&mux);
	#endif
    if (_port->available() > _len)	{
        _len = _port->available();
        t = millis();
        Serial.print("L");
        Serial.println(_len);
		return;
    }
    if (_len != 0 && millis() - t < _t) { // Wait data whitespace if there is data
        Serial.print("W.");
        Serial.print(_len);
        Serial.print("D.");
        Serial.println(millis() - t);
        return;
    }

	#ifdef ESP32
    // portEXIT_CRITICAL(&mux);
 	#endif
    if (isMaster) cleanup();
	if (_len == 0)
		return;

    Serial.print("OK");
    Serial.println(_len);
...

I then get this output:

L1
W.1D.0
W.1D.0
W.1D.0
W.1D.0
W.1D.1
W.1D.1
W.1D.1
W.1D.1
W.1D.1
W.1D.1
W.1D.1
W.1D.1
W.1D.1
W.1D.1
W.1D.1
W.1D.1
W.1D.9
W.1D.17
OK1

L12
W.12D.11
OK12

Which means, the mb.task for some reason only gets one byte in _port->available() and then waits until the timeout happens, then tries to parse this one byte, but discards it, because its not valid.
After that it gets the reminding data (12byte) but also discards it, because the 1byte from the first iteration is missing.

If I add a delay(100) in the main-loop it works better, but also not 100% of the time.

ESP32, with platform.io

[env]
platform = espressif32
board = nodemcu-32s
framework = arduino
lib_deps =
    modbus-esp8266

The modbus is on Serial2:

   // Setup ModBus
    Serial2.begin(9600, SERIAL_8N1, MODBUS_RXD, MODBUS_TXD);
    mb.begin(&Serial2, -1);
    mb.slave(SLAVE_ID);
void loop() {
    ArduinoOTA.handle();
    mb.task();
    // otherwise mb.task makes problems?
//        delay(150);
}

Any ideas what could be wrong?

Complete code - working example

Hi,

I'm trying to connect an ESP32 (master) to a motor (slave) using MODBUS RTU and I found this promising project.

As I'm just starting to learn I hope for some help :-)

When connecting the ESP32 to the motor I use an RS485/max485 module like this one: http://www.bizkit.ru/en/2019/02/21/12563/

If I look at how this is to be connected to the ESP32 (also shown in the link above) it seems there is a connection from an ESP32 GPIO to DE and RE (which are shorted). And looking at example code (not using this project) it seems the GPIO has to be set accordingly depending on receiving or sending data to/from RS485.

I have looked through the examples but cannot see this implemented in any code. Therefore the question: How is that to be handled using this project? And is it possible to have a look at some "Arduino" working code (e.g. Master on MODBUS RTU reading from Input registers/writing holding registers)?

Thank you very much in advance.

Question about modbus run in separate tasks! One with continous read and one with a write.

I'am using an esp32. At startup i want to read all the slaves on the bus.

My max slave count is 128, starting address is 10.

I want all my existing slaves in an array to be able to loop on the existing slaves at runtime.
I created this code:

#define MAX_EXPANDERS 128
boolean First_Read_Mode = false;
int Existing_Expanders[MAX_EXPANDERS];
String Ascii_Data = "";
int Exp_Arr_Counter = 0;
uint16_t regs[44];

const char ASCIIARR[] = {
    '0','1','2','3','4','5',
    '6','7','8','9',':',';',
    'A','B','C','D','E','F',
    'G','H','I','J','K','L',
    'M','N','O','P','Q','R',
    'S','T','U','V','W','X',
    'Y','Z','a','b','c','d',
    'e','f','g','h','i','j',
    'k','l','m','n','o','p',
    'q','r','s','t','u','v',
    'w','x','y','z',' ',
  };
const int ASCIINUM[] = {
    48,49,50,51,52,53,
    54,55,56,57,58,59,
    65,66,67,68,69,70,
    71,72,73,74,75,76,
    77,78,79,80,81,82,
    83,84,85,86,87,88,
    89,90,97,98,99,100,
    101,102,103,104,105,106,
    107,108,109,110,111,112,
    113,114,115,116,117,118,
    119,120,121,122,32,
  };

static inline char Get_ASCII(int Data){
    char Found_ASCII;boolean Found = false;
    for(byte i = 0; i < (sizeof(ASCIINUM) / sizeof(ASCIINUM[0])); i++){
        if(ASCIINUM[i] == Data){
        Found_ASCII = ASCIIARR[i];
        Found = true;
        break;
        }
    }
    if(Found){
        return Found_ASCII;
    }else{
        return '-';
    }
}

bool cbRead(Modbus::ResultCode event, uint16_t transactionId, void* data) {
    if(First_Read_Mode){
        for(int i = 0; i < 44;i++){
            if(i == 0){
                Existing_Expanders[Exp_Arr_Counter] = regs[i];
                Exp_Arr_Counter++;
            }else{
                Ascii_Data += Get_ASCII(regs[i]);
            }
        }
    }
  return true;
}

static const inline void Sync_ModBus_Setup(){
    Serial.begin(115200, SERIAL_8N1);
    mb.begin(&Serial,5);
    mb.master();
}

static const inline void Read_All_Expanders(){
    First_Read_Mode = true;
    uint8_t Start_Address = 10;
        for(int i = 0; i < MAX_EXPANDERS;i++){
            mb.readHreg(Start_Address,0x4064,regs,0x2c,cbRead);
            Start_Address++;
            vTaskDelay(10);
        }
    First_Read_Mode = false;
    Exp_Arr_Counter = 0;
}

void ModBus_Task( void * parameter ){
Sync_ModBus_Setup();
Read_All_Expanders();
  for ever{
    Read_Existing_Expanders();
    mb.task();
    vTaskDelay(1);
  }
}

As you can see, at startup the program wants to read all the slaves until it reaches 128 ( max slaves ). When in first readd mode inside the cbRead callback i try to separate the address from the rest of the data. The first data is the address.
The problem is that i don't get any data.

If i define the existing modules like this:

int Existing_Expanders[MAX_EXPANDERS] = {11,14}; // The two slaves currently on the BUS

The reading is working fine.

Is it not recommended to read the slaves inside a for loop?

Reading multible Holding Registers (Question)

I'm trying to read some Holding registers.
for example Register 152. I want to read a 4 bit float. so I have to read numregs=2. But I didnt get it right now.
Is it possible to do that with the Library?

Help getting started with two ESP8266

Hi!

I need some help getting started. I initially was naive and just wanted to connect an esp to a sensor and read it. That did not work so I tried connection to ESP8266s together. Electrically the signals get transmitted from through two MAX3485 and the Tx signal from the master makes it to the slave just fine.

I used a slightly modified code from the examples. Please help me to understand why they are not communicating. The only error code I get is 0xE4.

Master

#include <Arduino.h>

#include <SoftwareSerial.h>    // https://github.com/PaulStoffregen/SoftwareSerial
#include <ModbusRTU.h>
#include <ESP8266WiFi.h>

#define MODBUSRTU_DEBUG

int incomingByte = 0;

#define RX        D5    // Soft Serial RS485 Receive pin
#define TX        D4   // Soft Serial RS485 Transmit pin
#define RTS       D7    // RS485 Direction control

SoftwareSerial RS485(RX, TX);
ModbusRTU mb;

bool cbWrite(Modbus::ResultCode event, uint16_t transactionId, void* data) {
  Serial.printf_P("Request result: 0x%02X, Mem: %d\n", event, ESP.getFreeHeap());
  return true;
}

void setup() {
//  pinMode(RTS, OUTPUT);  
  Serial.begin(115200);
  RS485.begin(300, SWSERIAL_8N2);
  Serial.println("Booting");
  delay(4000);
  
  mb.begin(&RS485, RTS);
  mb.setBaudrate(300);
  mb.master();
}

uint16_t test;

void loop() {
    if (!mb.slave()) {
      mb.readHreg(1, 10, &test, 1, cbWrite);
      Serial.println("readHreg");
    }
    mb.task();
    yield();
    Serial.print("Received: ");
    Serial.println(test);
    delay(2000);
}

The only output i get from this code is:

readHreg
Received: 0
Request result: 0xE4, Mem: 48552
Received: 0

Slave

/*
  ModbusRTU ESP8266/ESP32
  Simple slave example

  (c)2019 Alexander Emelianov ([email protected])
  https://github.com/emelianov/modbus-esp8266

  modified 13 May 2020
  by brainelectronics

  This code is licensed under the BSD New License. See LICENSE.txt for more info.
*/

#include <Arduino.h>

#include <SoftwareSerial.h>    // https://github.com/PaulStoffregen/SoftwareSerial
#include <ModbusRTU.h>
#include <ESP8266WiFi.h>

#define MODBUSRTU_DEBUG
#define REGN 10
#define SLAVE_ID 1

#define RX        D4    // Soft Serial RS485 Receive pin
#define TX        D1   // Soft Serial RS485 Transmit pin
#define RTS       D7    // RS485 Direction control

SoftwareSerial RS485(RX, TX);
ModbusRTU mb;

void setup() {
  Serial.begin(115200);
  RS485.begin(300, SWSERIAL_8N2);
  Serial.println("Booting");
  
  mb.begin(&RS485, RTS);
  mb.setBaudrate(300);
  mb.slave(SLAVE_ID);
  mb.addHreg(REGN);
  mb.Hreg(REGN, 100);
}

void loop() {
  mb.task();
  yield();
}

Newbie help request.

I'm looking for a good TCP Modbus controller for a long time, want now to use this library on my NodeMCU board.
Regularly, I use the Arduino IDE to program it, and the Library manager to add needed libraries to my environment.

I've tried to find this library in my manager without success.

2 things:

  1. May you please add your great program to the public Arduino library repository so it will be available there?
  2. Meanwhile, when it's not there, how can I install and use it in my environment?

Many thanks!

Need some help converting from Modbus-Master-Slave-for-Arduino

Hi,

I'm very new at this low level stuff, but managed to read some values from this setup:
esp8266<->TTL to RS485 Converter<->Energy Counter

The code was based on this links that are using a old library, "Modbus-Master-Slave-for-Arduino":
https://github.com/edphackathon/EDPIoTHackathon2017/blob/master/src/examples/EDPComm_example/EDPComm_example.ino
https://github.com/edphackathon/EDPIoTHackathon2017/blob/master/src/EDPComm-Hackathon-2017/EDPComm.cpp

Special this part:

void SendEBRequest(uint8_t u8id, uint8_t u8fct, uint16_t u16RegAdd, uint16_t u16CoilsNo, uint16_t *au16reg)
{
  /*
    u8id : slave address, in this case =1
    u8fct : function code (check documentation)
    u16RegAdd : start address in slave (check documentation)
    u16CoilsNo : number of elements (coils or registers) to read 
    au16reg : pointer to a memory array in the Arduino
  */
  telegram = {u8id, u8fct, u16RegAdd, u16CoilsNo, au16reg};
  Serial.println("**Sending Request to EB**");
  master.query(telegram); // send query (only once)
}
void loop()
{
  switch (u8state)
  {
  case 0:
    // wait state
    if (millis() > u32wait)
      u8state++;
    break;
  case 1:
    /* For FCT_READLOADPROFILE the u16RegAdd is 769 (00000011 00000001 in binary) 
         That means values 0x0003 and 0x0001" in hexadecimal:
         0x0003 for Measumerent ID indexes to retrieve (1st - Clock 2nd -AMR Status and 3rd - Active Energy Import (A+))
         0x0001 for quantity of entries (we only need the last)
         The u16CoilsNo is 0 as we don't need any more inputs.
         You should always use this configuration for FCT_READLOADPROFILE
      */
    SendEBRequest(1, FCT_READLOADPROFILE, 769, 0, au16data);
    u8state++;
    break;
  case 2:
    master.poll(); // check incoming messages
    if (master.getState() == COM_IDLE)
    {
      u32wait = millis() + 2000;
      edpComm.printRawData(au16data); //prints raw load profile data coming from the EB
      u8state =6; //goes to Sigfox sending option
    }
    break;
  case 3:
    // wait state. You should always use this between SendEBRequests()
    if (millis() > u32wait)
      u8state++;
    break;
  case 4:
    /* For FCT_READSINGLEREGISTER the u16RegAdd depends on which register you want to get.
       Check the documentation for more info.
       The u16CoilsNo is 1 as in one output.
      You should always use this configuration for FCT_READSINGLEREGISTER
    */
    SendEBRequest(1, FCT_READSINGLEREGISTER, 109, 1, au16data); // #109 register is Instantaneous Current
    u8state++;
    break;
  case 5:
    master.poll(); // check incoming messages
    if (master.getState() == COM_IDLE)
    {
      u32wait = millis() + 2000;
      double current = edpComm.getLiveInstantValues(au16data);
      Serial.println(current);          //Current has a scaler of -1
      edpComm.resetDataArray(au16data); //Always reset au16data
      u32wait = millis() + 2000;
      u8state = 0;
    }
    break;
  case 6:
    /*
        In this example, we will ONLY send the last data value from the Load Profile (3rd - Active Energy Import (A+))
        You should complete the case with the other data available coming in from the EBs and send it to Sigfox. 
        Be aware of the 12 bytes payload limit!
        */
    if (edpComm.checkLoadProfileData(au16data))
    {
      int loadProfileData = edpComm.getLoadProfileData(au16data);
     //send data ...
      edpComm.resetDataArray(au16data);
      u32wait = millis() + 2000;
      u8state = 3;
      break;
    }
    else
    {
      Serial.println("**Skipped. Trying again...**");
      edpComm.resetDataArray(au16data);
      u32wait = millis() + 2000;
      u8state = 0;
      break;
    }
  }
}

I was trying to convert to this library, but have some doubts:
Where I have

SendEBRequest(1, FCT_READSINGLEREGISTER, 121, 2, au16data); // #121 Instantaneous Power

Should be something like this?

if (!mb.slave()) {
      mb.readHreg(1, 121, coils, FCT_READSINGLEREGISTER, cbWrite);
    } 

Thx

Feature Request: support non standard data types (int32, float, ...)

Thanks for this great implementation of the MODBUS protocol. I found it to be as the most complete and clean library out there.

Would it be possible and in the spirit of the lib to support non standard data types like 32bit integers and float? there are quite a few devices and masters out there that make use of those, even if they are not strictly MODBUS.

Any opinions?

Read a 32bit value

Hi, i need to read a 32bit value (2 reg of 16 bit) with the second reg is the lower value and first is the high value from tcp device that have uid = 3.
I use mb.readHreg(remote, REG_POWER, (uint16_t*)&prodPower32_W, 2, nullptr, 3); but prodPower32_W return =0.
Can you help me?
Thank you

How to add Line control for ESP32 modbus RTU slave?

Hello,
Im trying to use ESP32 as modbus RTU slave device .my connection is RS485 based on ADM485 ,but im unable to recieve any data .how should i use data flow control on this library?
i hope help me :).
here is a section of my code i use modbus :
`
Sensor1_COIL_stat = mb.Coil(Sensor1_COIL_addr);

Sensor4_COIL_stat = mb.Coil(Sensor4_COIL_addr);

Valve3_COIL_stat= mb.Coil(Valve3_COIL_addr);

Motor_COIL_stat = mb.Coil(Motor_COIL_addr);
`

Best Regards

Modbus read Master

Hi, where I can find an example of read a register from a MasterPLC and conver my ESP as a Slave?

Examples not compiling

I'm getting this type of error when trying to compile the examples

error: 'vector' in namespace 'std' does not name a template type

Read Holding Registers from Modbus Master (Solaredge)

Good Morning,

unluckily i need a little support to get my project working. I am using CAS MODBUS SCANNER and get the Result of the inverter.

Attached two pictures

image
image

With this informations i created the code

#include <ESP8266WiFi.h>
#include <ModbusIP_ESP8266.h>

const int REG = 205;               // Modbus Hreg Offset
IPAddress remote(192, 168, 1, 26);  // Address of Modbus Slave device
const int LOOP_COUNT = 10;

ModbusIP mb;  //ModbusIP object

void setup() {
  Serial.begin(115200);
 
  WiFi.begin("SSID", "PASSWORD");
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  mb.master();
}

uint16_t res = 0;
uint8_t show = LOOP_COUNT;

void loop() {
  if (mb.isConnected(remote)) {   // Check if connection to Modbus Slave is established
    mb.readHreg(remote, REG, &res);  // Initiate Read Coil from Modbus Slave
  } else {
    mb.connect(remote);           // Try to connect if no connection
  }
  mb.task();                      // Common local Modbus task
  delay(100);                     // Pulling interval
  if (!show--) {                   // Display Slave register value one time per second (with default settings)
    Serial.println(res);
    show = LOOP_COUNT;
  }
}

But my result posted on the serial console is just 0 and not 4998 as supposed by the modbus scanner.

Do you have an hint for me?

Thanks and Regards,
Christian

Maximum register is too small

#define MB_MAX_REGS 32

Is it possible to default the library to a higher value, say 512?

Also is there a way I can update the Holding/Input register value direct via pointer instead of calling Ireg/Hreg ?

Any help is appreciated!

Thanks for your wonderful work!

Question about multi register reading. ( MODBUS TCP )

Hi! I have a question about mb.readHreg.

How can i read multiple registers?
Do i have to declare somewhere the register addresses?

If i try this way:

#define Input_Reg    0x4000
#define OutPut_Reg    0x4032
uint16_t EXP_Input_Buffer[2];

bool SaveInput(Modbus::ResultCode event, uint16_t transactionId, void* data) {
    if(event == mb.EX_SUCCESS){
        Expander_Info[ADDRESS_COUNTER]->Inputs[0]     = EXP_Input_Buffer[0];
        Expander_Info[ADDRESS_COUNTER]->OutPuts[0]  = EXP_Input_Buffer[1];
        return true;
    }else{
        return false;
    }
}

static const inline void Read_Info_Registers(){
    if (!mb.slave()) {
        if(Expander_Info[ADDRESS_COUNTER] != 0){
            mb.readHreg(Expander_Info[ADDRESS_COUNTER]->Address,Input_Reg,EXP_Input_Buffer,2,SaveInput);
            while (mb.slave()){mb.task();}
        }
        ADDRESS_COUNTER++;
        if(ADDRESS_COUNTER == MAX_EXPANDER){ADDRESS_COUNTER = 0;}
    }
}

I don't get anything inside Expander_Info[ADDRESS_COUNTER]->OutPuts[0]. :(

How to receive response from Slave

Hi,

when I sent writeHreg to TCP Slave, is there way to read response from Slave to this message?

When I'm reading multiple registers using readIreg, do I need to use addIreg function for results, or it it's enough to define uint16_t array?

Thanks

Petr

RTU and IP functionality by one device

Hi,

I want to ask if it's possible to use RTU and IP by one device.

My setup:
Slave and server --> ESP8266
Master and client --> ESP32

On the ESP32 device the reading of values does not work. If I'm removing RTU or IP part the program is working. Can you help me to setup?

ESP8266 code --> slave and server :
`#include <ModbusRTU.h>
#ifdef ESP8266
#include <ESP8266WiFi.h>
#else //ESP32
#include <WiFi.h>
#endif
#include <ModbusIP_ESP8266.h>

#define REGN 10
#define SLAVE_ID 2

const char* ssid = "xxx";
const char* password = "xxx";

ModbusRTU mb;
ModbusIP ip;

void setup() {
Serial.begin(57600, SERIAL_8N1);

mb.begin(&Serial);
mb.slave(SLAVE_ID);
mb.addHreg(4353, 100);
mb.addHreg(4354, 33224);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());

ip.server();
ip.addHreg(2, 1);
ip.addHreg(4, 71);
ip.addHreg(6, 0x4152);
ip.addHreg(7, 0x5449);
ip.addHreg(8, 0x434C);
ip.addHreg(9, 0x455F);
ip.addHreg(10, 0x4E55);
ip.addHreg(11, 0x4D42);
ip.addHreg(12, 0x4552);
ip.addHreg(13, 0x0D0A);
ip.addHreg(14, 0x5345);
ip.addHreg(15, 0x5249);
ip.addHreg(16, 0x414C);
ip.addHreg(17, 0x5F5F);
ip.addHreg(18, 0x5F4E);
ip.addHreg(19, 0x554D);
ip.addHreg(20, 0x4245);
ip.addHreg(21, 0x522E);
}

void loop() {
ip.task();
mb.task();
yield();
}`

ESP32 --> Master and client
`#include <ModbusRTU.h>
#include <WiFi.h>
#include <ModbusIP_ESP8266.h>

const char* ssid = "xxx";
const char* password = "xxx";

IPAddress remote(192, 168, xxx, xxx);
ModbusRTU mb;
ModbusIP ip;

uint16_t slaveReg[2];
uint16_t serverReg1;
uint16_t serverReg2;
uint16_t serverReg3[8];
uint16_t serverReg4[8];

void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());

ip.client();
Serial2.begin(57600, SERIAL_8N1);
mb.begin(&Serial2);
mb.master();
}

void loop() {

if (!mb.slave()) {
mb.readHreg(2, 4353, slaveReg, 2);
}
Serial.println("FAN_SPEED: " + String(slaveReg[0]));
Serial.println("TEMP_EXTRACT_AIR: " + String(slaveReg[1]));

if (ip.isConnected(remote)) { // Check if connection to Modbus Slave is established
Serial.println("Start read 1");
ip.readHreg(remote, 2, &serverReg1);
Serial.println("Start read 2");
ip.readHreg(remote, 4, &serverReg2);
Serial.println("Start read 3");
ip.readHreg(remote, 6, serverReg3, 8);
Serial.println("Start read 4");
ip.readHreg(remote, 14, serverReg4, 8);
} else {
Serial.println("Try to connect");
ip.connect(remote); // Try to connect if no connection
}
Serial.println("MODBUS_ENABLE: " + String(serverReg1));
Serial.println("MODBUS_UNIT_ID: " + String(serverReg2));
for (uint8_t i=0; i < 8; i++) {
Serial.println("INVERTER_ARTICLENUMBER" + String(i) + ": " + String(serverReg3[i]));
}
for (uint8_t i=0; i < 8; i++) {
Serial.println("INVERTER_SERIAL_NUMBER" + String(i) + ": " + String(serverReg4[i]));
}
delay(100); // Pulling interval

ip.task();
mb.task();
yield();
}`

How do I call the value of reading from VL53LOX and store it to a register?

I have VL53LOX connecting to arduino D1 I use the code find it in the example of IDE (shown below). Its required to read this value to to PLC via Modbus protocol
The problem is the serial stopped reading the value when plc connected to arduino D1 and began to read the distance.
#include "Adafruit_VL53L0X.h"

Adafruit_VL53L0X lox = Adafruit_VL53L0X();

void setup() {
Serial.begin(115200);

// wait until serial port opens for native USB devices
while (! Serial) {
delay(1);
}

Serial.println("Adafruit VL53L0X test");
if (!lox.begin()) {
Serial.println(F("Failed to boot VL53L0X"));
while(1);
}
// power
Serial.println(F("VL53L0X API Simple Ranging example\n\n"));
}
Knowing that modbus part of code not included.

Will miss message from master, if also receiving serial data on other Uart.

Hi,
Thanks for your library.

I'm using the library set up as a slave on a ESP32.
For the modbus uart i'm using Uart1 at 9600bps.
In general everything seems to work, except when also at the same time Uart2 (115200 bps) receives a long message ~100ms. Then the modbus message from the master is missed.
I verified this with a scope.

I 'fixed' it by changing the _t inter-frame delay to 10ms.
But of course this is not a very good solution.
It would be better if the receive function had better control over the uart, maybe with an interrupt?

Thanks!
-Michael

ModbusTCP readHreg failed, but connection to slave is ok

Hi, @emelianov thanks for your library. I'm doing some testing code. I'm setting esp32 as Master and connects to the slave address just fine. However, when I try to read Holding registers the cbTransaction triggers and shows error 0X04 which I read it means fail to proces request. I'm using modsim as slave and it shows the connection with the esp32 and the "read data" state. I've put values on modsim registers as float32, decimal,hex and none of those seems to be read by the esp.
I post the code:

holding register

Hi Emelianov,
Thank you for this great work.
Could you advise me, how to holding the value of [get distance ()] in register 100 of ESP8266 in the following mod-bus distance measurement code:

#ifdef ESP8266
#include <ESP8266WiFi.h>
#else //ESP32
#include <WiFi.h>
#endif
#include <ModbusIP_ESP8266.h>
const int trigPin = 5; // pin no. 5 is D1 ESP8266
const int echoPin = 4; // pin no. 4 is D2 ESP8266
int dist;
long duration;
// Modbus Registers Offsets
const int TEST_HREG = 100;
//ModbusIP object
ModbusIP mb;
IPAddress staticIP224_60(192,168,1,70);
IPAddress gateway224_60(192,168,1,1);
IPAddress subnet224_60(255,255,255,0);
void setup() {
#ifdef ESP8266
Serial.begin(9600);
#else
Serial.begin(115200);
#endif
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
WiFi.config(staticIP224_60, gateway224_60, subnet224_60);
WiFi.begin("---", "----");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
mb.slave();
mb.addHreg(TEST_HREG, 0xABCD);
mb.addHreg(dist, 0x65);
}
void loop() {
//Call once inside loop() - all magic here
mb.task();
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance
dist= duration*0.034/2;
// Prints the distance on the Serial Monitor
Serial.print("Distance: ");
Serial.println(dist);

delay(1000);
}

Sensor float value

Hi,

I wonder if you could give me some advice/help. I am a C# programmer by day (and work with modbus quite often). I can't seem to get float values to work. And this shouldn't be to hard probably... The sensor I am reading gives me a float value as sensor reading and I want to present that as 2 registers (running my code as modbus slave). But I can't seem to figure it out somehow. Do I first need to declare 2 registers separately for example?

Library naming is wrong

When you use Modbus TCP, you have "CLIENT" and "SERVER". It is confusing to use master/slave naming for modbus tcp protocol.

Master/slave naming is only for modbus RTU.

Thanks

Reading a float value from modbus device

Hi @emelianov this is more a need for help than an issue. I read two registers from a modbus device, that join them gives a float value. Is it possible to join these two registers and convert them into the float value that it's shown on the device with this library?. Let's say I read two registers, starting from register 33. I made an union and the values return are 16919 and 27089, but sometimes the second value is negative(I've seen the negative value with modscan, but I see that the library only accepts uint variables, so I can't get that negative value when using readHreg). When I show the real value, it does not match the one that's on the device.
A piece of the code where I get the values:
union data{ float real; uint16_t d[2]; }; data res; .... mod.readHreg(1,33,res.d,2,cbWrite);

Modbus RTU Master and Slave implementation in ESP32

Board: ESP32 Development Board
ESP32 core: 1.0.3
Library version: 3.0.0-DEVEL

Hello there,

Thanks for an amazing workaround on providing Modbus RTU support for ESP32.

For one of my project, I need to implement one ESP32 as a Modbus master and another one as a Modbus slave. I tried RTU-master and RTU-slave example by slightly modifying them. I stored values in the Slave holding register and tried to read the same by calling readHreg in master. But it's showing some garbage values. I have verified connections and everything looks good. Kindly help me out to resolve this.

Attaching programs for your reference.

This one is of Modbus Slave.

#include <ModbusRTU.h>

#define REGN 10
#define SLAVE_ID 1

#define RE_DE 4

ModbusRTU mb;

void setup() {
  Serial.begin(115200);
  mb.begin(&Serial,RE_DE);
  mb.slave(SLAVE_ID);
  mb.addHreg(REGN);
  mb.Hreg(REGN, 100);
  Serial.println(mb.Hreg(REGN));
  Serial.println(mb.slave());
}

void loop() {
  mb.task();
  yield();
}

Following one is of Modbus Master.

#include <ModbusRTU.h>

ModbusRTU mb;

bool cbWrite(Modbus::ResultCode event, uint16_t transactionId, void* data) {
  Serial.printf_P("Request result: 0x%02X, Mem: %d\n", event, ESP.getFreeHeap());
  return true;
}

void setup() {
  Serial.begin(115200);
  mb.begin(&Serial);
  mb.master();
}

uint16_t coils[20];

void loop() {
  if (!mb.slave()) {
    mb.readHreg(1, 10, coils, 1, cbWrite);
  }
  mb.task();
  yield();
}

Thanks,
Krutarth Trivedi.

Modbus TCP to RTU bridge

I'm interested in using this library as TCP to RTU modbus bridge, i.e.:

  • have modbus TCP master on a different system with any modbus TCP standard library
  • use esp8266 as modbus TCP slave over Wifi
  • have esp8266 as modbus RTU master against slave device connected to esp8266
  • implement bridging behaviour on esp8266

I'm not sure about any timing constraints in modbus, but is this a scenario that could be supported by this library?

Call input register by modbus from ESP8266 or Arduino D1

Dear emelianov
Thank you very much for your replay- I am so grateful for you.
I apply your advice in my code shown below, but I get this error message:
(( exit status 1
'MB' was not declared in this scope ))
When declare MB as " unsigned int MB;"
The compiler give me
((request for member 'Ireg' in 'MB', which is of non-class type 'unsigned int'
))
My code is:

#include <ESP8266WiFi.h>
#define analog_output D5
#include "Adafruit_VL53L0X.h"
Adafruit_VL53L0X lox = Adafruit_VL53L0X();
float distance;
long duration;
int dataIn;
const char* ssid = "MH_Ext";
const char* password = "74375325";
int ModbusTCP_port = 502;
//////// Required for Modbus TCP / IP ///
#define maxInputRegister 20
#define maxHoldingRegister 20
#define MB_FC_NONE 0
#define MB_FC_READ_REGISTERS 3 //implemented
#define MB_FC_WRITE_REGISTER 6 //implemented
#define MB_FC_WRITE_MULTIPLE_REGISTERS 16 //implemented
// MODBUS Error Codes
#define MB_EC_NONE 0
#define MB_EC_ILLEGAL_FUNCTION 1
#define MB_EC_ILLEGAL_DATA_ADDRESS 2
#define MB_EC_ILLEGAL_DATA_VALUE 3
#define MB_EC_SLAVE_DEVICE_FAILURE 4
// MODBUS MBAP offsets
#define MB_TCP_TID 0
#define MB_TCP_PID 2
#define MB_TCP_LEN 4
#define MB_TCP_UID 6
#define MB_TCP_FUNC 7
#define MB_TCP_REGISTER_START 8
#define MB_TCP_REGISTER_NUMBER 10
byte ByteArray[260];
unsigned int MBHoldingRegister[maxHoldingRegister];
//////////////////////////////////////////////////////////////////////////
WiFiServer MBServer(ModbusTCP_port);
IPAddress staticIP224_60(192,168,1,60);
IPAddress gateway224_60(192,168,1,1);
IPAddress subnet224_60(255,255,255,0);
void setup() {
//pinMode(14, OUTPUT);
Serial.begin(115200);
// wait until serial port opens for native USB devices
while (! Serial) {
delay(1);
}

Serial.println("Adafruit VL53L0X test");
if (!lox.begin()) {
Serial.println(F("Failed to boot VL53L0X"));
while(1);
}
// power
Serial.println(F("VL53L0X API Simple Ranging example\n\n"));
WiFi.config(staticIP224_60, gateway224_60, subnet224_60);
WiFi.begin(ssid, password); //rest of init
delay(100) ;
WiFi.begin(ssid, password);
delay(100) ;
Serial.println(".");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
MBServer.begin();
Serial.println("Connected ");
Serial.print("ESP8266 Slave Modbus TCP/IP ");
Serial.print(WiFi.localIP());
Serial.print(":");
Serial.println(String(ModbusTCP_port));
Serial.println("Modbus TCP/IP Online");
}
void loop() { //read from VL53LOX
VL53L0X_RangingMeasurementData_t measure;

Serial.print("Reading a measurement... ");
lox.rangingTest(&measure, false); // pass in 'true' to get debug data printout!

if (measure.RangeStatus != 4) { // phase failures have incorrect data
Serial.print("Distance (mm): "); Serial.println(measure.RangeMilliMeter);
MB.Ireg(6, measure.RangeMilliMeter); // Assign value to Ireg
} else {
Serial.println(" out of range ");
MB.Ireg(6, 0); // Set 0 on error
}
delay(1000);
// Check if a client has connected // Modbus TCP/IP
WiFiClient client = MBServer.available();
if (!client) {
return;
}
boolean flagClientConnected = 0;
byte byteFN = MB_FC_NONE;
int Start;
int WordDataLength;
int ByteDataLength;
int MessageLength;
// Modbus TCP/IP
while (client.connected()) {
if(client.available())
{
flagClientConnected = 1;
int i = 0;
while(client.available())
{
ByteArray[i] = client.read();
i++;
}
client.flush();
///////// Holding Register [0] A [9] = 10 Holding Registers Writing
//// end code - fin
//// rutine Modbus TCP
byteFN = ByteArray[MB_TCP_FUNC];
Start = word(ByteArray[MB_TCP_REGISTER_START],ByteArray[MB_TCP_REGISTER_START+1]);
WordDataLength = word(ByteArray[MB_TCP_REGISTER_NUMBER],ByteArray[MB_TCP_REGISTER_NUMBER+1]);
}
// Handle request
switch(byteFN) {
case MB_FC_NONE:
break;
case MB_FC_READ_REGISTERS: // 03 Read Holding Registers
ByteDataLength = WordDataLength * 2;
ByteArray[5] = ByteDataLength + 3; //Number of bytes after this one.
ByteArray[8] = ByteDataLength; //Number of bytes after this one (or number of bytes of data).
for(int i = 0; i < WordDataLength; i++)
{
ByteArray[ 9 + i * 2] = highByte(MBHoldingRegister[Start + i]);
ByteArray[10 + i * 2] = lowByte(MBHoldingRegister[Start + i]);
}
MessageLength = ByteDataLength + 9;
client.write((const uint8_t *)ByteArray,MessageLength);
byteFN = MB_FC_NONE;
break;
case MB_FC_WRITE_REGISTER: // 06 Write Holding Register
MBHoldingRegister[Start] = word(ByteArray[MB_TCP_REGISTER_NUMBER],ByteArray[MB_TCP_REGISTER_NUMBER+1]);
ByteArray[5] = 6; //Number of bytes after this one.
MessageLength = 12;
client.write((const uint8_t *)ByteArray,MessageLength);
byteFN = MB_FC_NONE;
break;
case MB_FC_WRITE_MULTIPLE_REGISTERS: //16 Write Holding Registers
ByteDataLength = WordDataLength * 2;
ByteArray[5] = ByteDataLength + 3; //Number of bytes after this one.
for(int i = 0; i < WordDataLength; i++)
{
MBHoldingRegister[Start + i] = word(ByteArray[ 13 + i * 2],ByteArray[14 + i * 2]);
}
MessageLength = 12;
client.write((const uint8_t *)ByteArray,MessageLength);
byteFN = MB_FC_NONE;
break;
}
}

}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.