ESP32 RTU Modbus simple message transmit and receive

Thread Starter

zazas321

Joined Nov 29, 2015
936
Hello. I need some advice on how to get Modbus working between 2 or more devices.

I have 2 ESP32. One is programmed as master and the other one as slave. All I want to do is to send some message from master to slave. For now, all I am trying to do is to write number "5" to Holding register and then receive that number "5" on my slave device.

My rs485 schematic:
1603267520960.png

RS48_RXD is connected to GPIO16
RS485_TXD is connected to GPIO17
RS485_DIR is connected to GPIO15

For modbus, I use this library:
https://github.com/emelianov/modbus-esp8266

I have implemented slave, master sketches for my devices and changed them slightly accordingly to my needs.

Slave code:
Code:
/*
  ModbusRTU ESP8266/ESP32
  Simple slave example

  (c)2019 Alexander Emelianov (a.m.emelianov@gmail.com)
  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 <ModbusRTU.h>

#define RXD2 16
#define TXD2 17
#define DIR 15

#define REGN 1
#define SLAVE_ID 1

ModbusRTU mb;

void setup() {
  Serial.begin(9600, SERIAL_8N1);
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  mb.begin(&Serial2);
  mb.setBaudrate(9600);

  mb.slave(SLAVE_ID);//Initializng modbus slave device with ID 1
  mb.addHreg(REGN); // add the register with address 1
  mb.Hreg(REGN, 100); // DONT UNDERSTAND WHAT THIS FUNCTION FOR?????
  pinMode(DIR, OUTPUT);    // sets the digital pin 13 as output
  digitalWrite(13, LOW); // sets the digital pin 13 on
}

uint16_t storing_data = 0; // place holder to store data
void loop() {
  mb.readHreg(1, 1, &storing_data, 1, cbWrite);
  mb.task();
  yield();

 
}
As you can see, I have defined REGN as 1 and SLAVE_ID as 1
I then call function to addHreg:
Code:
mb.addHreg(REGN); // add the register with address 1
mb.Hreg(REGN, 100); // DONT UNDERSTAND WHAT THIS FUNCTION FOR?????
I also write direction to LOW since thats what I read. In order to read RS485 data RE,DE needs to be pulled low. Am I right?



My master code:

Code:
/*
  ModbusRTU ESP8266/ESP32
  Read multiple coils from slave device example

  (c)2019 Alexander Emelianov (a.m.emelianov@gmail.com)
  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 <ModbusRTU.h>
#define RXD2 16
#define TXD2 17
#define DIR 15

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);
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  mb.begin(&Serial2);
  mb.master();
  pinMode(DIR, OUTPUT);    // sets the digital pin 13 as output
  digitalWrite(13, HIGH); // sets the digital pin 13 on
}

uint16_t send_data = 5;

void loop() {
  if (!mb.slave()) {
    mb.writeHreg(1, 1, &send_data, 1, cbWrite);
  }
  mb.task();
  yield();
  delay(5000);
}
So my master as you can see above, is writing to the Holding register with the address offset 1 (same as I created in my slave):
Code:
mb.writeHreg(1, 1, &send_data, 1, cbWrite);


QUESTIONS:


1. In the slave sketch, after initialzing holding register, Hreg function is used. Can someone help me understand the purpose of that?:
Code:
mb.Hreg(REGN, 100); // DONT UNDERSTAND WHAT THIS FUNCTION FOR?????



2. What is the best way to control DE/RE pins of RS485 IC? Is it okay to pull the pins HIGH on master device and pins LOW on slave devices since at for the moment master will be only sending data and slaves only receiving.

Later I will need to be able to write/read back data on my master device so I am not entirely sure how I am going to control DE and RE pins since I am not going to know when I need to receive? Would wiring DE/RE pins to USART2 RTS pin is better?


3. I can seem to understand how this library works even though I have gone through the source code and docs a few times. I dont understand what is callback function required for?. All I want to do is just send a number from master device to slave device I do not need any callbacks or etc.


If anyone have used this library and could help me understand how to implement the most simple MODBUS transmit and receive I would be very happy! Thanks in advance.
 

bogosort

Joined Sep 24, 2011
696
As you can see, I have defined REGN as 1 and SLAVE_ID as 1
I then call function to addHreg:
Code:
mb.addHreg(REGN); // add the register with address 1
mb.Hreg(REGN, 100); // DONT UNDERSTAND WHAT THIS FUNCTION FOR?????
According to the library's API, Hreg() with two arguments writes the second parameter to the local address of the first parameter. In other words, you're setting the value of holding register 1 to 100. If your master reads from register 1, it should see the value 100.

Note that your loop() in the slave appears incorrect. You're calling readHreg(), which reads from a remote slave -- but this is the remote slave. Look at the slave example in the examples directory of the library.

My master code:
Try to read the value of 100 from the slave to ensure you have good communication and the addressing offsets are correct. If you're not getting the value you expect, try subtracting 1 from the given address.
 

John P

Joined Oct 14, 2008
2,025
Zazas321, I'm only seeing part of your circuit diagram, so maybe there's more. But what it shows is R13, a 120 ohm resistor joining the two wires of your RS485 bus. That would be correct to terminate a line, but do you have additional pull-up and pull-down resistors to ensure that it reads a '1' most of the time? Normally an RS485 bus has all its drivers turned off, and the resistors keep it in a known state. When one node wants to transmit, it enables its driver (that would be your RS485_DIR line) and then it disables the driver when its transmission is complete. That can be tricky, because your UART may make it difficult to tell when the last character is complete. You mustn't turn off the driver until it's all done! But that's really all you need to do.
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
Zazas321, I'm only seeing part of your circuit diagram, so maybe there's more. But what it shows is R13, a 120 ohm resistor joining the two wires of your RS485 bus. That would be correct to terminate a line, but do you have additional pull-up and pull-down resistors to ensure that it reads a '1' most of the time? Normally an RS485 bus has all its drivers turned off, and the resistors keep it in a known state. When one node wants to transmit, it enables its driver (that would be your RS485_DIR line) and then it disables the driver when its transmission is complete. That can be tricky, because your UART may make it difficult to tell when the last character is complete. You mustn't turn off the driver until it's all done! But that's really all you need to do.
No I do not have any resistors pulling UP or DOWN. The schematic that I have provided is a full schematic for the RS485. Of course there are more things in the schematic but nothing to do with the RS485. I will check my signals with logic analyzer and see what kind of signals I get.. Maybe that could be a problem. I remember I have read about something called "failsafe bias" I assume thats what you are reffering to?
 

John P

Joined Oct 14, 2008
2,025
Yes, I see in the WIkipedia listing about RS485 that they do use the term "failsafe bias" but I think it's misleading. There have to be times when the bus isn't driven--it's not a failure condition. It's very important to make sure that the receivers see a known condition on the bus at all times! The data sheet for the MAX485 specifies "Receiver Differential Threshold Voltage +/-0.2V", so I assume they mean anything between those voltages sends an unpredictable signal on the RX line. If there's anything worse than seeing the wrong thing on the line, it's not knowing whether it's wrong or not.
 
Last edited:

aemelianov

Joined Oct 23, 2020
5
1. In the slave sketch, after initialzing holding register, Hreg function is used. Can someone help me understand the purpose of that?:
Code:
mb.Hreg(REGN, 100); // DONT UNDERSTAND WHAT THIS FUNCTION FOR?????
2. What is the best way to control DE/RE pins of RS485 IC? Is it okay to pull the pins HIGH on master device and pins LOW on slave devices since at for the moment master will be only sending data and slaves only receiving.

Later I will need to be able to write/read back data on my master device so I am not entirely sure how I am going to control DE and RE pins since I am not going to know when I need to receive? Would wiring DE/RE pins to USART2 RTS pin is better?

3. I can seem to understand how this library works even though I have gone through the source code and docs a few times. I dont understand what is callback function required for?. All I want to do is just send a number from master device to slave device I do not need any callbacks or etc.
Hello.
I'm maintainer of the mentioned library and just noticed your thread. Get my 5 cents.
1. Take a look coments in code below.
2. The library is designed to control DE/RE by itself. Also refere comments in code bellow.
3. Callback function is fired on various events. As for callback mentioned in read*/write* functions it's called at request end and allows to gets result code of 0x00 on success or Modbus Error code on error.

Slave code:

Code:
#include <ModbusRTU.h>

#define RXD2 16
#define TXD2 17
#define DIR 15
#define REGN 1
#define SLAVE_ID 1

ModbusRTU mb;

void setup() {
  Serial.begin(9600, SERIAL_8N1);
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  //mb.begin(&Serial2);
  mb.begin(&Serial2, DIR);
  // Note that second parameter in .begin() is stands for RE_DE pin
  //mb.setBaudrate(9600);
  // No need to .setBaudrate() for ESP devices

  mb.slave(SLAVE_ID);//Initializng modbus slave device with ID 1

  mb.addHreg(REGN); // add the register with address 1
  mb.Hreg(REGN, 100); // DONT UNDERSTAND WHAT THIS FUNCTION FOR?????
  // Exactly as was wtitten line above assigns value 100 to local HoldingReg #REGN.

  //pinMode(DIR, OUTPUT);    // sets the digital pin 13 as output
  //digitalWrite(13, LOW); // sets the digital pin 13 on
  // No need for lines above the library can control RX/TX by itself
}

//uint16_t storing_data = 0; // place holder to store data

void loop() {
  //mb.readHreg(1, 1, &storing_data, 1, cbWrite);
  // line above make sence only for master.
  mb.task();
  yield();
}
Master code:

Code:
#include <ModbusRTU.h>

#define RXD2 16
#define TXD2 17
#define DIR 15
#define REGN 1
#define SLAVE_ID 1

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);
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  //mb.begin(&Serial2);
  mb.begin(&Serial2, DIR);
  mb.master();

  //pinMode(DIR, OUTPUT);    // sets the digital pin 13 as output
  //digitalWrite(13, HIGH); // sets the digital pin 13 on
}

uint16_t send_data = 5;

void loop() {
  if (!mb.slave()) {
    mb.writeHreg(SLAVE_ID, REGN, &send_data, 1, cbWrite);
  }
  mb.task();
  yield();
  //delay(5000);
  delay(100);
  // It's strongly recommended to run .task() multiple times withn timeout period (that is 1 second by default)
}
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
Hey. Thanks all for contribution and helping me getting modbus to work! I have managed to get the very basic communications between two devices . I thank the library maintainer for very useful comments. I have a few additional questions though:

my masters code:

Code:
/*
 * //masteris su lipduku
  ModbusRTU ESP8266/ESP32
  Read multiple coils from slave device example

  (c)2019 Alexander Emelianov (a.m.emelianov@gmail.com)
  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 <ModbusRTU.h>
#define RXD2 16
#define TXD2 17
#define DIR 15
#define REG1 10
#define BUTTON1   36 //pin D5

ModbusRTU mb;

int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
uint16_t send_data = 5;
uint16_t storing_data = 0; // place holder to store data

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(BUTTON1,INPUT);
  Serial.begin(9600);
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  mb.begin(&Serial2,DIR,true);
  mb.master();
}

void loop() {

  mb.task();
  //yield();
  check_button_state(BUTTON1);
  delay(10);
}

void check_button_state(int pin){

  buttonState = digitalRead(pin);
  if (buttonState != lastButtonState) {
    if (buttonState == HIGH){
      Serial.println("button pressed");
      if (!mb.slave()) {
        mb.writeHreg(1, REG1, 99,  cbWrite);
      } 
      // if the current state is HIGH then the button went from off to on:
      Serial.println("on");
    } 
      else {
      // if the current state is LOW then the button went from on to off:
      Serial.println("off");
    }
  }
  lastButtonState = buttonState;  
}
I have implemented a simple push button. When I push a button, the master sends "99" to a slave device REG1.

And it appears to be working fine. I am able to receive a message on my slave.

My mater debug monitor:
1603706683837.png



In the meantime, my slave code:
Code:
/*
  ModbusRTU ESP8266/ESP32
  Simple slave example

  (c)2019 Alexander Emelianov (a.m.emelianov@gmail.com)
  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 <ModbusRTU.h>

#define RXD2 16
#define TXD2 17
#define DIR 15
#define REG1 10
#define SLAVE_ID 1
#define BUTTON1   36 //pin D5

ModbusRTU mb;

uint16_t send_data = 100;


void setup() {

  Serial.begin(9600, SERIAL_8N1);
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  mb.begin(&Serial2,DIR,true);
  mb.setBaudrate(9600);

  mb.slave(SLAVE_ID);//Initializng modbus slave device with ID 1
  mb.addHreg(REG1); // add the register with address 1
  mb.Hreg(REG1, 0);    

  //mb.writeHreg(1, 100, &send_data, 1, cbWrite);
}
void loop() {
  mb.task();
  delay(200);
  if(mb.Hreg(REG1)==99){
    // IF RECEIVED MESSAGE IS 99, DO SOME TASKS HERE AND THEN REPLY BACK TO MASTER BY PUTTING ANOTHER VALUE TO REG1
    Serial.println(mb.Hreg(REG1));
    mb.Hreg(REG1, 55);    //PUT 55 IN REG1
  }
  
  
}
When the slave received the message 99, it have to do some tasks and then reply to the master so the master knows the task is completed and we can proceed with another operation. I am putting value "55" to REG1 and I want to capture that back on my master

I have added a function inside my void loop to read for an answer:
Code:
void loop() {

  mb.task();
  //yield();
  check_button_state(BUTTON1);
  delay(10);
  
  mb.readHreg(1, REG1, &storing_data,1);
  if(storing_data==55){//THIS NEVER PRINTS 55 ?
    Serial.println("55 read back from the slave");
  }
}
Now my master is starting to act weird. It does not print the callback message and does not seems like it ever receives the message "55" from the slave.

1603706849318.png


Am I doing something wrong here? How to properly implement an answer from slave to master? Also, I have commented yield() function as I have read that its not neccessary for ESP32 that uses 2 cores. I think it introduces larger delay to my system that I dont want
 

aemelianov

Joined Oct 23, 2020
5
For the first sight last code snippet should work somehow. Are you sure that wiring is ok? If RS485 RE pin is connected to DIR (to ground is also suitable way).
Anyway try to monitor error code like you did before.
Code:
 mb.readHreg(1, REG1, &storing_data,1, cbWrite);
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
For the first sight last code snippet should work somehow. Are you sure that wiring is ok? If RS485 RE pin is connected to DIR (to ground is also suitable way).
Anyway try to monitor error code like you did before.
Code:
mb.readHreg(1, REG1, &storing_data,1, cbWrite);
I will try to add a callback to the function tommorow.

Im more concerned about the fact that adding this readHreg function caused the writehreg to stop working. After pressing button it no longer executes the write callback.
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
Seems to work more reliable when I add :
if (!mb.slave()) before I read or write.

Do you have any example that sends/receives a string or json format data? I have tried to do the following:
 
Last edited:
Seems to work more reliable when I add :
if (!mb.slave()) before I read or write.
That's make sence.

Do you have any example that sends/receives a string or json format data? I have tried to do the following:
Largest object that Modbus can operate is 16bit register. So if you need to send json you have to split it across multipe sequental registers and read/write all these registers. It doesn't seems to me that Modbus is good transport for json. Why not HTTP ?
Also there is Modbus File read/write functions but they are rarely available at PLC (i have thse function implementation but not production reade at the time).
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
That's make sence.


Largest object that Modbus can operate is 16bit register. So if you need to send json you have to split it across multipe sequental registers and read/write all these registers. It doesn't seems to me that Modbus is good transport for json. Why not HTTP ?
Also there is Modbus File read/write functions but they are rarely available at PLC (i have thse function implementation but not production reade at the time).
What do you mean http?

I have to communicate with multiple ESP32 devices . In the room where im implementing the system it is very crappy internet signal so im trying to avoid using internet if I can and. Im not entirely sure what you mean by http
 

aemelianov

Joined Oct 23, 2020
5
What do you mean http?
I mean that native trasport for JSON is http. Incapsulating json to modbus doesn't seems to be good idea. If you can't cover all ESP's by WiFi and have to pass data over RS485 it's better to go away from json and migrate to modbus paradigm of binary registers. That is to implement binary data exchange protocol not to serialize/desrialize json.
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
I mean that native trasport for JSON is http. Incapsulating json to modbus doesn't seems to be good idea. If you can't cover all ESP's by WiFi and have to pass data over RS485 it's better to go away from json and migrate to modbus paradigm of binary registers. That is to implement binary data exchange protocol not to serialize/desrialize json.
I understood. I will tell you about one of the examples how I need to communicate with the slave devices. Can you tell me whether this sort of modbus messaging makes any sense


So I have ESP32 devices that are each assigned a serial number. This serial number can be anywhere from 8 to 10 characters.

When the program starts, the Raspberry PI (master) initiates a task. There will be more tasks but lets just take an example of one task.

Task1 - During this task, one of the ESP32 devices will have to update one of their variables that I named "Quantity".

So lets say initially I have 5 ESP32 devices:

Slave 1
Serial number = 111111111
Quantity = 100

Slave 2
Serial number = 222222222
Quantity = 200

Slave 3
Serial number = 333333333
Quantity = 300

Slave 4
Serial number = 444444444
Quantity = 400

Slave 5
Serial number = 555555555
Quantity = 500



So the raspberry PI sends a command to tell all ESP32 devices that we are going to do "TASK1" and send value "1" to register offset 10
writeHreg(1,10,1)
writeHreg(2,10,1)
writeHreg(3,10,1)
writeHreg(4,10,1)
writeHreg(5,10,1)


So now all my ESP32 devices know that task1 is initiated, Now I have to select a particular ESP32 device that I want to update. For that, I have a button on each ESP32 device. When button is pressed, I want to respond to Raspberry PI and send to Raspberry PI the devices slave ID, serial number, and quantity. So for example I will respond with 3 variables so I am going to write multiple registers with offeset 20. At this point, the raspberry PI knows that it needs to receive response from atleast one of the devices , so it will be constantly checking register with offset 20 untill it receives something

The slave device will do:
addHreg(20,SLAVE_ID)
addHreg(21,Quantity)
addHreg(22,Serial) (Serial is more than 16 bit so I am not sure how can I respond with it)

Once the slave device responds, the raspberry PI deactivates all devices so I cannot press button again and send data to master from multiple ESP32 devices during a task. Only 1 device can do task!!
The ESP32 button is only actitave when the value in address offset 10 is set to 1, otherwise its not active. Since one of the ESP32 devices already acknowledged to the task1, I do not care about other devices anymore so I disable the button on all devices:
writeHreg(1,10,0)
writeHreg(2,10,0)
writeHreg(3,10,0)
writeHreg(4,10,0)
writeHreg(5,10,0)


So once the raspberry PI receives the data above, it will ask the user to enter the quantity on my user interface screen that I developed using tkinter. For example if I type 50, It will have to update the slave device quantity and add 50. Now the ESP32 device knows that he needs to receive an updated quantity from Raspberry PI so I will be constantly checking the register and wait for the value to change. Lets say the raspberry PI will respond with the new quantity on offset 30 address

It will send another command to the slave device that was selected
writeHreg(SLAVE_ID,30,Quantity+50)

When ESP32 gets the updated quantity, , I save the value to EEPROM cause I want to save this value even when the device turns OFF.
Thats it, TASK2 is complete.


Does that make any sense ?
 
Last edited:

bogosort

Joined Sep 24, 2011
696
addHreg(22,Serial) (Serial is more than 16 bit so I am not sure how can I respond with it)
Break up the serial number into 16-bit chunks. For example, if the serial is 64-bits long, you can map it to four holding registers:
C:
uint16_t reg1, reg2, reg3, reg4;
uint64_t serial = 0xABCD1234FEDC5678;

reg1 = (serial >> 48) & 0xFFFF;
reg2 = (serial >> 32) & 0xFFFF;
reg3 = (serial >> 16) & 0xFFFF;
reg4 = serial & 0xFFFF;
Now reg1 has 0xABCD, reg2 has 0x1234, and so on.

To reconstruct the serial number in the master, you can shift, mask, and bitwise OR the register values into a 64-bit container. Or you can use a union, e.g.,
C:
union {
    uint64_t slaveSerial;
    uint16_t chunks[4];
} serialReg;

serialReg.chunks[0] = reg4; // little-endian
serialReg.chunks[1] = reg3;
serialReg.chunks[2] = reg2;
serialReg.chunks[3] = reg1;

printf( "slave serial: 0x%lX\n", serialReg.slaveSerial ); // 0xABCD1234FEDC5678
 

aemelianov

Joined Oct 23, 2020
5
That's right solution to store Serial this way and then
Code:
// on slave
addHreg(22, _serialReg.chunks[0]);
addHreg(23, _serialReg.chunks[1]);
addHreg(24, _serialReg.chunks[2]);
addHreg(25, _serialReg.chunks[3]);
// on master
readHreg(SLAVE, 22, &_serialReg, 4).
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
Break up the serial number into 16-bit chunks. For example, if the serial is 64-bits long, you can map it to four holding registers:
C:
uint16_t reg1, reg2, reg3, reg4;
uint64_t serial = 0xABCD1234FEDC5678;

reg1 = (serial >> 48) & 0xFFFF;
reg2 = (serial >> 32) & 0xFFFF;
reg3 = (serial >> 16) & 0xFFFF;
reg4 = serial & 0xFFFF;
Now reg1 has 0xABCD, reg2 has 0x1234, and so on.

To reconstruct the serial number in the master, you can shift, mask, and bitwise OR the register values into a 64-bit container. Or you can use a union, e.g.,
C:
union {
    uint64_t slaveSerial;
    uint16_t chunks[4];
} serialReg;

serialReg.chunks[0] = reg4; // little-endian
serialReg.chunks[1] = reg3;
serialReg.chunks[2] = reg2;
serialReg.chunks[3] = reg1;

printf( "slave serial: 0x%lX\n", serialReg.slaveSerial ); // 0xABCD1234FEDC5678
Understood. I have managed to implement a simmilar example as you have suggested. However I am slightly concerned about the following:

1. What if the serial number length is varying? For example sometimes it might be 8 characters, sometimes 10 characters

Also, does this appraoch make any sense?
declaring serial number as uint8_t array of length 10 (10 will be the maximum length of serial number)
Code:
uint8_t serial2[10]={0,1,2,3,4,5,6,7,8,9}; // I have assigned these values random for now just for testing.
  mb.Hreg(11,( serial2[1]) << 8 | (serial2[0] & 0xff)) );
  mb.Hreg(12,( serial2[3]) << 8 | (serial2[2] & 0xff)) );
  mb.Hreg(13,( (serial2[5]) << 8 | (serial2[4] & 0xff)) );
  mb.Hreg(14,( (serial2[7]) << 8 | (serial2[6] & 0xff)) );
The master is able to receive those numbers and returns:
256,770,1284,1798
256 will correspond to 0x10
770 will correspond to 0x302
1284 will correspond to 0x504
1798 will correspond to 0x706

Obviously thats not exactly what I need but maybe with the correct bitwise operation it is possible to achieve what I want here?

I am expecting to receive :
Register 11 = 01
Register 12 = 23
Register 13 = 45
Register 14 = 67
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
Oh. I havent noticed your latest answer whilst I was typing my own answer. I will have a look at this chunks function that you use. I am not aware about this _ sign that you use near the variable. Have never seen it before.

Also, keep in mind that for my actual project I wont be using esp32 master. The raspberry PI will be my master device and I will have to implement a function that will decode different bits to a single serial code.


For now, I am just trying to find the most simple way for the slave device to send its serial number to master
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
I have tried this:

Code:
uint64_t serial3 = 0x123456789;
uint16_t reg1, reg2, reg3, reg4;
union {
    uint64_t slaveSerial;
    uint16_t chunks[4];
} serialReg;


void modbus_respond_pildymas(){
  mb.Hreg(REG_Pildymas, 2);    //PUT 55 IN REG1
  Serial.print("item device quantity inside=");
  Serial.println(item_inside.quantity);
  mb.Hreg(REG_Pildymas+1, item_inside.quantity);    //PUT 55 IN REG1
  reg1 = (item_inside.serial3 >> 48) & 0xFFFF;
  reg2 = (item_inside.serial3 >> 32) & 0xFFFF;
  reg3 = (item_inside.serial3 >> 16) & 0xFFFF;
  reg4 = item_inside.serial3 & 0xFFFF;

  serialReg.chunks[0] = reg4; // little-endian
  serialReg.chunks[1] = reg3;
  serialReg.chunks[2] = reg2;
  serialReg.chunks[3] = reg1;
  mb.Hreg(11, serialReg.chunks[0]);
  mb.Hreg(12, serialReg.chunks[1]);
  mb.Hreg(13, serialReg.chunks[2]);
  mb.Hreg(14, serialReg.chunks[3]);
Unfortunately not getting any good results.
The master reads back:
11 - 26505
12 - 9029
13 - 1
14 - 0

I am also confused why use this complex approach for such a simple thing. Why create 4 variables reg1,reg2,reg3,reg4 and why use these chunks? Can we just not pass it straight from variable serial3. It seems to be that this is way too complex to do this simple thing ( transmitting series of characters)

Also, keep in mind that the serial number may contain any alphabet character for example:
ABPH193G
 
Last edited:

Thread Starter

zazas321

Joined Nov 29, 2015
936
What makes the most sense to me currently:

Code:
char serial[10];
strcpy(serial,"hello");
mb.Hreg(10, serial[0]);
mb.Hreg(11, serial[1]);
mb.Hreg(12, serial[2]);
mb.Hreg(13, serial[3]);
mb.Hreg(14, serial[4]);
mb.Hreg(15, serial[5]);
mb.Hreg(16, serial[6]);
mb.Hreg(17, serial[7]);
The master receives:

10- 104
11- 101
12- 108
13- 108
14- 111
15- 0
16- 0
17- 0

Converted decimals to asci I get "hello"
All I need is to convert decimal values to asci and construct a serial number. Isnt that much more simple than your previously suggested method?
 
Top