设置位和将逻辑一个位写入位有什么区别?

What is the difference between setting a bit and writing logic one to a bit?

我正在研究 Atmel ATMega 的 TWI,示例代码让我很困惑。它说中断标志 TWINT 必须通过向其写入逻辑 1 来清除,所以我想在 C 中发送 START 条件是这样的

TWCR |= (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)

然而在示例代码中是这样的

TWCR = (1<<TWINT)|(1<<TWSTA|(1<<TWEN)

在Atmel页面上也说TWCR |=(1<<TWINT)是清除中断标志的错误方法http://www.atmel.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_intbits.html 那么设置位和写入位之间的区别是什么,因为使用 TWCR |=(1<<TWINT)

是错误的

我正在使用 Atmel 2549 8 位微控制器的数据表。示例代码取自第 24.6

linked FAQ说的很清楚了(最后一段是重点)——你只需要将这个寄存器中的相关中断位设置为1就可以清除中断(设置位为0没有效果).因此无需保留其他位的状态,使用写入而不是读取-修改-写入将避免读取周期和写入周期之间可能出现的潜在竞争条件。

如何正确写入寄存器要视具体情况而定。 link 你提到的 中断标志​​寄存器 通过写入 1.

来清除

假设您有带有两个标志的 8 位寄存器 REG。你想清除 lsb 标志。如果你写

#define FLAG0 0x01
#define FLAG1 0x02
...
REG = FLAG0;

然后这将转换为机器代码"in REG, write value 1 to bit 0",正确清除标志。

如果您这样做 REG |= FLAG0,则程序将首先读取寄存器并将读取的值存储在临时位置。假设寄存器的值为 0x03,两个标志都已设置。您的代码会将 0x01 写入此临时位置,但由于按位或,它还会保留其他不相关标志的值。因此,您最终将值 0x03 写回到 REG,同时清除了所需的标志和不相关的标志。

中断标志寄存器非常精巧,因为它们可以通过各种不适合C编程的怪异逻辑来实现,例如"clear by writing 1"或"clear by read with flag set"。因此,我强烈建议始终反汇编清除此类标志的 C 代码,并检查代码实际执行的操作。

|= 赋值是一个读取-修改-写入操作,但并非所有硬件寄存器的行为都像内存位置 - 在这种情况下,位值由硬件设置并读取 and/or 由软件清除。软件写入不存储写入的值,但在这些位的情况下清除该位。 TWCR 中的其他位具有不同的行为,但是 none 可以设置为特定值并且将零写入其中任何一个都没有效果。

因此读-改-写是不必要的,而且不正确 - 它可能会导致无意中清除位。

这就是文档对术语 "writing logic one" 非常小心的原因,因为它明确不会 "set the bit" - 它会清除它。