C语言 将两个 8 位 uint 转换为一个 12 位 uint



我正在从微控制器读取两个寄存器。一个有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通信。寄存器01和寄存器02是不同的地址。RegValue1 是 8 位,但只需要 4 LSB 并连接到 RegValue(RegValue1 的 4-LSB 和所有 8 位的 RegValue)。*/

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

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

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

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 ;

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

就性能或实际生成的代码而言,以上都不一定比原始代码"更好",并且在很大程度上是偏好或本地编码标准或实践的问题。

如果寄存器彼此相邻,则它们在目标字节序方面也非常容易。 在这种情况下,它们可以被读取为单个16位寄存器并相应地屏蔽,假设Register01是较低的地址值:

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

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

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

最新更新