Embedded 数据转换:将数组中的4字节数据分配到1字节数组中
首先,让我解释一下环境。我正在使用C作为嵌入式32位微控制器。通过各种工具进行单元测试,但结果是相同的。printf仅用于使用MinGW的测试 我试图将数据从float32数组(4字节数组)(IEEE754)复制到字节数组中 我在这里仅使用十六进制数据,十六进制值的位置必须准确,即:Embedded 数据转换:将数组中的4字节数据分配到1字节数组中,embedded,microcontroller,generic-programming,Embedded,Microcontroller,Generic Programming,首先,让我解释一下环境。我正在使用C作为嵌入式32位微控制器。通过各种工具进行单元测试,但结果是相同的。printf仅用于使用MinGW的测试 我试图将数据从float32数组(4字节数组)(IEEE754)复制到字节数组中 我在这里仅使用十六进制数据,十六进制值的位置必须准确,即: If CalibData[0] = 01 02 03 04 那么数据应该如下所示: Data[0] = 01 Data[1] = 02 Data[2] = 03 Data[3] = 04
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));
}
根据IEEE754,十六进制格式应为0x3F 0x80 0x00 0x00,但在单元测试或printf中,它将按如下方式执行:
Data[0] = 01
Data[1] = 02
Data[2] = 03
Data[3] = 04
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,那个么代码就是在数据中显示垃圾值
请告诉我一个更好的方法或改进上述方法之一
将错误视为演员
(uint32)
,因为它正在将浮动
转换为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标准。但它可能在您的实际系统上工作
编辑1
仍然不符合要求,但不使用联合
,您可以使用铸造指针来模拟:
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()
:
最后一个选项有两个主要优点:
校准数据的数据类型大小的更改是安全的
#if !defined(MY_COMPILER_ID)
#error Compiler not supported
#endif
要以相反的顺序存储浮点值,可以使用“编辑1”的第一个备选方案和反向索引:
const uint8* b = (const uint8*)(calib_Data + i); // equally, but simpler to read than &calib_Data[i]
Data[dataElementCounter] = b[3];
dataElementCounter++;
Data[dataElementCounter] = b[2];
dataElementCounter++;
Data[dataElementCounter] = b[1];
dataElementCounter++;
Data[dataElementCounter] = b[0];
dataElementCounter++;
为了使其在将来不会因calib_Data
的数据类型的大小变化而变得安全,您需要一个循环:
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++;
}
感谢您的回答,您的分析是正确的,但不幸的是,由于一些一致性限制,我无法在代码中使用联合谢谢您的详细回答,我发现您的第二种方法非常有用,现在我可以在调试器中看到正确的数据,但它被翻转了。例如,我期望数据[0]=3F数据[1]=80数据[2]=00数据[3]=00,但我得到的结果如下:数据[0]=00数据[1]=00数据[2]=80数据[3]=3F你能建议改变这个顺序吗?不幸的是,第一种方法不适用于我,返回0x00 0x00 0x00 0x01作为我自己的代码,但memcpy方法似乎工作正常,但只有reuslts被翻转。我想不出如何用memcpy翻转浮动顺序。不过,感谢您对安全性的非常好的解释和附加信息。我一定会这样做。如果
memcpy()
似乎有效,只要翻转一下,您的数据的数据类型就不是int
,而是uint8\u t
或其他大小为1的数据类型。-正如您所发现的,memcpy()
无法翻转。你必须自己做。你是对的,我自己在memcpy之后翻转字节,它就像魅力一样工作。非常感谢你的指导。现在问题解决了。“嵌入式32位微控制器?”你知道不止一个,对吗?
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++;
}