Go Down

### Topic: Convert hex string to float - how? (Read 4380 times)previous topic - next topic

#### strictlyrude27

##### Mar 31, 2011, 08:25 pmLast Edit: Mar 31, 2011, 08:28 pm by strictlyrude27 Reason: 1
Hi all -

My Arduino board will receive via Serial.read() a four-character hexadecimal string that I would like to convert into a float. The four character string is the IEEE754 representation of the float using four bytes.

I've looked all over the interwebs to figure out how to do this elegantly and I can't find anything - just how to convert a float to a string.

Can anyone help me? Thanks!

#### AWOL

#1
##### Mar 31, 2011, 08:25 pm
Does the hex represent an IEEE754 float value?
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

#### strictlyrude27

#2
##### Mar 31, 2011, 08:26 pm

Does the hex represent an IEEE754 float value?

Yessir. OP edited to denote that.

#### TeslaFan

#3
##### Mar 31, 2011, 08:44 pm
//Converting a float to 4 bytes:
float float_var;
byte byte_array[4];

memcpy(byte_array,&float_var,4);

// Use magic to transport the 4 bytes to the other computer. Put the bytes in an identical array as the sending computer.

//Copy them back!
float float_var;
byte byte_array[4];

memcpy(&float_var,byte_array,4);

Everything is made of bytes. There is nothing stopping you from taking them apart and putting them back together through pointer and memory manipulation.

With a float, byte ordering is the same in all systems. But with 16 and 32 bit ints, Intel PCs and Atmel microcontrollers store the bytes in a different order. This is called "Byte Ordering". You have to swap the bytes around if you use this method to send ints or longs.
Linux and Arduino, two great things that go great together!
http://www.roboticcore.com

#### davekw7x

#4
##### Mar 31, 2011, 10:16 pmLast Edit: Mar 31, 2011, 11:33 pm by davekw7x Reason: 1

//Converting a float to 4 bytes:
.
.
.
Everything is made of bytes. There is nothing stopping you from taking them apart and putting them back together through pointer and memory manipulation.

I'm with you up to here.

However...

Quote from: TeslaFan

With a float, byte ordering is the same in all systems.

Not true.  I have an application running on an Intel IXP420 arm-xscale processor.  Integer variables and floating point variables are all stored big-endian.  On my i386 workstations and on my ATmega boards, they are all stored little-endian.  See Footnote.

Quote from: TeslaFan

But with 16 and 32 bit ints, Intel PCs and Atmel microcontrollers store the bytes in a different order.

No they are not.  With avr-gcc (Arduino's compiler), integer and floating point variables are all stored little-endian (same as on my i386 Windows and Linux workstations).

Quote from: TeslaFan
You have to swap the bytes around if you use this method to send ints or longs.

You have to swap bytes if (and only if) the transmitter and receiver are different-endian.  Period. Full Stop.

Higher level network protocols usually (almost always, I think) specify that binary bytes (octets) of multi-byte numerical quantities be sent in big-endian order.  Compiler vendors usually supply byte-swapping functions or macros that convert machine-endian integers to network-endian (i.e. big-endian) representation.    By using vendor-supplied functions like htons, htonl, ntohs, ntohl, etc. the program source can be compiled on either type of system without modification.  These create no overhead for big-endian systems but actually require that the processor do some work little-endian systems.

Regards,

Dave

Footnote:

Arduino sketch:
Code: [Select]
`void setup(){    Serial.begin(9600);    uint16_t x = 0x1234;    float z = 1.125e4;    unsigned i;    unsigned char *chpt;    Serial.print("Here's the 16-bit integer         : 0x");    Serial.println(x, HEX);    chpt = (unsigned char *)&x;    Serial.print("Here are the bytes in memory order: ");    for (i = 0; i < sizeof(x); i++) {        Serial.print("0x");        Serial.print(chpt[i],HEX);        Serial.print(" ");    }    Serial.println();Serial.println();    chpt = (unsigned char *)&z;    Serial.print("Here's the float                  : ");Serial.println(z);    Serial.print("Here are the bytes in memory order: ");    for (i = 0; i < sizeof(z); i++) {        Serial.print("0x");        Serial.print(chpt[i],HEX);        Serial.print(" ");    }    Serial.println();}void loop(){}`

Output from Duemilanove:

Here's the 16-bit integer         : 0x1234
Here are the bytes in memory order: 0x34 0x12

Here's the float                  : 11250.00
Here are the bytes in memory order: 0x0 0xC8 0x2F 0x46

The integer is obviously stored least-significant byte first, right?
Then...
Look at the bytes of the floating point number and you can see that the float is stored least-significant byte first.
(You can work it out using a reference like: Floating Point on Wikipedia.)

Equivalent standard C program compiled with GNU gcc on my Linux workstation:
Code: [Select]
`#include <stdio.h>#include <stdint.h>int main(){    uint16_t x = 0x1234;    float z = 1.125e4;    unsigned i;    unsigned char *chpt;    chpt = (unsigned char *)&x;    printf("Here's the 16-bit integer         : 0x%02x\n", x);    printf("Here are the bytes in memory order: ");    for (i = 0; i < sizeof(x); i++) {        printf("0x%02x ", chpt[i]);    }    printf("\n");    printf("Here's the float                  : %.2f\n", z);    chpt = (unsigned char *)&z;    printf("Here are the bites in memory order: ");    for (i = 0; i < sizeof(z); i++) {        printf("0x%02x ", chpt[i]);    }    printf("\n");    return 0;}`

Output:

Here's the 16-bit integer         : 0x1234
Here are the bytes in memory order: 0x34 0x12
Here's the float                  : 11250.00
Here are the bites in memory order: 0x00 0xc8 0x2f 0x46

Same results as with Arduino: Little-endian all the way.

Then:

When I cross-compiled the same C program with arm-linux-gcc for the xscale and ran the result on the target system, here's the output:

Here's the 16-bit integer         : 0x1234
Here are the bytes in memory order: 0x12 0x34
Here's the float                  : 11250.00
Here are the bites in memory order: 0x46 0x2f 0xc8 0x00

Big-endian all the way!

Final note (I promise.  Really)
I don't remember ever having to send binary floating point numbers from workstation to arm-xscale system (or anything else to anything else either), but if I ever need to, I might check this out: Floating-point and Endianness on Wikipedia

#### TeslaFan

#5
##### Mar 31, 2011, 10:33 pm
Is that right? I could have sworn I was sending data from Linux unswapped and swapping it on receipt on the Arduino end.

Heh. Dave, you're absolutely right. I was swapping on both sides. I had deluded myself into thinking the Arduino was ordered the other way.

Thanks for correcting that!
Linux and Arduino, two great things that go great together!
http://www.roboticcore.com

#### gardner

#6
##### Mar 31, 2011, 11:43 pm

Code: [Select]
`//Converting a float to 4 bytes:float float_var;byte byte_array[4];memcpy(byte_array,&float_var,4);`

Save yourself some memory and copying...

Code: [Select]
`union {   //Converting a float to 4 bytes:   float float_var;   byte byte_array[4];} both;  both.float_var = 3.1415926535;  send(both.byte_array[0]);  // or whatever it is you want to do with the bytes  send(both.byte_array[1]);  send(both.byte_array[2]);  send(both.byte_array[3]);`

#### strictlyrude27

#7
##### Apr 05, 2011, 09:38 am

Code: [Select]
`//Converting a float to 4 bytes:float float_var;byte byte_array[4];memcpy(byte_array,&float_var,4);`

Save yourself some memory and copying...

Code: [Select]
`union {   //Converting a float to 4 bytes:   float float_var;   byte byte_array[4];} both;  both.float_var = 3.1415926535;  send(both.byte_array[0]);  // or whatever it is you want to do with the bytes  send(both.byte_array[1]);  send(both.byte_array[2]);  send(both.byte_array[3]);`

This worked fine, although I ran into the endianness problem described above. I was receiving a hex string big-endian style and needed to flip to little-endian before the float was represented correctly.

Thanks to everyone for their help and insight on this!

Go Up

Please enter a valid email to subscribe