user33713: I am trying to read a SDM220 meter on my solar setup. I've been reading it using Modbus SCADA, so know it all works ok.
But I want to read it with my Arduino Mega 256. My problem is that when I run the code below the final value MtrKWh , is not float value. it's actual value is printed.
Here is a copy of the output.
17241 MtrKWh1 1129906176 MtrKWh1<<16 57737 MtrKWh2 1129963913 MtrKWh3 11299639.00 MtrKWh 2
the value '1129963913'       MtrKWh3, 
if I turn it into Binary is
01000011010110011110000110001001,
if I convert this to binary using https://www.h-schmidt.net/FloatConverter/
it gives me the value 
217.881, 
the very value I expect. Am I missing some brackets somewhere?
So how do I get MtrKWh to print its float value?
I have left a lot of commented out bits to show the several things I have tried. Sorry if it appears messy, I will tidy it up once I solve this problem.
I'm sure it is something simple, but, I haven't been able to see it so far.
Any sugestions would be appreciated.
    // MtrV, MtrC, MtrW, MtrKWh
    //void AddressRegistry_0()
    result = sdm220_modbus.readInputRegisters(0x48, 2);
    //while (!result == 0) {
    // delay(10);
    // result = sdm220_modbus.readInputRegisters(0x156,4);
    //}
   if (result == sdm220_modbus.ku8MBSuccess)
   {
    // 1 Serial.println((node.getResponseBuffer(0x0D) + node.getResponseBuffer(0x0E) << 16)/100.0f);
    // 2 pvpower = ((long)node.getResponseBuffer(0x03) << 16 | node.getResponseBuffer(0x02)) / 100.0f;
    // 3 long pressure = ((pressure_data_high << 16) | pressure_data_low) / 4;
    // 1 working ?? MtrKWh1 = (((long)sdm220_modbus.getResponseBuffer(0x0) + sdm220_modbus.getResponseBuffer(0x1) << 16)/6.f);
    // 2 working ?? MtrKWh1 = ((long)sdm220_modbus.getResponseBuffer(0x0) << 16 | sdm220_modbus.getResponseBuffer(0x1)) / 100.3f;
    // 3 working MtrKWh1 = (( sdm220_modbus.getResponseBuffer(0x0)  << 16) |  sdm220_modbus.getResponseBuffer(0x1))  / 16.3f;
    //
   // float MtrKWh0 =((float)(sdm220_modbus.getResponseBuffer( 0) << 16 | sdm220_modbus.getResponseBuffer( 1)));
    //      Serial.print(MtrKWh0);
    //    Serial.print(" MtrKWh0     ");

signed long MtrKWh1 = sdm220_modbus.getResponseBuffer(0x0);
Serial.print(" ");
Serial.print(MtrKWh1);
Serial.print(" MtrKWh1");

MtrKWh1 = MtrKWh1 << 16;
Serial.print(" ");
Serial.print(MtrKWh1);
Serial.print(" MtrKWh1<<16");

word MtrKWh2 = sdm220_modbus.getResponseBuffer(0x1);
Serial.print(" ");
Serial.print(MtrKWh2);
Serial.print(" MtrKWh2");

signed long MtrKWh3 = MtrKWh1 | MtrKWh2;
Serial.print(" ");
Serial.print(MtrKWh3);
Serial.print(" MtrKWh3");

float (MtrKWh) = float (MtrKWh3) / 10000.0;
Serial.print(" ");
Serial.print(MtrKWh);
Serial.print(" MtrKWh     ");

//uint32_t x = 0x3f322e3f;
//float y = *(float*)&x;
//Serial.print (y, 6);
// Serial.print(" MtrKWhxxx ");

   }
   else
   {
    rs485DataReceived = false;
    Serial.println("Fail sdm220_modbus.readInputRegisters(0x0, 1) ");
   }


user4143: You need to convert the format by overlaying one type on top of the other, rather than casting from one type to another.
1000 as an integer cast to a floating point value is still 1000.
You have an example of how it can be done in comments:
//float y = *(float*)&x;

However this method is called type punning and is frowned upon (there are compiler options that can prevent it being used).  Instead using a union is a better option:
union ifloat {
    uint8_t bytes[4];
    float val;
};

void setup() {
    ifloat f;
    Serial.begin(115200);
    f.bytes[3] = 0x43;
    f.bytes[2] = 0x59;
    f.bytes[1] = 0xE1;
    f.bytes[0] = 0x89;
    Serial.println(f.val, 4);

}

void loop() {
}

So you can get the byte order right your current numeric value of 1129963913 is 0x4359E189 in hexadecimal. Byte 3 is therefore the most significant byte and byte 0 the least significant. Note that it can change from system to system depending on the endianness of the chip. 
How it works is quite simple. You have 4 bytes in memory, and the union just gives you different views of those 4 bytes.
You can either see them as four individual bytes (f.bytes[0-3]) or as a floating point value (f.val). 
You can understand more about how the four bytes describe the floating point number by understanding more about the IEEE 754 Single Precision Floating Point Format.

You can achieve the same thing using reinterpret_cast, but that has to be done using pointers, not the values, which makes it a little more complex to understand:
// Your incoming 32-bit value
uint32_t l = 1129963913; 

// A pointer to the same memory with a different type
float *f = reinterpret_cast<float *>(&l);

// Print the *content* of the pointer interpreted as a float.
Serial.println(*f, 3); 


user33713: OK. So I never got the reinterpret_cast, thing to work. Went with Majenko's solution.
This code goes above Setup
// UNION, used to re-jig float
union ifloat {
uint8_t bytes[4];
float val;
};
// END UNION

And this is the modified code, with all the comments and bug print statements removed.
  // MtrV, MtrC, MtrW, MtrKWh
 //void AddressRegistry_0()
 result = sdm220_modbus.readInputRegisters(0x48, 2);
 if (result == sdm220_modbus.ku8MBSuccess)
 {
signed long MtrKWh1 = sdm220_modbus.getResponseBuffer(0x0);
word MtrKWh2 = sdm220_modbus.getResponseBuffer(0x1);
byte msb3 = MtrKWh1;
byte msb4 = MtrKWh1 >> 8;
byte msb1 = MtrKWh2;
byte msb2 = MtrKWh2 >> 8;
ifloat f;
f.bytes[3] = msb4;
f.bytes[2] = msb3;
f.bytes[1] = msb2;
f.bytes[0] = msb1;
Serial.println(f.val,3 );
  }
 else
 {
rs485DataReceived = false;
Serial.println("Fail sdm220_modbus.readInputRegisters(0x0, 1) ");
 }

And it is giving me the right numbers!
Thanks for input to all who did, it helps some times to be show which door to walk through.
Majenko, if you have time, and inclination, it would really help my understanding if you could describe your code. I am using it, but not sure how it works,or what most of it is doing. If you have the time.

33713: <p>I am trying to read a SDM220 meter on my solar setup. I've been reading it using Modbus SCADA, so know it all works ok.
But I want to read it with my Arduino Mega 256. My problem is that when I run the code below the final value MtrKWh , is not float value. it's actual value is printed.
Here is a copy of the output.</p>

<p>17241 MtrKWh1 1129906176 MtrKWh1&lt;&lt;16 57737 MtrKWh2 1129963913 MtrKWh3 11299639.00 MtrKWh 2</p>

<p>the value '1129963913'       MtrKWh3, </p>

<p>if I turn it into Binary is
01000011010110011110000110001001,</p>

<p>if I convert this to binary using <a href="https://www.h-schmidt.net/FloatConverter/" rel="nofollow noreferrer">https://www.h-schmidt.net/FloatConverter/</a>
it gives me the value </p>

<p>217.881, </p>

<p>the very value I expect. Am I missing some brackets somewhere?
So how do I get MtrKWh to print its float value?
I have left a lot of commented out bits to show the several things I have tried. Sorry if it appears messy, I will tidy it up once I solve this problem.
I'm sure it is something simple, but, I haven't been able to see it so far.
Any sugestions would be appreciated.</p>

<pre><code>    // MtrV, MtrC, MtrW, MtrKWh
    //void AddressRegistry_0()
    result = sdm220_modbus.readInputRegisters(0x48, 2);
    //while (!result == 0) {
    // delay(10);
    // result = sdm220_modbus.readInputRegisters(0x156,4);
    //}
   if (result == sdm220_modbus.ku8MBSuccess)
   {
    // 1 Serial.println((node.getResponseBuffer(0x0D) + node.getResponseBuffer(0x0E) &lt;&lt; 16)/100.0f);
    // 2 pvpower = ((long)node.getResponseBuffer(0x03) &lt;&lt; 16 | node.getResponseBuffer(0x02)) / 100.0f;
    // 3 long pressure = ((pressure_data_high &lt;&lt; 16) | pressure_data_low) / 4;
    // 1 working ?? MtrKWh1 = (((long)sdm220_modbus.getResponseBuffer(0x0) + sdm220_modbus.getResponseBuffer(0x1) &lt;&lt; 16)/6.f);
    // 2 working ?? MtrKWh1 = ((long)sdm220_modbus.getResponseBuffer(0x0) &lt;&lt; 16 | sdm220_modbus.getResponseBuffer(0x1)) / 100.3f;
    // 3 working MtrKWh1 = (( sdm220_modbus.getResponseBuffer(0x0)  &lt;&lt; 16) |  sdm220_modbus.getResponseBuffer(0x1))  / 16.3f;
    //
   // float MtrKWh0 =((float)(sdm220_modbus.getResponseBuffer( 0) &lt;&lt; 16 | sdm220_modbus.getResponseBuffer( 1)));
    //      Serial.print(MtrKWh0);
    //    Serial.print(" MtrKWh0     ");

signed long MtrKWh1 = sdm220_modbus.getResponseBuffer(0x0);
Serial.print(" ");
Serial.print(MtrKWh1);
Serial.print(" MtrKWh1");

MtrKWh1 = MtrKWh1 &lt;&lt; 16;
Serial.print(" ");
Serial.print(MtrKWh1);
Serial.print(" MtrKWh1&lt;&lt;16");

word MtrKWh2 = sdm220_modbus.getResponseBuffer(0x1);
Serial.print(" ");
Serial.print(MtrKWh2);
Serial.print(" MtrKWh2");

signed long MtrKWh3 = MtrKWh1 | MtrKWh2;
Serial.print(" ");
Serial.print(MtrKWh3);
Serial.print(" MtrKWh3");

float (MtrKWh) = float (MtrKWh3) / 10000.0;
Serial.print(" ");
Serial.print(MtrKWh);
Serial.print(" MtrKWh     ");

//uint32_t x = 0x3f322e3f;
//float y = *(float*)&amp;x;
//Serial.print (y, 6);
// Serial.print(" MtrKWhxxx ");

   }
   else
   {
    rs485DataReceived = false;
    Serial.println("Fail sdm220_modbus.readInputRegisters(0x0, 1) ");
   }
</code></pre>
 4143: <p>You need to convert the format by overlaying one type on top of the other, rather than casting from one type to another.</p>

<p>1000 as an integer cast to a floating point value is still 1000.</p>

<p>You have an example of how it can be done in comments:</p>

<pre><code>//float y = *(float*)&amp;x;
</code></pre>

<p>However this method is called <em>type punning</em> and is frowned upon (there are compiler options that can prevent it being used).  Instead using a <em>union</em> is a better option:</p>

<pre><code>union ifloat {
    uint8_t bytes[4];
    float val;
};

void setup() {
    ifloat f;
    Serial.begin(115200);
    f.bytes[3] = 0x43;
    f.bytes[2] = 0x59;
    f.bytes[1] = 0xE1;
    f.bytes[0] = 0x89;
    Serial.println(f.val, 4);

}

void loop() {
}
</code></pre>

<p>So you can get the byte order right your current numeric value of 1129963913 is 0x4359E189 in hexadecimal. Byte 3 is therefore the most significant byte and byte 0 the least significant. Note that it can change from system to system depending on the <em>endianness</em> of the chip. </p>

<p>How it works is quite simple. You have 4 bytes in memory, and the union just gives you different views of those 4 bytes.</p>

<p>You can either see them as four individual bytes (f.bytes[0-3]) or as a floating point value (f.val). </p>

<p>You can understand more about how the four bytes describe the floating point number by understanding more about the <a href="https://en.wikipedia.org/wiki/Single-precision_floating-point_format" rel="nofollow noreferrer">IEEE 754 Single Precision Floating Point Format</a>.</p>

<hr>

<p>You can achieve the same thing using <code>reinterpret_cast</code>, but that has to be done using <em>pointers</em>, not the values, which makes it a little more complex to understand:</p>

<pre><code>// Your incoming 32-bit value
uint32_t l = 1129963913; 

// A pointer to the same memory with a different type
float *f = reinterpret_cast&lt;float *&gt;(&amp;l);

// Print the *content* of the pointer interpreted as a float.
Serial.println(*f, 3); 
</code></pre>
 33713: <p>OK. So I never got the reinterpret_cast, thing to work. Went with Majenko's solution.
This code goes above Setup</p>

<pre><code>// UNION, used to re-jig float
union ifloat {
uint8_t bytes[4];
float val;
};
// END UNION
</code></pre>

<p>And this is the modified code, with all the comments and bug print statements removed.</p>

<pre><code>  // MtrV, MtrC, MtrW, MtrKWh
 //void AddressRegistry_0()
 result = sdm220_modbus.readInputRegisters(0x48, 2);
 if (result == sdm220_modbus.ku8MBSuccess)
 {
signed long MtrKWh1 = sdm220_modbus.getResponseBuffer(0x0);
word MtrKWh2 = sdm220_modbus.getResponseBuffer(0x1);
byte msb3 = MtrKWh1;
byte msb4 = MtrKWh1 &gt;&gt; 8;
byte msb1 = MtrKWh2;
byte msb2 = MtrKWh2 &gt;&gt; 8;
ifloat f;
f.bytes[3] = msb4;
f.bytes[2] = msb3;
f.bytes[1] = msb2;
f.bytes[0] = msb1;
Serial.println(f.val,3 );
  }
 else
 {
rs485DataReceived = false;
Serial.println("Fail sdm220_modbus.readInputRegisters(0x0, 1) ");
 }
</code></pre>

<p>And it is giving me the right numbers!
Thanks for input to all who did, it helps some times to be show which door to walk through.
Majenko, if you have time, and inclination, it would really help my understanding if you could describe your code. I am using it, but not sure how it works,or what most of it is doing. If you have the time.</p>
