Search code examples
cesp8266arduino-esp8266modbus-tcp

Read float values Modbus/TCP ESP8266


I'm currently working with ESP8266 as a master and can read data from EEM-MA370 which is already configured with the gateway.

Instantaneous values of HMI

Imagine that I want to read the value of U12.

ModbusIP mb; //ModbusIP object
IPAddress remote(10, 30 ,21 ,75);  // Address of Modbus Slave device
const int REG = 32768; //Dec value of U12

void loop(void){
  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);   
        Serial.print("Trying");
                // Try to connect if no connection
    }

When I run the code, it shows me the value as 60664 etc. I know that Modbus only supports 16bit, so I found a code that convert to 32 bit. But i didn't understand how it works actually. How would I know values of the var1 and var2 manually?

#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>

int main()
{
    uint16_t var1 = 255; // 0000 0000 1111 1111
    uint16_t var2 = 255; // 0000 0000 1111 1111

    uint32_t var3 = (var1 << 16) +  var2;

    printf("%#"PRIx32"\n", var3);
}

I would like to know, how can I read float values.

Many thanks


Solution

  • If your Modbus device send response with floating point data, you need to read 2 words (i.e. 4 bytes) data from the register, the return data will be a 4-byte data following the IEEE-754 floating point format.

    One more thing about Modbus is that it use Big Endian while your Arduino (and almost all modern computer architectures) is using Little Endian, so there is also a need to convert it from Big Endian to Little Endian.

    Here is an example(in C++) on how to get the floating point value sent by Modbus.

    // This is a valid modbus response return 4-bytes of data in floating format that representing a voltage value
    uint8_t response[] = {0x01, 0x04, 0x04, 0x43, 0x6B, 0x58, 0x0E, 0x25, 0xD8};
    
    float getFloat() {
    
        float fv = 0.0;
    
        ((uint8_t*)&fv)[3]= response[3];
        ((uint8_t*)&fv)[2]= response[4];
        ((uint8_t*)&fv)[1]= response[5];
        ((uint8_t*)&fv)[0]= response[6];
    
        return fv;
    }
    
    void setup() {
        Serial.begin(115200);
        
        float voltage = getFloat();
        Serial.println(voltage);
    }
    

    This will convert the values 0x43, 0x6B, 0x58 and 0x0E to a floating point and print out as:

    235.34