2012-06-04 67 views
0

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

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位)。 */

+0

“更好”在哪个意义上?这取决于什么对你很重要,例如便携性,速度,代码密度... –

+0

我想你想要'x = x | (RegValue&0xFF)' – Esailija

+0

@Esailija:'&'具有比'|更高的优先级。 –

回答

0

由于RegValue已经是8位,因此不需要RegValue & 0x00FF掩码。

分解成三句话可能是很好的清晰度,但这种表达可能是很简单的一个语句来实现:

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

使用一个无符号的文字(0x0Fu)的差别不大,但强调我们正在处理无符号的8位数据。事实上,即使只有两位数字,它也是一个unsigned int,但是这也强调了读者或许我们只处理8位,并且纯粹是文体而不是语义。在C中没有8位文字常量类型(尽管在C++ '\x0f'中有类型char)。你可以强制更好的类型协议如下:

#define LS4BITMASK ((UINT8)0x0fu) 

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

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

在性能或实际生成的代码方面,以上都不比您的原始代码“更好”,主要是偏好或本地编码标准或实践问题。

+0

_ RegValue&0x00FF掩码是不必要的,因为RegValue已经是8 bit._您是对的 - 这是不必要的 – PawelZ

+0

请注意,从编译器的角度来看,使用'LS4BITMASK'是毫无意义的@PawelZ。 '&'会导致整数升级,所以这些位操作是通过'int's [按照as-if规则来执行的,如果硬件允许8位类型的位操作,那么可以使用这些操作,只要它们产生与如果使用'int']。如果没有转换到'UINT8',掩码'0x0Fu'会导致操作在'unsigned int'上执行。这些值不会右移,编译器应该很明显'(RegValue1&0x0Fu)<< 8'可以用int来表示,两者都应该导致相同的代码。 –

+0

@丹尼尔:我很确定我已经明确表示它不会生成*更好的翻译*。然而,它可以说是更好的人类可读代码。许多编码标准要求避免使用“幻数”,而且我可能花了很长时间通过静态分析“清理”代码。我原本想提到隐含的演员参与,但决定它可能只会造成混淆。 – Clifford

2

如果你知道你的机器的存储方式,可以读取字节 直接进入x这样的:

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

请注意,这不是便携和性能增益(如有)将 可能很小。

0

如果寄存器是彼此相邻的,那么它们最有可能与目标字节顺序相关的顺序也是正确的。这是它们可以被视为单一的16位寄存器,并相应地掩蔽的情况下,假定Register01是低位地址值:

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

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

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

@undur_gongor:感谢您的更正。卫生署! – Clifford