Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
107 views
in Technique[技术] by (71.8m points)

java - How can I send with two bytes a float from type %8.5f over bluetooth low energy to my android app

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.

question from:https://stackoverflow.com/questions/65952711/how-can-i-send-with-two-bytes-a-float-from-type-8-5f-over-bluetooth-low-energy

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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'.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...