如何将寄存器的一部分仅更改为数字(示例做错了?



例如,我想将数字 32 写入寄存器的 16-24 位。此寄存器长 100 位,其余或某些寄存器包含不应写入的"保留位"(根据数据表),或者假设它包含我不想更改的其他值(以前的设置)。

如果只有几位,我可以为每个位设置R &= ~(1 << x)R |= 1 << x。但如果它是一个数字,将 32 变成二进制并一个接一个地完成将是一个巨大的痛苦。我看到一些例子基本上是做类似R = 0x20 << 16.但我很困惑。这不会破坏其他位并将保留位设置为 0 以扰乱 MCU 操作吗?

例如,

我想将数字 32 写入寄存器的 16-24 位。此寄存器长 100 位,其余或某些寄存器包含不应写入的"保留位"(根据数据表),或者假设它包含我不想更改的其他值(以前的设置)。

您想要执行读取-修改-写入。在本例中,您有兴趣将位 16-24 设置为特定值。假设这些值为零,您可以这样做:

my_register |= (32 << 16);

这是一个按位 OR 操作,需要注意这一点很重要,因为它保留了位的值。

假设这些值不为零,您需要先清除这些位,然后写入新值。你可以这样做:

my_register &= ~(0xFF << 16); //Clear bits 16-24
my_register |= (0x20 << 16); //Set bits 16-24 to 32

上面使用按位 AND、按位 OR 和按位反转。同样,这些操作维护其他位的值。

我看到一些例子基本上是做类似 R = 0x20 <<16 的事情。 但我很困惑。那岂不是毁了其他位并设置 保留位为 0 弄乱 MCU 操作?

这不一定是真的。这些位可能是写保护的,或者这些位的默认值可能是 0,因此对它们写入 0 不起作用。这仅取决于MCU本身。

这里有一个理解原则的函数:

unsigned SetSomeBits(unsigned Var, unsigned StartBitNumber, unsigned NumberOfBits, unsigned Value2Set)
{
unsigned Mask = (1<<NumberOfBits)-1; //With NumberOfBits=3 Mask becomes 0b000111 
Mask <<= StartBitNumber;
//Mask contains now 0 at do-not-touch  bit positions
//Mask contains now 1 at to-be-changed bit positions
Var &= ~Mask; //Zero out the to-be-changed bits
return Var | (Value2Set<<StartBitNumber); //Set the requested bits
}

。这里作为一个宏:

#define SET_SOME_BITS(Var, StartBitNumber, NumberOfBits, Value2Set) ((Var) & ~(((1<<(NumberOfBits))-1)<<(StartBitNumber)) | (Value2Set)<<(StartBitNumber))

如果 Value2Set 不适合 NumberOfBits,则两个版本都将失败。

相关内容

最新更新