1

I try to send sensor data continuously from a stm32wb55 to my own android app. I receive two bytes from a acceleration sensor and convert those correctly on my stm32wb55 to a float with format (XX.XXXXX, float can be negative).

Now I want to send exactly this float to my own android app.

Before, I have send two bytes from type "int or uint" to my android app and tried to convert those the same way I have done already on the stm32wb55. But the values on my screen are up to 50% of cases false. So now I try to send the float value directly, so that no more conversion on my phone is needed.


EDIT: After your contributions, I have forget my poor idea to send a float to my android app. I tried again to send the two byte integers and convert those the right way on my app. Now it works how it should. I have found the solution I needed on this post:2 Chars to Short in C. By combining the two bytes to a 16-Bit Integer, I just needed 0x00ff & for my LSB like it be used in the answer of the referenced post.

AnBa
  • 41
  • 7
  • 2
    Did you consider to share the relevant code on both sides? – petrch Jan 29 '21 at 10:30
  • 1
    _the same way I have done already on the stm32wb55_: you need to show the relevant parts of your code. Otherwise the only thing we can say is: you did something wrong in the code you didn't show. – Jabberwocky Jan 29 '21 at 10:36
  • But anyway sending a float which takes 4 bytes using only 2 bytes seems impossible. Also what is a `%8.5f` type? This looks like a format specifier for the printf function family. You really need to [edit] your question and clarify. Before read this: [ask] – Jabberwocky Jan 29 '21 at 10:39
  • 2
    `Now I want to send exactly this float to my own android app.` It is pretty unclear what you wanna send. If you wanna send "12.34567" then that is text. If you wanna send a float variable then most certainly the variable consists of four bytes and hence you would send those four bytes. Please elaborate. (In your post. The comments are for us). – blackapps Jan 29 '21 at 10:45
  • there is not type of float 8.5. You probably mean the string – 0___________ Jan 29 '21 at 10:45
  • 1
    `I receive two bytes from a acceleration sensor` Better forward those two bytes and you are done. – blackapps Jan 29 '21 at 10:46
  • Blackapps's comment sounds good. Send the two bytes you receive from the accelerometer to your android app and do the conversion in java in the android app. This is by far the simplest solution. This has also the advantage that the heavy conversion work is done on the android computer which is fa more poweful and has far more ressources that the stm32wb55 – Jabberwocky Jan 29 '21 at 10:52

1 Answers1

1

to a float with format (XX.XXXXX, float can be negative).

This is impossible.

floats are a 32-bit IEEE754 floating point number. They do not work like you (apparently) think they do.

Specifically, they are binary constructs with a mantissa system. I'll try to explain why it doesn't work like you think they do: What is 1/3, in decimal? You'll find that you can't write it in decimal no matter how many 'bits' (digits) you use. You'll never quite get it. There's always another 3 to add.

floating point works the same way, but it's in binary (base 2) and not decimal (base 10). That means there are numbers that work great in decimal (such as 1/10th which in decimal is 0.1, with perfect accuracy) but which are like 1/3 in binary: No matter how many bits you use, you'll never get it.

Here's another way to think about it: 32-bit, so, there are only 2^32 (about 4 billion) different values. In other words, of all the numbers in existence (and there is an infinite infinity of them: There are infinite numbers, and within any 2 consecutive numbers, another infinity of numbers), only at most 4 billion are blessed: 4 billion of all numbers in existence are representable by a float value. If you try to represent a number that isn't blessed with a float, then java / your CPU will just round it to the nearest blessed number and gives you no real opportunity to deal with the error (after all, how would you represent the error? It is rather unlikely to be blessed, either).

Thus, say, '12.34567'? That's not a blessed number - therefore, your float cannot possibly represent that. It'll instead be a number very close to it, and probably a number that would round to 12.34567 if you round it to 5 digits.

send exactly this float to my own android app.

So, no, you don't want to do that. You want to send 12.34567 to your android app, not the 32 bits that represent it. Unless you intend for the android side of the app to do the rounding, which you probably should. Note that I bet there are numbers that fit the 'XX.YYYYY' pattern that just do not 'work' as a float (they round such that you're off by 1). If that's a problem, don't use floats (use doubles where I doubt that you'll find an XX.YYYYY that doesn't have a blessed number such that it rounds correctly due to having more bits to work with, or use a string, or use 2 ints, or use a single int, and have an agreement that both sides know that the int 1234567 represents 12.34567).

That last one sounds like the most convenient trick for you here, but it's hard to tell as you haven't provided much detail.

Something like (but note that the float may be off by 1 or so!):

sender side:

double v = theFloat; // doubles have less error
int z = (int) (v * 100000);
sendToPhone(z);

receiver side:

int z = getFromDevice();
double v = z;
v /= 100000;
float theFloat = (float) v;

The above will end up automatically rounding off (rounding down for positive numbers and up for negative numbers) any digits after the floating point beyond the 5 you want), and can deal with numbers up to plus or minus 21473.99999. Sounds like that'll easily cover your needs.

NB: You'll have to write the 'multiply by 100000 and then convert to an int32' code for your stm32wb55, the above is how you'd write it if the stm32wb55 was programmed in java, which I would assume it isn't. The 'go to double before multiplying by 100000 is a probably irrelevant optimization, I wouldn't be too worried if you can't do that. Note that CPUs are not guaranteed to use the exact same IEEE754 representation for floats/doubles that java does, which is why you should definitely not attempt to send the value as a float/double across the bluetooth channel, but as something universally agreed upon, such as 'a 2's complement 32-bit integer value'.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • Thank you so much for these detailed explanations! I am sure it will help me even more in the future. – AnBa Jan 30 '21 at 12:12
  • Just for the record, it *is* possible to send a floating-point value in two bytes. See for example the [IEEE-754 "half" precision](https://en.wikipedia.org/wiki/Half-precision_floating-point_format) type, or the ["bfloat16"](https://en.wikipedia.org/wiki/Bfloat16_floating-point_format) type. I'm not saying the OP would want to use either of these, but they do exist. – Steve Summit Jan 30 '21 at 12:12