Convert float to byte and back again?

Hello!

I am struggling trying to send some data through a transceiver. All of my other values go through fine since they are of type uint8_t, however, when I am trying to send a float it comes out as 220....

This is what I am trying to do, my float value is 4828.9038
I am trying to store it in a packet whose class is this:
class CCPACKET
{
public:
/**

  • Data length
    */
    byte length;

/**

  • Data buffer
    */
    byte data[CC1101_DATA_LEN];

/**

  • CRC OK flag
    */
    boolean crc_ok;

/**

  • Received Strength Signal Indication
    */
    byte rssi;

/**

  • Link Quality Index
    */
    byte lqi;
    };

essential I am trying to store it as follows

CCPACKET data;
data.length = 20;
data.data[0] = 4828.9038;

This provides me with an output of 220 what I run Serial.println(data[0]);

So I believe my goal is to go from my float (4828.9038) to a byte(or many bytes) and then on the receiving end, go from byte to float.
I really don't care which format/type it is in so long as that on the receiving end I can parse out 4828.9038 since I will be typing that into a text box!

Thanks in advance!
I have been searching for 2 days now and can't seem to find a decent answer anywhere. (Please let me know if I have left out vital information!)

What makes you think you can stuff a 4 byte variable into a single byte? That's like trying to park four cars into the same spot; it just doesn't work. The simplest way is to use a union:

typedef union
{
  float number;
  uint8_t bytes[4];
} FLOATUNION_t;

Then if you want to access both the byte array and the actual float number:

FLOATUNION_t myFloat;
myFloat.number = 123.456; // Assign a number to the float
for (int i=0; i<4; i++)
{
  Serial.print(myFloat.bytes[i], HEX); // Print the hex representation of the float
  Serial.print(' ');
}
1 Like

There are several options. One is to convert float to a character string and send the character string. Any computer can then convert the character string back to a float, regardless of type. Another is to send the four bytes that represent the floating point variable value. For that, the "union" construct is useful, in which you can refer to the same memory space in two different ways: e.g.

union cvt {
float val;
unsigned char b[4];
} x;

Then in your code you might refer to these as in the following

x.val= 4828.9038;
send_message(x.b,4);

Pointer arithmetic is not something to tackle casually, but it gives you a concise solution:

float payload = 4828.9038;

CCPACKET data;

*(float *) data.data = payload;
data.length = sizeof(payload);
payload = *(float*) data.data;

Thank you everyone for your fast replies!
PeterH provided very simple code which gets the job done however using the provided code, the entire packet is set to contain the float. I am looking to send other data as well... my current packet looks like:
data.data[0] = hour;
data.data[1] = minute;
data.data[2] = seconds;
data.data[3] = milliseconds;
put float here
data.data[4] = day;
data.data[5] = month;
data.data[6] = year;

and now to integrate the float how would I go about doing that and then read it on the other side?

Thanks again!

now to integrate the float how would I go about doing that

Use the union, and copy the byte representation into your data packet. But do take a moment to read and understand the responses you've received.

union cvt {
float val;
unsigned char b[4];
} x;

float yourValue =  4338.123 ;
x.val = yourValue ;


data.data[0] = hour;
data.data[1] = minute;
data.data[2] = seconds;
data.data[3] = milliseconds;
*put float here*
data.data[4]=x.b[0] ;
data.data[5]=x.b[1] ;
data.data[6]=x.b[2] ;
data.data[7]=x.b[3] ;

data.data[8] = day;
data.data[9] = month;
data.data[10] = year;

optomus:
my current packet looks like:
data.data[0] = hour;
data.data[1] = minute;
data.data[2] = seconds;
data.data[3] = milliseconds;
put float here
data.data[4] = day;
data.data[5] = month;
data.data[6] = year;

Define a struct to represent your message format, and use the technique I showed you to copy the content of the struct into and out of the byte array.

jremington:

now to integrate the float how would I go about doing that

Use the union, and copy the byte representation into your data packet. But do take a moment to read and understand the responses you've received.

Okay so, I go ahead and create the union and now I have both my float value stored in myFloat.number and the byte representation of that stored in myFloat.bytes.

Now I go ahead and add it to my packet like this:
data.data[0] = hour;
data.data[1] = minute;
data.data[2] = seconds;
data.data[3] = milliseconds;
data.data[4] = myFloat.bytes[0];
data.data[5] = myFloat.bytes[1];
data.data[6] = myFloat.bytes[2];
data.data[7] = myFloat.bytes[3];
data.data[8] = day;
data.data[9] = month;
data.data[10] = year;

Now on the receiving end, I have all my other data fine, but the myFloat.bytes are come through as: 61, 231, 150, 69. My problem is I just don't understand how to convert that back into a float on the receiving end.
Sorry this is so tasking but I think I am lacking a little comprehension here. I do appreciate the fact everyone is taking time out of their day to slow pitch this in for me!

Again, take a moment to read and understand the responses you've received.
It is not that difficult. Don't be afraid to experiment until you do understand it!
Most of us don't want to write your program for you.

optomus:
Now on the receiving end, I have all my other data fine, but the myFloat.bytes are come through as: 61, 231, 150, 69. My problem is I just don't understand how to convert that back into a float on the receiving end.
Sorry this is so tasking but I think I am lacking a little comprehension here. I do appreciate the fact everyone is taking time out of their day to slow pitch this in for me!

Do what you did on the sender, but in reverse.

Alright, thanks guys, finally got through my thick skull. Thanks Arrch for spelling it out just enough!
Ended up using, on the sending end:
union
{
float misc;
unsigned char misc_byte[3];
}Misc;
Misc.misc = myValue;

And on the receiving end:

Misc.misc_byte[0] = packet.data[19];
Misc.misc_byte[1] = packet.data[20];
Misc.misc_byte[2] = packet.data[21];
Misc.misc_byte[3] = packet.data[22];
myValue = Misc.misc;

Thanks again!

There is another way to do it if you don't want to use structs.
Convert float to String, then you need your array of bytes and you pass each char of that String to the array of bytes...
I know it's not pretty but it works :stuck_out_tongue:

Hi,
Thank you all and with your helps I could solve my problem. I wrote a below sketches to demonstrate usage of union with struct for both writing and reading from NVRAM, which worked perfectly. Hope it helps others and below is the code:-

*/ *************************************************************

 Purpose:-
    This is a trial program made to test the typedef union 
    with various data types to see if it works with 
    in data writing and reading from DS1307 or similar NVRAM 
 Author:-
    Pradip Khare
 
 Courtesy:-
    Respective owner of the libraries writers, who make our programming easier

 Results:-
    it works perfectly check with Nano and RTC chip DS1307
    Also, it is 50 times faster than writtign to EEPROM of the processor 
    for the same data bytes written and read 

*/

#include <Wire.h>
#include "RTClib.h" // Courtsey Jeelabs- https://github.com/adafruit/RTClib


RTC_DS1307 rtc;  // i2c address 0x68 

// below is the data format that I need to write and read from NVRAM
struct myStruct{   
  boolean wasDataSaved;
  char  lastMode;
  float VlimitVal;
  float VsetVal;
  float AlimitVal;
  boolean wasOEnabled;
  int lastCurPos;
};

typedef union{        // union to contain above structure
  myStruct inSide;
  byte bytes[17];
} UNION_t;

long lM1,lM2;       // just to capture the time stamp in milli seconds

void setup() {
  Serial.begin(9600);
  rtc.begin();
  
  UNION_t oldSet;   // source
  UNION_t newSet;   // target
  
// the actual values to be written  
  oldSet.inSide.wasDataSaved  = false;
  oldSet.inSide.lastMode      = 'A'; 
  oldSet.inSide.VlimitVal     = 20.00;
  oldSet.inSide.VsetVal       = 10.00;
  oldSet.inSide.AlimitVal     =  0.50;
  oldSet.inSide.wasOEnabled   = true;
  oldSet.inSide.lastCurPos    = 3;

  // below dummies values in target to check the difference after NVRAM read
  newSet.inSide.wasDataSaved  = true;
  newSet.inSide.lastMode      = 0; 
  newSet.inSide.VlimitVal     = 0.0;
  newSet.inSide.VsetVal       = 0.0;
  newSet.inSide.AlimitVal     = 0.0;
  newSet.inSide.wasOEnabled   = false;
  newSet.inSide.lastCurPos    = 0;

  Serial.print("\nSize oldSet=");Serial.print(sizeof(oldSet));
  Serial.print("\nOld Bytes pattern to be written from union"); 
  for(int i=0;i<17;i++) {  
    Serial.print(" ");Serial.print(oldSet.bytes[i]); // Print the DEC representation of the data
  }
  
  lM1=millis();
  rtc.writenvram(0, oldSet.bytes, 17); // memory write
  lM2=millis();
  
  Serial.print("\nTook ");Serial.print(lM1-lM2);Serial.print(" milliSeconds to Write.");
  Serial.print("\n\nBefore Read values in source :-");
  Serial.print("\nwasDataSaved="); Serial.print(oldSet.inSide.wasDataSaved);
  Serial.print("\nlastMode    ="); Serial.print(oldSet.inSide.lastMode);
  Serial.print("\nVlimitVal   ="); Serial.print(oldSet.inSide.VlimitVal);
  Serial.print("\nVsetVal     ="); Serial.print(oldSet.inSide.VsetVal);
  Serial.print("\nAlimitVal   ="); Serial.print(oldSet.inSide.AlimitVal);
  Serial.print("\nwasOEnabled ="); Serial.print(oldSet.inSide.wasOEnabled);
  Serial.print("\nlastCurPos  ="); Serial.print(oldSet.inSide.lastCurPos);

  lM1=millis();
  rtc.readnvram (newSet.bytes,17, 0); // memory read
  lM2=millis();
  
  Serial.print("\nTook ");Serial.print(lM1-lM2);Serial.print(" milliSeconds to Read.");
  Serial.print("\nNew Bytes");
  for(int i=0;i<17;i++) {  
    Serial.print(" ");Serial.print(newSet.bytes[i]); // Print the hex representation of the float
  }
  Serial.print("\n\nFrom NVRAM actual values-");
  Serial.print("\nwasDataSaved="); Serial.print(newSet.inSide.wasDataSaved);
  Serial.print("\nlastMode    ="); Serial.print(newSet.inSide.lastMode);
  Serial.print("\nVlimitVal   ="); Serial.print(newSet.inSide.VlimitVal);
  Serial.print("\nVsetVal     ="); Serial.print(newSet.inSide.VsetVal);
  Serial.print("\nAlimitVal   ="); Serial.print(newSet.inSide.AlimitVal);
  Serial.print("\nwasOEnabled ="); Serial.print(newSet.inSide.wasOEnabled);
  Serial.print("\nlastCurPos  ="); Serial.print(newSet.inSide.lastCurPos);
}

void loop() {
  // put your main code here, to run repeatedly:
}

Below is the Results when executed:-

Size oldSet=17
Old Bytes Pattern 0 65 0 0 160 65 0 0 32 65 0 0 0 63 1 3 0
Took -2 milliSeconds to Write.

Before Read:-
wasDataSaved=1
lastMode =
VlimitVal =0.00
VsetVal =0.00
AlimitVal =0.00
wasOEnabled =0
lastCurPos =0
Took -2 milliSeconds to Read.
New Bytes pattern 0 65 0 0 160 65 0 0 32 65 0 0 0 63 1 3 0

From NVRAM:-
wasDataSaved=0
lastMode =A
VlimitVal =20.00
VsetVal =10.00
AlimitVal =0.50
wasOEnabled =1
lastCurPos =3