Member 14040031 Ответов: 4

Как преобразовать 32-битное целое число в float


Я пытаюсь считывать данные с датчика, используя связь I2C. Выходные данные-это четыре из одного байта, которые равны 0x43, 0xDB, 0x8C, 0X2E соответственно.
Поэтому я успешно прочитал эти значения отдельно. Когда я пытаюсь объединить и преобразовать его в действительное число. Выходное значение не такое, как я ожидал:

Значение, считываемое с датчика, равно: 0x43DB8C2E
Согласно техническому паспорту, это большой Эндиан и соответствует 439.09.
Но то, что я получил на выходе, - это 29650.

Что я уже пробовал:

Я попробовал пример кода из таблицы данных о том, как считывать это значение. Но результат все равно не тот, что я хочу.

// CO2 concentration
float co2Concentration;
unsigned int tempU32;
// read data is in a buffer. In case of I2C CRCs have been removed // beforehand. Content of the buffer is the following
unsigned char buffer[4];
buffer[0] = 0x43; //  MMSB CO2
buffer[1] = 0xDB; //  MLSB CO2
buffer[2] = 0x8C; //  LMSB CO2
buffer[3] = 0x2E; //  LLSB CO2

// cast 4 bytes to one unsigned 32 bit integer
tempU32 = (unsigned int)((((unsigned int)buffer[0]) << 24) | (((unsigned int)buffer[1]) << 16) | (((unsigned int)buffer[2]) << 8) |
                          ((unsigned int)buffer[3]));

// cast unsigned 32 bit integer to 32 bit float
co2Concentration = *(float*)&tempU32; // co2Concentration = 439.09f


я печатаю значение концентрации CO2 и оно составляет 29650

4 Ответов

Рейтинг:
2

CPallini

На маленькой машине с обратным порядком байтов сначала надо изменить порядок следования байтов и привести указатель:

#include <stdio.h>

int main()
{
  unsigned char buffer[4];

  buffer[0] = 0x43; //  MMSB CO2
  buffer[1] = 0xDB; //  MLSB CO2
  buffer[2] = 0x8C; //  LMSB CO2
  buffer[3] = 0x2E; //  LLSB CO2

  unsigned char le [] = {buffer[3], buffer[2], buffer[1], buffer[0]};
  float f = *(float *)(le);
  printf("%f\n", f);
  return 0;
}


Рейтинг:
1

KarstenK

Решение гораздо проще:

float co2Concentration = 0;
char *buffer = (char*) &co2Concentration;
buffer[0] = 0x43; //  MMSB CO2
buffer[1] = 0xDB; //  MLSB CO2
buffer[2] = 0x8C; //  LMSB CO2
buffer[3] = 0x2E; //  LLSB CO2


Рейтинг:
1

OriginalGriff

Зачем ты возишься с указателями?
Просто брось его:

double co2Concentration;
unsigned int tempU32;
// read data is in a buffer. In case of I2C CRCs have been removed // beforehand. Content of the buffer is the following
unsigned char buffer[4];
buffer[0] = 0x43; //  MMSB CO2
buffer[1] = 0xDB; //  MLSB CO2
buffer[2] = 0x8C; //  LMSB CO2
buffer[3] = 0x2E; //  LLSB CO2

// cast 4 bytes to one unsigned 32 bit integer
tempU32 = (unsigned int)((((unsigned int)buffer[0]) << 24) | (((unsigned int)buffer[1]) << 16) | (((unsigned int)buffer[2]) << 8) |
                          ((unsigned int)buffer[3]));

// cast unsigned 32 bit integer to 32 bit float
co2Concentration = (double)tempU32; // co2Concentration = 439.09f
	printf("%d\n", tempU32);	
	printf("%f\n", co2Concentration);	
И выход есть:
1138461742
1138461742


(Я переключился на Double, потому что значение не было точным в float на моем компиляторе по очевидным причинам).


Member 14040031

Спасибо Вам за ваше решение. Но выход, который мне нужен, - это 439.09, и у меня нет идеала, как я могу его получить.

OriginalGriff

Вы имеете в виду 439.095154?
Потому что это просто! - у тебя неправильный порядок байтов, вот и все!
unsigned char buffer[4];
буфер[3] = 0x43; // MMSB CO2
буфер[2] = 0xDB; // MLSB CO2
буфер[1] = 0x8C; // LMSB CO2
буфер[0] = 0x2E; // LLSB CO2
float f = (float)(*буфер);
printf("%f\n", f);
Числа ПК-это маленький эндиан, а не большой эндиан!

Рейтинг:
0

David O'Neil

Попробуйте использовать союз. Вот с чего вы можете начать:

union U {
   int i;
   float f;
   };
U temp;
temp.f = 439.09;
int i = temp.i;

Пройди через это и увидишь что i равняется. Затем поиграйте со своими ценностями и посмотрите, как все складывается для вас. Если датчик не подает значение поплавка в соответствии со стандартами, вам придется придумать собственный метод.

Надеюсь, это поможет!