emelianov / modbus-esp8266

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.
Other
534 stars 188 forks source link

Writing floats / 32 bit values #180

Closed eqfive closed 2 years ago

eqfive commented 2 years ago

Hello there and thanks for the fantastic library and explanations in the "issues" section. As I am fairly unskilled as a programmer, my question will appear trivial to you. Still I hope I may pose it here as I am stuck at this point.

I am successfully reading a 32 bit value from a server device (controller of a heating unit) by reading two adjacent Modbus registers using the code you proposed:

float value32;
//int32 value32;

mb.readHreg(ip, REG_NR, (*uint16_t)&value32, 2); // read two sequental registers to 32 bit variable
//value32 = (value32>>16) | (value32<<16); // Uncomment for words swap

35

99

How do I do this the other way around - write a 32 bit value to two adjacent 16-bit registers on the server using your library?

This is the code I tested, though I have to clean up the bit conversion part in the end. It is somewhat redundant this way. I get the correct unscaled value, though negative instead of positive, so the "else"-part applies here - meaning the first 16 bits of the value being read are == 0 ?


uint32_t targetValue = 0;

void loop() {
if (!mb.isConnected(remote)) {
  if (!mb.connect(remote))
      Serial.print(".");
      delay(200);
  }

  if (mb.isConnected(remote)) {   // Check if connection to Modbus Slave is established
  uint16_t transaction = mb.readHreg(remote, REG, (uint16_t*)&targetValue, 2, cb, 3); // Initiate Read Hreg from Modbus Slave

  if (transaction) {
      while (mb.isTransaction(transaction)) mb.task(); // This is more strict implementation than using delay()
      if ((targetValue & (1 << 15)) == 0) {
        targetValue = (targetValue >> 16) | (targetValue << 16); // Uncomment for words swap
      } else {
        targetValue = ((targetValue >> 16) | (targetValue << 17)) * -1;
      }
      Serial.println((int32_t)targetValue);
    }
  }
delay(1000);
}```

Thank you in advance and best regards,
Julian
emelianov commented 2 years ago

Hello Julian,

It seems to me reading of signed int should work a little bit easier. Something like this way:

int32_t targetValue = 0; // Declare as signed int

void loop() {
if (!mb.isConnected(remote)) {
  if (!mb.connect(remote))
      Serial.print(".");
      delay(200);
  }

  if (mb.isConnected(remote)) {   // Check if connection to Modbus Slave is established
  uint16_t transaction = mb.readHreg(remote, REG, (uint16_t*)&targetValue, 2, cb, 3); // Initiate Read Hreg from Modbus Slave

  if (transaction) {
      while (mb.isTransaction(transaction)) {
        mb.task();
        yield();
      }
      targetValue = (targetValue >> 16) | (targetValue << 16); // Uncomment for words swap
      Serial.println(targetValue);
  }
  delay(1000);
}

Write Register code that case should be like:

int32_t tmp = targetValue;
tmp = (tmp >> 16) | (tmp << 16);
uint16_t transaction = mb.writeHreg(remote, REG, (uint16_t*)&tmp, 2, cb, 3);
eqfive commented 2 years ago

Hello Alexander, this is great, thank you so much! I will try reading/writing values tomorrow and close this question if the device cooperates :-) Best regards, Julian

eqfive commented 2 years ago

Hello again, it works like a charm, thank you again! I can now succesfully send temperature values to the heating controller. I had been on the verge of giving up already.