Cast from array to float: Code OK?

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a compass module with an SPI that sends the heading information as IEEE floating point.

The float number is contained in a longer data stream, the four bytes for its representation are organized MSB first. The exaxt position of the four bytes inside the data stream is know.

I´ve got the following variable definitions:

uint8_t  incoming_data[24];
uint8_t  tmpstr[4];
float    heading;

The four bytes of the float are in the incoming_data array at positions 3 to 6.

Since avr-gcc also uses the 32 bit IEEE-representation for floats, after receiving the whole 24 byte data stream, I do:

memcpy(tmpstr,incoming_data+3,4);
heading = (float) *tmpstr;

I´m unsure if this cast will work out OK. Could you please comment on this?

Thanks,

Ingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ikletti wrote:
I´m unsure if this cast will work out OK.

So just don't do it - use a union instead! 8)

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay,

but I haven´t used any union before :oops:
(Although I´ve seen some in example programs).

What exactly would the use of a union help in this case? I´ll need to accomplish some floating point operations on the acquired heading.

Ingo

Edit:

OK, I´ve done some reading on unions but still am unsure how to use them.
Are you talking of something like this?:

union
{
  uint8_t  byte1;
  uint8_t  byte2;
  uint8_t  byte3;
  uint8_t  byte4;
} transfer;

and then

transfer.byte1 = incoming_data[3];
transfer.byte2 = incoming_data[4];
transfer.byte3 = incoming_data[5];
transfer.byte4 = incoming_data[6];
heading = (float) transfer;
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

With the union you want:

union
{
  uint8_t bytes[4];
  float heading;
} headingUnion;

headingUnion.bytes[0] = incoming_data[3];
headingUnion.bytes[1] = incoming_data[4];
headingUnion.bytes[2] = incoming_data[5];
headingUnion.bytes[3] = incoming_data[6];

Then you would use headingUnion.heading to access the float value.

But why bother with the union or tmpstr at all. Just do:

memcpy(void*(&heading), incoming_data+3,4);

memcpy just wants a pointer to a memory space. It doesn't care at all what it points to, it always treats it as bytes.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ikletti wrote:
What exactly would the use of a union help in this case?

It would save you messing about with possibly incorrect pointer casts!

Pointers are very powerful things but, if misused, this makes them very dangerous things! :shock:

I think the union is probably safer - especially as you say yourself that you're struggling with the pointer casts...

However, if all you need is an address to tell memcpy where to put its data, the pointer should be fine - as Steve A. said!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ikletti wrote:

union
{
  uint8_t  byte1;
  uint8_t  byte2;
  uint8_t  byte3;
  uint8_t  byte4;
} transfer;

and then

transfer.byte1 = incoming_data[3];
transfer.byte2 = incoming_data[4];
transfer.byte3 = incoming_data[5];
transfer.byte4 = incoming_data[6];
heading = (float) transfer;

not quite. All teh elements of a union at teh same level will occupy the same staring address. (unlike a struct where tehy are organized sequentially) So in your union, all bytes 1-4 will occupy the same single bye in RAM which is not what you want. There are a few ways to do what you want, using unions. the most obvious two are using an array in the union, or using a struct in the union.

so using an array would look like

union {
uint8_t as_bytes[4]
float   as_float;
} transfer;
.
.
.
transfer.as_byte[1] = incoming_data[3];
transfer.as_byte[2] = incoming_data[4];
transfer.as_byte[3] = incoming_data[5];
transfer.as_byte[4] = incoming_data[6];

heading = transfer.as_float;

or as a struct

union {
struct {
uint8_t byte1;
uint8_t byte2;
uint8_t byte3;
uint8_t byte4;
} stream;
float as_float;
} transfer;
.
.
.
transfer.stream.byte1 = incoming_data[3];
transfer.stream.byte2 = incoming_data[4];
transfer.stream.byte3 = incoming_data[5];
transfer.stream.byte4 = incoming_data[6];

heading = transfer.as_float;

Of course with some careful arrangement, you don't need to copy in and out of the union to variables.

union {
uint8_t  stream[24];
struct {
uint8_t stream_header[4];
float heading
uint8_t next_data_field;
.
.
.
uint8_t last_data_field;
} data;
} transfer;
.
.
.
// in your receive routine
transfer.stream[n] = SPI_DATA;
.
.
.
// in your main loop
if(transfer.data.heading==1.0) {

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Steve A, awneil, glitch,

thanks for your comments. I came down with a cold yesterday, I´ll try to get my head around this once it stops aching.

Ingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
// Option 1
memcpy(&heading,incoming_data+3,4); 

// Option 2
heading = *(float*) (incoming_data+3);

// Option 3
float *pheading = (float*)  (incoming_data+3);

The third option is more efficient since no bytes are moved, and option 2 is better than option 1 since no subroutine call and/or loop is required.

C: i = "told you so";