Byte array to float issues

I have been working a quick program to get data from an ultrasonic flowmeter over rs485 using the modbus protocol. It is basically intended to be a port of another quick program I wrote in matlab.

I am having no issues at all with the serial communication the only issue is that I cant seem to convert my byte array to a float correctly.

I have used C extensively so initially I was trying to cast the array to a float pointer and then dereference it. This didn't seem to work. My second idea was to use a union, which also didn't work.

I began to wonder if it was just an issue printing floats in general but it doesn't seem to be the case.

Below is some of my test code:

union FloatConv {
  float f;
  uint16_t i;
  byte b[4];
} floatConv;

uint8_t data[] = {0x3F,0x80,0x00,0x00}; //float for 1

void setup() {
  Serial.begin(115200);

  float * dataFloat;
  dataFloat = (float *) data;
  Serial.print("float from pointer casting: ");
  Serial.println(floatConv.f);  
  
  floatConv.b[0] = data[0];
  floatConv.b[1] = data[1];
  floatConv.b[2] = data[2];
  floatConv.b[3] = data[3];
  
  Serial.print("\nFrom union conversion:\ninteger: ");
  Serial.println(floatConv.i);
  Serial.print("float: ");  
  Serial.println(floatConv.f);

  float f = 1.0;
  Serial.print("\nPrinting a 'normal' float: ");
  Serial.print(f);
  
  
  
}

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

}

and the output:

float from pointer casting: 0.00

From union conversion:
integer: 32831
float: 0.00

Printing a 'normal' float:1.00

I am beginning to get quite frustrated with this. Any insight would be appreciated.

Tobin.

What are you doing? It looks like major over-thinking to me. Can't you pass ASCII characters down the serial port?

  float * dataFloat;
  dataFloat = (float *) data;
  Serial.print("float from pointer casting: ");
  Serial.println(floatConv.f);

I don't know why you are printing floatConv.f there, because you haven't assigned anything to it yet.

Because it is in a union so it shares the memory location of the other union members. Notice I also did not assign the value of floatConv.i it was set by changing b[].

No, it was not.

Looking back, there is indeed an error in that code, it obviously should have been printing dataFloat.
Regardless, the result is 0.00.

If you had read the initial post you would realize I cant just send ascii down the serial line, nor would I want to.

I can assure you that the value of floatConv.i was being set by changing floatConv.b, I can't fathom why you would insist it is not. Although looking again I believe my problem is with endianness.

I believe that the arduino print function is unable to express floats that are very small otherwise I might have noticed immediately.

masternibot:
If you had read the initial post you would realize I cant just send ascii down the serial line, nor would I want to.

I believe I did read the initial post, and I don't see anything about not wanting to do things the simple way, like sending an ASCII string down the line.

I am interfacing with a device that uses the modbus protocol. I cant just send an ascii string. Besides, sending the data using ascii is unnecesscarily slow. Not only does it use more time to decode but it also takes more time to transmit.

I can assure you that the value of floatConv.i was being set by changing floatConv.b, I can't fathom why you would insist it is not.

Simple, really.

  Serial.println(floatConv.f);  
  
  floatConv.b[0] = data[0];
  floatConv.b[1] = data[1];
  floatConv.b[2] = data[2];
  floatConv.b[3] = data[3];

Print the value of an uninitialized variable, and THEN assign a value to it. THAT is what is useless.

  floatConv.b[0] = data[0];
  floatConv.b[1] = data[1];
  floatConv.b[2] = data[2];
  floatConv.b[3] = data[3];

  Serial.println(floatConv.f);

would make sense to everyone else.

Your uint16 should be a uint32, and your float value is wrong endian.

union FloatConv {
  float f;
  uint32_t i;
  byte b[4];
} floatConv;

uint8_t data[] = {0x3F,0x80,0x00,0x00}; //float for 1

void setup() {
  Serial.begin(9600);

  float * dataFloat;
  dataFloat = (float *) data;
  Serial.print("float from pointer casting: ");
  Serial.println(floatConv.f); 
 
  floatConv.b[0] = data[3];
  floatConv.b[1] = data[2];
  floatConv.b[2] = data[1];
  floatConv.b[3] = data[0];
 
  Serial.print("\nFrom union conversion:\ninteger: ");
  Serial.println(floatConv.i);
  Serial.print("float: "); 
  Serial.println(floatConv.f);

  float f = 1.0;
  Serial.print("\nPrinting a 'normal' float: ");
  Serial.print(f);
 
 
 
}

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

}

PaulS I already acknowledged that as a mistake. That does not change the behavior of printing floatConv.i later in the code.

Thank you aarg for the useful response, bit of a goof with that uint16/32.

I am new to these forums and perhaps my posts have not been the most polite, but I did not expect such condescending and confrontational replies from a moderator.

It's usually considered bad form on this Forum to have 5 posts of your own and start poking someone with a sharp stick who has over 25,000 posts. If Nick says something about the Arduino, you can take it to the bank. If you feel you were treated unkindly, I think you will find that most of the other readers here are going to fall on Nick's side of the issue. I've been using C since 1978 and am still learning things from the posters here. It may be worthwhile to eat a little humble pie, leave your ego at the door and, instead, concentrate on the nuggets of knowledge you'll find dispersed here.

Perhaps that is true. I am sure Nick has helped a lot of people, though in this case his responses read negatively. Perhaps that was just my interpretation of them.

aarg has been the only one to post a helpful reply, thanks again.

Perhaps that was just my interpretation of them.

I think most people here would agree. Nick's a fuzzy puppy dog compared to some of us on this Forum. His website is a gold mine, if you're interested. Also, Nick's comment is helpful if you go back and reread it.

aarg has been the only one to post a helpful reply, thanks again.

From my point of view, all of the replies were helpful, because they were pointing out your mistakes.

masternibot:
I am new to these forums and perhaps my posts have not been the most polite, but I did not expect such condescending and confrontational replies from a moderator.

What was confrontational about pointing out you were printing something that was not initialized?

It also wasn't obvious why you were trying to reassemble a float number from the other device. Floating point numbers (can) have different internal representations, you are not normally expected to have to jump through the hoops you are going through.

I have been working a quick program to get data from an ultrasonic flowmeter over rs485 using the modbus protocol

A link this device would have been helpful.

aarg has been the only one to post a helpful reply, thanks again.

I posted a helpful response. You ignored it. PaulS clarified my response. You ignored that. It would have been helpful to post more information in your initial post, like the device number and a link to its datasheet.

I am sure Nick has helped a lot of people ...

You are sure, are you?

Clearly I have upset you. That was not my intention. I apologise. Perhaps I missed misunderstood your use of bolding in your first reply, a lot is lost in text communication. I was also in a poor mood yesterday.

The reason I thought that the error there was trivial is because this is the code I used to demonstrate the issue rather than the code I was using in my program. Additional context of my issue did not seem relevant.

The only reason I posted here is because I was confident that the code should worked and as it turns out it does. The only slight issue is that because printing floats using the arduino print function displays only 0.00 for very small floats, I was unable to tell what the float actually contained and that I had confused my endians.

Again I apologize, Thank you for your prompt reply. You seem like a great member of the arduino community, thanks for your time.

If the real issue is the number of decimal places, you can increase that when you print.

eg.

Serial.println (myFloat, 4);  // 4 decimal places