I'm writing a embedded systems program that receives 24-bit data from an external ADC over SPI and stores the data in an integer array. That part is working. In order for the data to be useful, I need to concatenate each byte in either binary or hexadecimal form and divide by 0x7FFFFFF. This is where I'm running into trouble. For example, I might receive a data array over SPI that looks like this:
data_buffer = { 24 , 17 , 140 };
aka
data_buffer = { 0b00011000 , 0b00010001 , 0b10001100 };
aka
data_buffer = { 0x18 , 0x11 , 0x8C };
What I need to do with this value is concatenate each element to get something like this:
data_value = 0x18118C
And then divide that value by 0x7FFFFF in order for it to be useful in my program. In this example the value I'd like to end up with is 0x18118C/0x7FFFFF = 0.188
How would I go about doing this?
I'm sorry I haven't provided more code, I honestly have no idea where to start.
答案 0 :(得分:5)
将三个字节组合成一个24位(实际上是32位)值是C的按位运算符的直接应用。 这是一个冗长的“长手”形式:
unsigned char data_buffer[] = { 24 , 17 , 140 };
unsigned long int data_value = 0;
data_value |= data_buffer[0];
data_value <<= 8;
data_value |= data_buffer[1];
data_value <<= 8;
data_value |= data_buffer[2];
我可能会以更紧凑的形式写出来:
unsigned long int data_value = 0;
data_value |= data_buffer[0];
data_value = (data_value << 8) | data_buffer[1];
data_value = (data_value << 8) | data_buffer[2];
或者你可以按照其他顺序进行,可以这么说:
unsigned long int data_value = 0;
data_value |= (unsigned long)data_buffer[0] << 16;
data_value |= data_buffer[1] << 8;
data_value |= data_buffer[2];
(这里你需要一个额外的演员阵容,如果你使用的是16位处理器,那么普通data_buffer[0] << 16
会将所有位移掉并丢失它们。)
或者您可以一次完成所有操作:
unsigned long int data_value =
((unsigned long)data_buffer[0] << 16) |
(data_buffer[1] << 8) |
data_buffer[2];
在任何情况下,您都可以进行所需的划分:
float float_value = (float)data_value / 0x7FFFFF;
(您可能希望使用double
代替float
。或者根据嵌入式环境的限制,您可能根本不希望使用这样的直接浮点;您没有'说。)
当我打印这些时,我会得到您要求的值:
printf("data_value = %#lX, float_value = %f\n", data_value, float_value);
的产率:
data_value = 0X18118C, float_value = 0.188036
附录:我忘了提到的一件事是,为了使这些技术正常工作,通常非常重要你的输入数据,即你的例子中的data_buffer
数组,是输入unsigned char
。如果不是 - 例如,如果它是普通的char
,这是在大多数机器上签名的 - 那么通常最终会出现令人虚弱的符号扩展问题。例如,如您所知,您的值140是十六进制数0x8c
,但被解释为签名 8位数字,它是-116。当它参与其他整数的表达式时,它通常会被符号扩展为0xff8c
或0xffffff8c
,这当然不是你想要的。 (你可以使用& 0xff
的额外掩码解决这个问题,正如SteveB的回答中所建议的那样,但这很麻烦。使用unsigned char
要简单得多。)
答案 1 :(得分:-1)
最简单的方法是将值移动到正确大小的整数。在您的示例中:
int data_value = 0;
for (i = 0; i < 3; ++i) {
data_value = data_value << 8;
data_value |= data[i] & 0xff; // Makes sure you are only adding 8 bits
}
您可以根据需要调整数组大小。您只需要确保data_value足以容纳所有内容。由于您正在使用24位数据,因此32位整数将起作用。然后,您将data_value分配给浮点值并进行除法。
double data_double = data_value;
double final_value = data_double / 8388607.0
您需要使用0x7FFFFF的浮点值来避免整数截断。