I have 4 bytes coming from serial want to convert to float variable
could you please help me?
Thanks in Advance
I have 4 bytes coming from serial want to convert to float variable
could you please help me?
Thanks in Advance
uint8_t bytes[4] = { 0, 1, 2, 3 }; // fill this array with the four bytes you received
static_assert(sizeof(float) == 4, "float size is expected to be 4 bytes");
float f;
memcpy (&f, bytes, 4);
Pieter
void loop()
{
uint8_t bytes[4] = {0X81,0X11,0X99,0X9A}; // fill this array with the four bytes you received
static_assert(sizeof(float) == 4, "float size is expected to be 4 bytes");
float f;
memcpy (&f, bytes, 4);
Serial.println(f);
delay(1000);
}
the result is -0.00
it must be as 4.55
Try the following codes with permissible value for the highest byte of the 4-byte data, which must agree with the template of IEEE-754 Standards (Fig-1).
void setup()
{
Serial.begin(9600);
uint8_t bytes[4] = {0X81, 0X11, 0X99, 0X41}; //{0X81, 0X11, 0X99, 0X9A}; //
long x = (long)bytes[3]<<24|(long)bytes[2]<<16|bytes[1]<<8|bytes[0];
union
{
long y;
float z;
}data;
data.y = x;
Serial.println(data.z,2); //shows: 19.13
}
void loop()
{
}
IEEE-754/binary32 Template for 32-bit Floating Point Number:
long x = (long)bytes[3]<<24|(long)bytes[2]<<16|bytes[1]<<8|bytes[0];
For safety, I'd always use "unsigned long" for the cast.
TheMemberFormerlyKnownAsAWOL:
long x = (long)bytes[3]<<24|(long)bytes[2]<<16|bytes[1]<<8|bytes[0];
For safety, I'd always use "unsigned long" for the cast.
Thanks! I have noted it down.
I am using this value :
uint8_t bytes[4] = {0X81, 0X11, 0X99, 0X9A};
the result is -0.00
it is not correct
GolamMostafa:
void setup()
{
Serial.begin(9600);
uint8_t bytes[4] = {0X81, 0X11, 0X99, 0X41}; //{0X81, 0X11, 0X99, 0X9A}; //
long x = (long)bytes[3]<<24|(long)bytes[2]<<16|bytes[1]<<8|bytes[0];
union
{
long y;
float z;
}data;
data.y = x;
Serial.println(data.z,2); //shows: 19.13
}
void loop()
{
}
Your code invokes undefined behavior. Using a union for type punning is not allowed:
float value 4.55 equal in HEX 0X81 0X11 0X99 0X9A
void setup()
{
Serial.begin(2400);
uint8_t bytes[4] = {0X81, 0X11, 0X99, 0X9A};
long x = (long)bytes[3]<<24|(long)bytes[2]<<16|bytes[1]<<8|bytes[0];
union
{
long y;
float z;
}data;
data.y = x;
Serial.println(data.z,2); //shows: -0.00
}
void loop()
{
}
but the result I got is not correct -0.00
void setup()
{
Serial.begin (115200);
float x = 4.55;
const byte* px = (byte*) &x;
Serial.print (F("Raw: "));
Serial.println (x, 3);
for (int i = 0; i < 4; i++) {
Serial.print (F("Hex ["));
Serial.print (i);
Serial.print (F("] = 0x"));
if (px[i] < 16)
Serial.print (0);
Serial.println (px[i], HEX);
}
byte floatVal [4] = {0x9A, 0x99, 0x91, 0x40};
float y;
uint32_t* const py = (uint32_t*) &y;
*py = ((uint32_t) floatVal [3] << 24) |
((uint32_t) floatVal [2] << 16) |
((uint32_t) floatVal [1] << 8) |
((uint32_t) floatVal [0] << 0);
Serial.print (F("Reconstituted: "));
Serial.println (y, 3);
}
void loop()
{
}
Eleckits:
float value 4.55 equal in HEX 0X81 0X11 0X99 0X9A
No it's not. 4.55 as a 32-bit IEEE754 floating point number is 0x4091999a.
Also mind the Endianness.
Eleckits:
void setup()
{
Serial.begin(2400);
uint8_t bytes[4] = {0X81, 0X11, 0X99, 0X9A};
long x = (long)bytes[3]<<24|(long)bytes[2]<<16|bytes[1]<<8|bytes[0];
union
{
long y;
float z;
}data;
data.y = x;
Serial.println(data.z,2); //shows: -0.00
}
void loop()
{
}
but the result I got is not correct -0.00
Don't use unions to convert from a long to a float, as mentioned above. Use memcpy instead.
TheMemberFormerlyKnownAsAWOL:
float y;
uint32_t* const py = (uint32_t*) &y;
*py = ((uint32_t) floatVal [3] << 24) |
((uint32_t) floatVal [2] << 16) |
((uint32_t) floatVal [1] << 8) |
((uint32_t) floatVal [0] << 0);
This isn't any better than using a union. It still breaks the strict aliasing rule.
y is a float, you cannot alias it with a uint32 pointer.
PieterP:
This isn't any better than using a union. It still breaks the strict aliasing rule.
y is a float, you cannot alias it with a uint32 pointer.
Can you break it?
TheMemberFormerlyKnownAsAWOL:
Can you break it?
No. It's undefined behavior. I've been bitten by this before, everything worked in debug mode, but when enabling optimizations, I got invalid results. Adding print statements around it changed the outcome of the program entirely.
Here's an in-depth explanation: What is Strict Aliasing and Why do we Care? · GitHub
@TheMemberFormerlyKnownAsAWOL
the hex value of 4.55 is : 0X81 0X11 0X99 0X9A

is there any mistake?
Eleckits:
@TheMemberFormerlyKnownAsAWOLthe hex value of 4.55 is : 0X81 0X11 0X99 0X9A
[img]http://C:\Users\hitro\Pictures\Ashampoo Snap 9\float to hex.png[/img]
is there any mistake?
The number you mention is
-6.33076×10-23 (Little Endian) or -2.67425×10-38 (Big Endian). Where did you get the number from?
Linking to images on your local hard drive won't work.
No mistake, just a misunderstanding (on your part) of endianess.
And sign bits.
PieterP:
It still breaks the strict aliasing rule.
It isn't a very strict "strict rule", is it?
Eleckits:
I am using this value :uint8_t bytes[4] = {0X81, 0X11, 0X99, 0X9A};
the result is -0.00
it is not correct
No. -0.00 is the correct result. Let us see that this is indeed correct (considering little endianess).
From Fig-1 of Post#3, the float value for your 4-byte data:
9A991181 (1 00110101 00110010001000110000001)
==> (-1)1*(1+ Si=1 to 23*b23-i*2-i)*2e-127
==> -1 (1+ Si=1 to 23*b23-i*2-i)*200110101 - 127
==> -1 (1+Si=1 to 23*b23-i*2-i)*2-74
==> -1 (1+Si=1 to 23*b23-i*2-i) 1/274
==> -1 (1+Si=1 to 23*b23-i*2-i)*0.00000000000..........
==> -0.00
this is the code from proton pic basic it is sending float value 4.55 via serial then I see it on LCD as Hex as :
9A991181
Dim SerData As Float
Main:
SerOut PORTA.2, 396, [SerData]
SerData = 4.55
Print At 1,1, Hex SerData
DelayMS 2000
Cls
GoTo Main
so could you please tell me what is the problem?