Search code examples
c#.netfloating-pointmodbusmodbus-tcp

Convert register values to float 32 big endian


I have two signed register values 17147 and -27394. They are in order of High-Low bits. I want to get the value float 32 big endian value using these value. I have used following code to convert to value.

My code

int intValue = 17147;
intValue <<= 16;
intValue += -27394;
byte[] bytes = BitConverter.GetBytes(intValue);
double readingValue = BitConverter.ToSingle(bytes, 0);

According to above code reading shows as 125.291. But modbus tools & other online convertions says that value should be 125.791.

Please note that some times reading is okay for some values. Actual value and converted value difference is not the same.


Solution

  • You're combining the two registers together incorrectly.

    • 17147 is hex 42 FB (or 00 00 42 FB as a 4-byte value)
    • -27394 is hex 94 FE as a 2-byte value, or FF FF 94 FE as a 4-byte value
    • Therefore intValue should have the hex value 42 FB 94 FE, but your way of combining 42 FB and 94 FE gives you 42 FA 94 FE.

    You're being caught out by the fact that -27394 is presented as a negative number, but that's just the way that your software has chosen to interpret those 2 bytes. You're then treating it as a signed 4-byte value rather than an unsigned 2-byte value when you come to combine it with the 17147.

    When we combine 17147 and -27394, we need to make sure that we just look at the lower 2 bytes of each. That will undo any damage that was done by interpreting the values as signed 4-byte numbers.

    int upper = 17147;
    int lower = -27394;
    int intValue = ((upper & 0xFFFF) << 16) | (lower & 0xFFFF);
    

    Now:

    byte[] bytes = BitConverter.GetBytes(intValue);
    double readingValue = BitConverter.ToSingle(bytes, 0);
    Console.WriteLine(readingValue);
    

    Gives 125.79100036621094, as expected.