ASCII input to floating point value

Hello everyone,

I am stuck here on this problem.

I have a device which gives me 16 bytes of data of which first 8 byes are 00 33 00 00 00 00 A0 C2 (all HEX). Now Bytes 7 to 4 ie C2A00000 gives me -80.00 in floating point. How do I get to that?

I got it working in Raspberry Pi, Spark Core but in Arduino I am really facing syntax problems. Using sscanf and sprintf seems to be very tiresome task in Arduino, atleast for me. If required I can post the code snippets.

Can anyone cite a simple example like starting with

unsigned char buffer[8] = {0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xC2}; and helping me get -80.00 from byte 7 to 4.

Your help is appreciated.

Thanks, Gaurav

IEEE-754

Using sscanf and sprintf seems to be very tiresome task in Arduino, atleast for me.

I can't imagine why, but it doesn't really matter, because neither is appropriate for handling binary data.

If required I can post the code snippets.

Don't bother. We'll just tell you to take them to http://snippets-r-us.com.

Storing the 4 byte values in the byte array in a union, and then using the float value in the union, seems the simplest way.

unsigned char buffer[8] = {
  0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xC2}; 

union
{
  float f;
  uint8_t c[4];
} 
conv;

void setup() 
{
  Serial.begin(115200);
  Serial.println("Start ");

  conv.c[0] = buffer[4];
  conv.c[1] = buffer[5];
  conv.c[2] = buffer[6];
  conv.c[3] = buffer[7];

  Serial.println(conv.f, 4);
}

void loop() 
{
}

@Rob: Interesting, as I was writing a similar approach (i.e., a union). I then noticed that your code was smaller than mine (3906 to 3932):

/*****
    This function converts a fixed-form, 8-byte data packet from ASCII to float

  Parameter list:
    unsigned char *packet    pointer to the packet

  Return value:
    float
*****/
float ConvPacketToFloat(unsigned char *packet) 
{
  int i;
  
  union {
    float f;
    uint8_t c[4];
  } conv;

  for (i = 0; i < 4; i++)        // This uses a little more code space
    conv.c[i] = *(packet + i + 4);
  return conv.f;
}

void setup() 
{
  Serial.begin(115200);
  Serial.println("Start ");

  Serial.println(ConvPacketToFloat(buffer), 4);
}

I then move the union out of the function and the code size dropped to 3914. I then unwound the for loop in the function to use direct assignments like you did but the code size didn’t change. I then moved the union back into the function and the code size dropped to 3896.
My conclusion is that moving the code into a function has very little impact on code size and probably not too much of an impact on speed. Given that, I wonder what the readers here would advise a newbie when it comes to writing the code: 1) keep the code direct or 2) bury it in a function? (I’m a retired programming teacher and I’ve had this debate before, but mostly with academics. Asking some “real” programmers is probably better!)

I wonder what the readers here would advise a newbie when it comes to writing the code: 1) keep the code direct or 2) bury it in a function?

Do you need to do it once? Or many places in the code? There is no one satisfactory answer. If it needs to be done once, directly in the function (and that includes loop()) where it is needed. If it is a useful function (would be called from many places), make it a function.

I'll move code into a function even if it's only called from one place just to make the calling function simpler. Getting a decent name for the new function is a bonus too.

this variation is bit creepy but - Sketch uses 3,870 bytes (11%) -
Works because the bytes seem to be in right order.

unsigned char buffer[8] = {
  0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xC2}; // and helping me get -80.00 from byte 7 to 4.

float convert(uint8_t * buf)
{
  return (float) *((float*)&buf[4]);  // kids don't do this at home ;)
}

void setup() 
{
  Serial.begin(115200);
  Serial.println("Start ");

  Serial.println(convert(buffer), 4);
}

void loop() 
{
}

It is fastest too.

perfomance - tested on UNO with IDE1.5.4

unsigned char buffer[8] = {
  0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xC2}; // and helping me get -80.00 from byte 7 to 4.

float convert(uint8_t * buf)
{
  return (float) *((float*)&buf[4]);
}

float ConvPacketToFloat(unsigned char *packet) 
{
  int i;

  union {
    float f;
    uint8_t c[4];
  } 
  conv;

  for (i = 0; i < 4; i++)        // This uses a little more code space
    conv.c[i] = *(packet + i + 4);
  return conv.f;
}

float convert2(unsigned char *buf) 
{
  union {
    float f;
    uint8_t c[4];
  } 
  conv;

  conv.c[0] = buf[4];
  conv.c[1] = buf[5];
  conv.c[2] = buf[6];
  conv.c[3] = buf[7];

  return conv.f;
}

float f;

void setup() 
{
  Serial.begin(115200);
  Serial.println("Start ");

  uint32_t start = micros();
  for (int i=0; i< 1000; i++) f = convert(buffer);
  uint32_t stop = micros();
  Serial.println(stop - start);
  Serial.println(f, 4);

  start = micros();
  for (int i=0; i< 1000; i++) f = ConvPacketToFloat(buffer);
  stop = micros();
  Serial.println(stop - start);
  Serial.println(f, 4);

  start = micros();
  for (int i=0; i< 1000; i++) f = convert2(buffer);
  stop = micros();
  Serial.println(stop - start);
  Serial.println(f, 4);

}

void loop() 
{
}

468
-80.0000
968
-80.0000
716
-80.0000

Thanks everyone for your valuable inputs.

-Gaurav