Преобразование данных: назначение 4-байтовых данных из массива в 1-байтовый массив - PullRequest
0 голосов
/ 30 марта 2020

Прежде всего, позвольте мне немного рассказать об окружающей среде. Я использую C для встроенного 32-разрядного микроконтроллера. выполнение юнит-тестов с помощью различных инструментов, но результаты одинаковы. printf используется только для теста с MinGW.

Я пытаюсь скопировать данные из массива float32 (4Byte array) (IEEE754) в байтовый массив.

Я работаю только с шестнадцатеричными данными только здесь, и важно, чтобы местоположение шестнадцатеричного значения было точным, то есть:

If CalibData[0] = 01 02 03 04

, тогда данные должны выглядеть следующим образом:

   Data[0] = 01
   Data[1] = 02
   Data[2] = 03
   Data[3] = 04

Возможности, о которых я мог подумать, аналогичны приведенному ниже блоку кода:

/*CalibData is a Global variable and change by other components, I am only reading it here*/
float32 CalibData [1920];

/*Data is an argument for my function and shall return it with values read from CalibData*/
int Data[7680];

/* Approach 1: */

uint16_t dataElementCounter = 0;
for (uint16_t i = 0; i < 1920; i++)
{
Data[dataElementCounter] = (uint8) ((uint32) calib_Data[i] >> 24);
dataElementCounter++;
Data[dataElementCounter] = (uint8) ((uint32) calib_Data[i] >> 16);
dataElementCounter++;
Data[dataElementCounter] = (uint8) ((uint32) calib_Data[i] >> 8);
dataElementCounter++;
Data[dataElementCounter] = (uint8) ((uint32)calib_Data[i]);
dataElementCounter++;
}

/* Approach 2: */
for (uint16_t i = 0; i < 1920; i++)
{
memcpy((uint8*) Data[0], &calib_Data[i],sizeof(float));
}

Теперь проблема в том, что если я использую подход 1, тогда сложно протестировать без оборудования если данные копировались правильно, потому что тестирование с помощью модульного теста или printf всегда предоставляет усеченные данные. Например,

if CalibData[0] = 1.0;

Согласно IEEE754 это должно быть 0x3F 0x80 0x00 0x00 в шестнадцатеричном формате, но в модульном тесте или printf это будет выглядеть так:

CalibData >> 24 - это дробное число 1,0 / 16777216. При преобразовании в uint32 он усекается до 0. CalibData >> 16 - это дробная часть 1,0 / 65536. Аналогично. CalibData >> 8 - это фракция 1.0 / 256. Аналогично. CalibData составляет 1,0. Это будет 1 как uint32.

, поэтому данные будут отображаться как:

Data[0] = 0
Data[1] = 0
Data[2] = 0
Data[3] = 1

И если я использую подход 2, тогда код показывает значения мусора в данных.

Пожалуйста, скажите мне лучший способ сделать это или улучшить один из вышеупомянутых подходов.

С уважением

1 Ответ

1 голос
/ 31 марта 2020

Ошибка - приведение (uint32) при преобразовании float в uint32, а это не то, что вам нужно.

Лучше всего ставить этот отрывок:

union {
    float f;
    uint8 b[4];
} u;

u.f = calib_Data[i];
Data[dataElementCounter] = u.b[0];
dataElementCounter++;
Data[dataElementCounter] = u.b[1];
dataElementCounter++;
Data[dataElementCounter] = u.b[2];
dataElementCounter++;
Data[dataElementCounter] = u.b[3];
dataElementCounter++;

Осторожно, это не соответствует стандарту C. Но это может работать в вашей реальной системе.

EDIT 1

Все еще не соответствует, но без использования union, вы можете эмулировать это с помощью приведенных указателей:

const uint8* b = (const uint8*)(calib_Data + i); // equally, but simpler to read than &calib_Data[i]
Data[dataElementCounter] = b[0];
dataElementCounter++;
Data[dataElementCounter] = b[1];
dataElementCounter++;
Data[dataElementCounter] = b[2];
dataElementCounter++;
Data[dataElementCounter] = b[3];
dataElementCounter++;

Это похоже на ответ Codetest, который даже лучше предлагает использовать memcpy():

memcpy(Data + dataElementCounter, calib_Data + i, sizeof calib_Data[i]);
dataElementCounter += sizeof calib_Data[i];

Последний вариант имеет два основных преимущества:

  1. Он понятен заранее с минимальным количеством строк.
  2. Он безопасен от изменений размера данных calib_Data.

РЕДАКТИРОВАТЬ 2

Требование: вы должны поменять местами байты.

Если ваша целевая система исправлена ​​и если вы полностью уверены в том, что делаете, первый что нужно сделать, это документировать это в комментарии. Кроме того, вы можете проверить компилятор:

 #if !defined(MY_COMPILER_ID)
 #error Compiler not supported
 #endif

Чтобы сохранить число с плавающей запятой в обратном порядке, вы можете использовать первый вариант EDIT 1 с инвертированными индексами: чтобы обеспечить безопасность в будущем от изменений размера данных calib_Data, вам понадобится al oop:

const uint8* b = (const uint8*)(calib_Data + i); // equally, but simpler to read than &calib_Data[i]
int b_i;
for (b_i = sizeof calib_Data[i] - 1; b_i >= 0; --b_i) {
    Data[dataElementCounter] = b[b_i];
    dataElementCounter++;
}
...