How do i:Read a float on an ESP32

Hi all,

After asking google for some answers, i decided to ask for help as i am not getting any further with floats on an ESP32.
i'll try to explain what i wish to realise, and put some off the code in here what i think matters for the understanding.

i recieve an UDP stream, and put it in a packetBuffer.

Udp.read(packetBuffer, 1367); // Read the protocol UDP packet, and put in it packetBuffer 1367

So ie. for storing the FuelCapacity, i read the packetbuffer 111 who hold the FuelCapacity value (Byte), like this:

FuelCapacity = (packetBuffer[111]); // Fuel Capacity

So far it all works.

But in the same the UDP stream there are 4 byte's, who hold the data for my ie. FuelLevel
These byte's are at position 116, 117, 118 and 119.

And what ever i try i don't get a proper value. (RANGE = 0.0f->1.0f)

  • So my question is: how do i read the UDP stream 116 to 119 as an float

What i have tried so far (and doesn't work) is as follow:

FuelLevel = (packetBuffer[119] << 24, packetBuffer[118] << 16, packetBuffer[117] << 8, packetBuffer[116],) << 0)

or

highWord = word(packetBuffer[119] , packetBuffer[118]);
lowWord = word(packetBuffer[117] , packetBuffer[116]);
FuelLevel = highWord << 16 | lowWord;

also another attempt doesn't work:

FuelLevel = (packetBuffer[119]) << 24 | (packetBuffer[118] & 0xff) << 16 | (packetBuffer[117] & 0xff) << 8 | (packetBuffer[116] & 0xff);

this time i put them in FuelLevel 116 and 117, and print those value's:

FuelLevel116 = float((packetBuffer[119]) << 24 | (packetBuffer[118] & 0xff) << 16 | (packetBuffer[117] & 0xff) << 8 | (packetBuffer[116]& 0xff));
FuelLevel117 = float((packetBuffer[119]) << 24 | (packetBuffer[118]) << 16 | (packetBuffer[117]) << 8 | (packetBuffer[116]) << 0 );

After this i have to multiply FuelLevel * FuelCapacity, to get the actual Fuellevel in Litres.

i can share the whole code (and i will when it works), but i hope this is enough information to get some help started.

Thanks in advance,

FuelLevel = (packetBuffer[119]  << 24, packetBuffer[118] << 16, packetBuffer[117] << 8, packetBuffer[116],) << 0)Those commas are doing you no favours.

Try a more appropriate operator.

FuelLevel116 = float((packetBuffer[119]) << 24 | (packetBuffer[118] & 0xff) << 16 | (packetBuffer[117] & 0xff) << 8 | (packetBuffer[116]& 0xff));
FuelLevel117 = float((packetBuffer[119]) << 24 | (packetBuffer[118]) << 16 | (packetBuffer[117]) << 8 | (packetBuffer[116]) << 0 );

Seems to get me in both occacions a number wich slowly lowers, the numbers are the same, so the code itself makes no difference.

Fuel level 116 : 1054481280.00 Fuel level 117 : 1054481280.00
Fuel level 116 : 1054480448.00 Fuel level 117 : 1054480448.00
Fuel level 116 : 1054479680.00 Fuel level 117 : 1054479680.00
Fuel level 116 : 1054478784.00 Fuel level 117 : 1054478784.00
Fuel level 116 : 1054477952.00 Fuel level 117 : 1054477952.00
Fuel level 116 : 1054477056.00 Fuel level 117 : 1054477056.00
Fuel level 116 : 1054476224.00 Fuel level 117 : 1054476224.00
Fuel level 116 : 1054475392.00 Fuel level 117 : 1054475392.00
Fuel level 116 : 1054474560.00 Fuel level 117 : 1054474560.00
Fuel level 116 : 1054473728.00 Fuel level 117 : 1054473728.00
Fuel level 116 : 1054472960.00 Fuel level 117 : 1054472960.00

he did, but he should have casted it first

FuelLevel = (packetBuffer[119]) << 24 | (packetBuffer[118] & 0xff) << 16 | (packetBuffer[117] & 0xff) << 8 | (packetBuffer[116] & 0xff);

but i am also a little stuck with converting the 4 bytes into a float. see you can fit them into a 4 byte variable as such

uint32_t FL=0;
for (uint8_t i=119; i>115; i--; {
  FL=FL<<8;
  FL=FL+packetBuffer[i];  // or FL=FL | packetBuffer[i];
}

Suppose a memcopy into a float would do the trick thereafter

(packetBuffer[119]) << 24 the variable that is shifted needs to be 32-bit, before you shift.

Thanks for the help.

uint32_t FL=0;
for (uint8_t i=119; i>115; i--; {
  FL=FL<<8;
  FL=FL+packetBuffer[i];  // or FL=FL | packetBuffer[i];
}

for (uint8_t i=119; i>115; i--; { should be this? for (uint8_t i=119; i>115; i--)

uint32_t FL=0;
for (uint8_t i=119; i>115; i--) {
  FL=FL<<8;
  FL=FL+packetBuffer[i];  // or FL=FL | packetBuffer[i];
}

i added the "FuelLevel = FL;" code, so i got this:

uint32_t FL=0;
for (uint8_t i=119; i>115; i--) {
  FL=FL<<8;
  FL=FL+packetBuffer[i];  // or FL=FL | packetBuffer[i];
}
  FuelLevel = FL;

and FuelLevel was earlier declared as: float FuelLevel;
So now i get a value in the FuelLevel

When i use serial print, and i print the byte's (119 to 116) and the FL and FuelLevel(float) i got this:

.

Fuel level (FL) : 111100001101101000111001101111
Fuel level (float) : 1010208384.00
119 : 111100
118 : 110110
117 : 10001110
116 : 1101111

Now i need to work on how to make that usefull data as i expect a number in the RANGE = 0.0f->1.0f

sorry about the typo !

i suggest you do a memcopy instead of an assignment, since the compiler tends to do a form of casting for you in this case. 1010208384 decimal = 3C368E80 HEX which does look a tad much like the first 23 bits of the value you received.

still possibility exist that the bytes get send in opposite order (not so likely) , or that a different kind of float is used (there are 2 ways of representing the exponent according to wiki)

Sign bit determines the sign of the number, which is the sign of the significand as well. Exponent is either an 8-bit signed integer from −128 to 127 (2's complement) or an 8-bit unsigned integer from 0 to 255, which is the accepted biased form in IEEE 754 binary32 definition. If the unsigned integer format is used, the exponent value used in the arithmetic is the exponent shifted by a bias – for the IEEE 754 binary32 case, an exponent value of 127 represents the actual zero (i.e. for 2e − 127 to be one, e must be 127). Exponents range from −126 to +127 because exponents of −127 (all 0s) and +128 (all 1s) are reserved for special numbers.

and i think with the bytes in this order it might be the latter (the exponent byte being 01111001 = 121 which would either be e=-6 i am not sure which way Arduino compiler uses. But still first try and do a memcopy from FL to FuelLevel !

you may actually also get away with

float FL=0;
for (uint8_t i=119; i>115; i--) {
  FL=FL<<8;
  FL=FL | packetBuffer[i];
}

since then you are just doing bitwise operations and the value never gets casted

Deva_Rishi:
you may actually also get away with

float FL=0;

for (uint8_t i=119; i>115; i--) {
  FL=FL<<8;
  FL=FL | packetBuffer[i];
}


since then you are just doing bitwise operations and the value never gets casted

i'll give it a go, but will be friday at earliest when i can test it, 2morrow i can change the code.

float FL=0;
for (uint8_t i=119; i>115; i--) {
  FL=FL<<8;
  FL=FL | packetBuffer[i];
}

get me the message:

2L_1_pc_beta.h:16: error: invalid operands of types 'float' and 'int' to binary 'operator<<'
FL=FL<<8;

The memcpy i tried this (not aquinted with memcpy yet)

memcpy(FuelLevel, FL, sizeof FuelLevel);

But then the IDE hammers this:

2L_1_pc_beta.h:28: error: cannot convert 'float' to 'void*' for argument '1' to 'void* memcpy(void*, const void*, size_t)'
memcpy(FuelLevel, FL, sizeof FuelLevel);

So i am probably doiing something wrong again.

Oh, well, in that case you should do as previously (sorry i didn't do a testing compile last time) and then do memcpy(&FuelLevel, &FL, 4);
in complete that would be

uint32_t FL=0;
for (uint8_t i=119; i>115; i--) {
  FL=FL<<8;
  FL=FL+packetBuffer[i]; 
}
  FuelLevel = FL;
  memcpy(&FuelLevel, &FL, 4);

doing that i got a result with the previous values of '0.0111423575'

Deva_Rishi:
Oh, well, in that case you should do as previously (sorry i didn't do a testing compile last time) and then do memcpy(&FuelLevel, &FL, 4);
in complete that would be

uint32_t FL=0;

for (uint8_t i=119; i>115; i--) {
  FL=FL<<8;
  FL=FL+packetBuffer[i];
}
  FuelLevel = FL;
  memcpy(&FuelLevel, &FL, 4);


doing that i got a result with the previous values of '0.0111423575'

Dude awesome it works. i have been trying this for weeks or even months. Every time i sorted something else to keep getting somewhere and keep the spirit up. But not getting the floats working was killing me, and now sorted in a few days.

You're my Hero :smiley: many many thanks. Now i need to figure out what the code is doiing you wrote, to know how to implement it in other parts off the sketch.

With comments it will become clearit is not all that special and i do apologize for it taking so long.

uint32_t FL=0;  //create a 32-bit integer
for (uint8_t i=119; i>115; i--) {  // set the loop for 4 bytes to be read.
  FL=FL<<8;  // bitshift 8 bits to the left (the first time around there is nothing to shift)
  FL=FL+packetBuffer[i]; // add the next 8 bits (msbyte first) so in the end the first byte gets shifted 24 bits
}
  //  FuelLevel = FL;  // this line actually shouldn't be there sorry.. we are not assigning FL to FuelLevel.
  memcpy(&FuelLevel, &FL, 4); // we copy the memory starting at where pointer of FL points to, to the memory  
  //  starting of where the pointer of FuelLevel points to, for 4 bytes

the last line effectively copies the bits of FL into FuelLevel, read about it hereMan hey really sorry there even were bugs in the final solution, this is what happens when i do multiple things at one time.

AWOL:
Try a more appropriate operator.

Like the union operator? :smiling_imp:

What would the benefifts be of that, and can you show / help with an example?

Less typing.

At the cost of violating strict aliasing. (packetBuffer being an array of byte means this is not a problem.)

So the code works, but this part slows down the whole sketch.

i think it has to do with the float calculations, is there a way to improve the code, so the sketch becomes quicker?
But the delay from 500mSec won't help either.

uint32_t FL=0;
for (uint8_t i=119; i>115; i--) {
  FL=FL<<8;
  FL=FL+packetBuffer[i]; 
}
  memcpy(&FuelLevel, &FL, 4);
  FuelLevel = FuelLevel * FuelCapacity;

   if (FuelLevel <= (( FuelCapacity * fuelCrit) / 100)) {
  //Serial.print("Fuel level is below Critical "); Serial.print(fuelCrit); Serial.println(" %"); // Debug option
    delay(500);
    digitalWrite(ledpinFuel, !digitalRead(ledpinFuel));                                          // Flash FuelLED
    }

  else if (FuelLevel <= (( FuelCapacity * fuelLow) / 100)) {
  //Serial.print("Fuel level is BELOW "); Serial.print(fuelLow); Serial.println(" %");           // Debug option
    digitalWrite(ledpinFuel, HIGH);                                                              // turn FuelLED on
    }

  else  {
  //Serial.print("Fuel level is ABOVE "); Serial.print(fuelCrit); Serial.print (" and "); Serial.print(fuelLow); Serial.println(" %");          // Debug option
    digitalWrite(ledpinFuel, LOW);                                                               // turn FuelLED off
  }

Removing...

...
    delay(500);
...

...is probably a good place to start.

Agree, but is there another way to make the FuelLow indicator (LED) flash?

State machine. This looks like a good place to start...

http://forum.arduino.cc/index.php?topic=503368.0