将两个8位uint转换为一个12位uint

时间:2012-06-04 08:48:28

标签: c bit-manipulation bit

我正在从微控制器读取两个寄存器。一个具有4位MSB(前4位还有其他一些东西)和另一个8位LSB。我想将它转换为一个12位uint(准确地说是16位)。到目前为止,我做到了这样:

UINT16 x;
UINT8 RegValue = 0;
UINT8 RegValue1 = 0;

ReadRegister(Register01, &RegValue1);
ReadRegister(Register02, &RegValue2);

x = RegValue1 & 0x000F;
x  = x << 8;
x = x | RegValue2 & 0x00FF;

还有更好的方法吗?

/ * 更准确一点ReadRegister是与另一个ADC的I2C通信。 Register01和Register02是不同的地址。 RegValue1是8位,但只需要4个LSB并连接到RegValue(RegValue1的4-LSB和RegValue的所有8位)。 * /

3 个答案:

答案 0 :(得分:2)

如果您知道机器的字节序,则可以读取字节数 直接进入x就像这样:

ReadRegister(Register01, (UINT8*)&x + 1);
ReadRegister(Register02, (UINT8*)&x);
x &= 0xfff;

请注意,这不是便携式的,性能提升(如果有的话)会 可能很小。

答案 1 :(得分:0)

RegValue & 0x00FF掩码是不必要的,因为RegValue已经是8位。

将其分解为三个语句可能有利于清晰,但这个表达式可能很简单,可以在一个语句中实现:

x = ((RegValue1 & 0x0Fu) << 8u) | RegValue ;

使用无符号文字(0x0Fu)几乎没有区别,但强调我们正在处理无符号的8位数据。它实际上是一个unsigned int,即使只有两位数,但这再次向读者强调我们只处理8位,而且纯粹是风格而不是语义。在C中,没有8位字面常量类型(尽管在C ++中'\x0f'具有类型char)。您可以按如下方式强制执行更好的类型协议:

#define LS4BITMASK ((UINT8)0x0fu)

x = ((RegValue1 & LS4BITMASK) << 8u) | RegValue ;

宏只是避免表达中的重复和混乱。

在性能或实际生成的代码方面,上述所有内容都不一定比原始代码“更好”,并且主要取决于偏好或本地编码标准或实践。

答案 2 :(得分:0)

如果寄存器彼此相邻,那么它们在目标字节序方面也可能是正确的顺序。在这种情况下,它们可以作为单个16位寄存器读取并相应地屏蔽,假设Register01是较低的地址值:

ReadRegister16(Register01, &x ) ;
x &= 0x0fffu ;

当然我在这里发明了ReadRegister16()函数,但如果寄存器是内存映射的,Register01只是一个地址,那么这可能只是:

UINT16 x = *Register01 ;
x &= 0x0fffu ;