Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I read registers in different blocks? RTU between slave and master. #353

Closed
pllagunos opened this issue May 28, 2024 · 1 comment
Closed

Comments

@pllagunos
Copy link

I want to be able to read holding registers in "blocks" (i.e a group of registers) and also as single registers. Here's my attempt at doing so:

Slave code on an ESP32 s3

#include <Arduino.h>
#include <ModbusRTU.h>

// Define your application variables
float PV;
float SP;

// Create ModbusRTU object
ModbusRTU mb;

uint16_t cbRead(TRegister* reg, uint16_t val) {
  uint16_t address = reg->address.address;
  Serial.printf("Address read: %d\n", address);
  
  switch (address) {
    case 1:
      PV = random(0, 100) / 10.0;
      Serial.printf("PV: %.2f\n", PV);
      return static_cast<uint16_t>(PV * 10);
    case 2:
      SP = random(0, 100) / 10.0;
      Serial.printf("SP: %.2f\n", SP);
      return static_cast<uint16_t>(SP * 10);
    case 3:
      return static_cast<uint16_t>(random(0,100));
      
    default:
      return 0;
  }
}

void setup() {
  Serial.begin(115200); // Configure the serial port for Modbus communication
  Serial2.begin(115200, SERIAL_8N1, 32, 26);

  mb.begin(&Serial2, 13);
  mb.setBaudrate(115200);
  mb.slave(1); // Set Modbus ID to 1

  // Add holding registers and set callbacks
  mb.addHreg(1, 0xF0F0, 3);
  mb.onGetHreg(1, cbRead, 3);
}

void loop() {
  mb.task(); // Process Modbus communication
  delay(10);
}

Master code on a ESP32 devkit

#include <ModbusRTU.h>

#define SLAVE 1

// Create ModbusRTU object
ModbusRTU mb;

void setup() {
  Serial.begin(115200); // Configure the serial port for Modbus communication

  Serial2.begin(115200, SERIAL_8N1, 19, 20);
  Serial2.setTimeout(200);

  mb.begin(&Serial2, 21);
  mb.setBaudrate(115200);
  mb.master();
}

void loop() {
  static uint32_t ts;
  if (millis() - ts > 1500) {
    ts = millis();
    uint16_t res[2];
    float PV;
    float SP;

    // Read PV & SP registers from the slave
    if (mb.readHreg(SLAVE, 1, res, 2)) {
      PV = res[0] / 10.0;
      SP = res[1] / 10.0;
      Serial.printf("PV: %.2f\n", PV);
      Serial.printf("SP: %.2f\n", SP);
    } 
    else {
      Serial.println("Failed to read PV and SP");
    }

    // Read single register from the slave, address 3
    uint16_t var;
    if (mb.readHreg(SLAVE, 3, &var, 1)) {
      Serial.printf("var: %d\n", var);
    } 
    else {
      Serial.println("Failed to read var");
    }

  }

  mb.task(); // Process Modbus communication
  delay(10);
}

The result is this:
15:35:29.870 -> PV: 6.80
15:35:29.870 -> SP: 1.10
15:35:29.870 -> Failed to read var
15:35:31.348 -> PV: 0.30
15:35:31.348 -> SP: 4.80
15:35:31.348 -> Failed to read var
15:35:32.858 -> PV: 0.60
15:35:32.858 -> SP: 0.10

If I comment the code related to reading PV and SP, var is succesfully read:
15:33:25.531 -> var: 76
15:33:27.043 -> var: 51
15:33:28.555 -> var: 88
15:33:30.033 -> var: 48

I tried adding a delay between the two but it doesn't work.

@emelianov
Copy link
Owner

Main point is that mb.readHreg() just sends request and returns. That is query runs async. Response processed bt mb.task(). mb.slave() returns true while request is in-progress.
Simplest way to resolve you problem is to wait the response (or timeout)

   // Read PV & SP registers from the slave
    if (mb.readHreg(SLAVE, 1, res, 2)) {
      while (mb.salve()) { // Wait response received
        yield();
        mb.task();
      }
      PV = res[0] / 10.0;
      SP = res[1] / 10.0;
      Serial.printf("PV: %.2f\n", PV);
      Serial.printf("SP: %.2f\n", SP);
    } 
    else {
      Serial.println("Failed to read PV and SP");
    }

    // Read single register from the slave, address 3
    uint16_t var;
    if (mb.readHreg(SLAVE, 3, &var, 1)) {
      while (mb.salve()) { // Wait response received
        yield();
        mb.task();
      }
      Serial.printf("var: %d\n", var);
    } 
    else {
      Serial.println("Failed to read var");
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants