Convert uint32 floating point view to uint8

Without going into too many details, I have two embedded systems, none of which can use the floating point library. Between them is a mobile application where some calculations are performed. One calculation should maintain accuracy. This value is sent to the client via Bluetooth, as an array of bytes. When it is received, I save it as uint32. Then this value is again used in conjunction with a mobile application where accuracy is required. There is no problem because I can use the Java ByteBuffer class. The problem is that I also need to share this value with the Z80 microprocessor as with uint8, because it is transmitted via UART and used as an ADC counter (0-255), so it loses accuracy (but it is not needed at this end).

So, I am doing this in my mobile application using Java:

int bits = Float.floatToIntBits(fAdcCount);
byte[] b = new byte[4];
b[0] = (byte)(bits & 0xff);
b[1] = (byte)((bits >> 8) & 0xff);
b[2] = (byte)((bits >> 16) & 0xff);
b[3] = (byte)((bits >> 24) & 0xff);

bthen sent with the BLE characteristic to the BLE microcontroller. The BLE microcontroller then reads this buffer as a 32-bit little-endian word and stores it in uint32. Looking at this uint32in the debugger, the correct values ​​are displayed, and, as I said above, I can return this one uint32back to the byte array and send it to the mobile application and read it using the Java ByteBuffer class. This works fine, I get the correct floating point value.

The problem is that I need the integer part of this floating point representation to send to the Z80 microprocessor via UART as uint8, because it is used as an ADC counter from 0 to 255.

, , uint32 ( ), uint8 ? , 0 255, 255,0 .

, :

uint32 fValue = 0x43246ADD; // = 164.417...

float?:

uint8 result = 164;

+4
3

OP. , . : , 0, ?. 0.

#include <stdint.h>
#define MANTISSA_BIT_WIDTH 23
#define BIASED_EXPO_MAX 255
#define EXPO_BIAS 127
#define SIGN_MASK 0x80000000

unsigned DN_float_to_uint8(uint32_t x) {
  if (x & SIGN_MASK) return 0; // negative
  int expo = (int) (x >> MANTISSA_BIT_WIDTH);
  if (expo == 0) return 0;  // sub-normal
  if (expo == BIASED_EXPO_MAX) return 255;  // Infinity, NaN
  expo -= EXPO_BIAS;
  if (expo > 7) return 255; // too big
  if (expo < 0) return 0; // wee number
  uint32_t mask = ((uint32_t)1 << MANTISSA_BIT_WIDTH) - 1;
  uint32_t mantissa = mask & x;
  mantissa |= mask + 1;
  mantissa >>= (MANTISSA_BIT_WIDTH - expo);
  return mantissa;
}

#include <stdio.h>
int main() {
  printf("%u\n", DN_float_to_uint8(0x43246a00)); // 164
  printf("%u\n", DN_float_to_uint8(0x437e0000)); // 254
  printf("%u\n", DN_float_to_uint8(0x437f0000)); // 255
  printf("%u\n", DN_float_to_uint8(0x43800000)); // 256
  printf("%u\n", DN_float_to_uint8(0x3f7fffff)); // 0.99999994
  printf("%u\n", DN_float_to_uint8(0x3f800000)); // 1
  printf("%u\n", DN_float_to_uint8(0x40000000)); // 2
  return 0;
}

164
254
255
255
0
1
2

IEEE 754


( ), , , .

  // mantissa >>= (MANTISSA_BIT_WIDTH - expo);
  // return mantissa;

  // shift as needed expect for 1 bit
  mantissa >>= (MANTISSA_BIT_WIDTH - expo - 1);
  // now shift last bit
  mantissa = (mantissa + 1) >> 1;
  // Handle special case
  if (mantissa >= 256) mantissa = 255;
  return mantissa;
+4

, IEEE 754 single precision float, .

, , . . -255 255 INT_MIN, ; , .. .

int integer_part_of_single_float(uint32_t f)
{
    uint32_t mantissa = (f & 0x7fffff) | 0x800000;
    uint8_t exponent = f >> 23;
    if (exponent < 127) {
        return 0;
    } else if (exponent >= 135) {
        return INT_MIN;
    } else {
        unsigned absolute_value = mantissa >> (22 - (exponent - 128));
        return mantissa & 0x80000000 ? -absolute_value : absolute_value;
    }
}
+2

, float, uint32_t, float , 32 sizeof(float)==4 ( ), - :

float *f;

f = (float *)&fValue;

if( *f <= 255 && *f >= 0 )
{
    result = (uint8_t) (*f);
}
else
{
    // overflow / undeflow
}

You declare a pointer floatand point it to a location uint32_t.

Then take the value indicated by po float pointer and try to apply to uint8_t


I tried the code and can say that the above assumptions are true in macOS .

For instance:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    uint32_t fValue = 0x43246ADD;
    uint8_t result=0;

    float *f;

    f = (float *)&fValue;

    if( *f <= 255 && *f >= 0 )
    {
        result = (uint8_t) (*f);
    }
    else
    {
        // overflow / undeflow
    }

    printf("%d\n", result);
}

Outputs:

164
0
source

Source: https://habr.com/ru/post/1659863/


All Articles