Преобразование фиксированной точки 8.24, диапазона 0,000000000000000 в диапазон 1,000000000000000 в значение uint32_t в C - PullRequest
0 голосов
/ 17 мая 2019

Я хотел бы преобразовать 8,24 числа с фиксированной точкой из диапазона \

0.000000000000000 -> 1.000000000000000 to uint32_t

Умножать ли я десятичные разряды или добавлять или сдвигать в битах?

Я получаю числа с фиксированной точкой формата 8.24 в виде 4 байтов

    uint8_t meterDataRX[4];

    // read 4 bytes from DSP channel
       HAL_I2C_Master_Receive(&I2cHandle,bbboxDsp_address,meterDataRX,4,1); 

    uint32_t a;

    a = (meterDataRX[0] << 24) | (meterDataRX[1] << 16) | (meterDataRX[2] << 8) | meterDataRX[3];

Но не уверен, что это правильно, чтобы начать с!

Цель состоит в том, чтобы установить значения междуuint8_t из 0x00 до 0xFF но я должен сделать uint32_t значения из 4 байтов 1-го?актерский состав

    uint8_t b;
    b = (uint8_t)a;

Ответы [ 3 ]

1 голос
/ 17 мая 2019

Вам нужно прочитать 4-байтовый номер 8.24 с фиксированным байтом как 32-битное число.Для действительного числа в диапазоне от 0 до 1 включительно число с фиксированной точкой «8,24» будет представлено как 32-разрядное число в диапазоне от 0 до 0x01000000 (целая часть равна 1, дробная часть равна 0).Вы хотите масштабировать это число до диапазона от 0 до 0xFF.

  1. Необязательный шаг: ограничить входной номер вне диапазона максимальным значением 0x01000000:

    if (a > 0x01000000) a = 0x01000000;

  2. Умножьте на 0xFF, чтобы получить число в диапазоне от 0x00000000 до 0xFF000000:

    a *= 0xFF;

  3. Необязательный шаг: для округления, а не усечения добавьте представление с фиксированной точкой '8,24' для реального значения 0,5, которое равно 0x00800000:

    a += 0x00800000;

  4. Shift rightна 24 бита, чтобы разделить дробную часть:

    a >>= 24;

У вас останется число в диапазоне от 0 до 0xFF.

Обратите внимание, что если вы пропустите шаг 1 (ограничение чисел вне диапазона), ввод значений, превышающих 0x01008080 (представляющий реальное значение 1.00196075439453125), приведет к арифметическому переполнению.Если вы пропустите оба шага 1 (зажим) и 3 (округление), входы, превышающие 0x01010101 (представляющий реальное значение 1.003921568393707275390625), приведут к арифметическому переполнению.

0 голосов
/ 17 мая 2019

Для фиксированной точки 8.24 каждый uint32_t (или эквивалентный) будет содержать число в диапазоне от 00000000.000000000000000000000000b до 11111111.111111111111111111111111b.

Если число с плавающей запятой находится в диапазоне от 0,000000000000000 до 1,000000000000000, вам необходимо умножить его на (1 << 24) перед преобразованием его в целое число без знака; так что вы в конечном итоге с 8,24 фиксированной точкой.

Для uint8_t, где 0x00 представляют 0,0, а 0xFF представляет 0,996; вам придется умножить его на (1 << (24-8)) (или сдвинуть влево на 16 мест), чтобы преобразовать его в 8,24 фиксированной точки.

Для uint8_t, где 0x00 представляют 0,0, а 0xFF представляет 1,0; вам придется умножить его на (1 << 24) (или сдвинуть влево на 24 позиции), а затем разделить на 0xFF, чтобы преобразовать его в 8,24 фиксированной точки.

Чтобы преобразовать 8,24 фиксированную точку обратно в любой из вышеприведенных случаев, вы должны сделать обратное (например, умножить на 0xFF, а затем сдвинуть вправо на 24 места, чтобы вернуться к uint8_t, где 0xFF представляет 1,0).

0 голосов
/ 17 мая 2019

, если значение находится в диапазоне от 0 до 1, его необходимо масштабировать.

но если вы хотите просто сохранить ее в переменной uint32, вам нужно изменить порядок, поскольку теперь (в вашем коде) ваши данные имеют большой порядок байтов, но в stm32 uC используется младший порядок.

    a = ((uint32_t )meterDataRX[0] ) | ((uint32_t )meterDataRX[1] << 8) | ((uint32_t )meterDataRX[2] << 16) | ((uint32_t )meterDataRX[3] <<24);

Вы также можете использовать для этого пиннинг

...