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

时间:2016-05-24 08:37:35

标签: c embedded bit-manipulation

我正在研究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节

3 个答案:

答案 0 :(得分:5)

如何正确写入寄存器是根据具体情况完成的。您所指的链接是指中断标志寄存器,它们通过写入1来清除。

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

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

然后这将转换为机器代码&#34;在REG中,将值1写入位0和#34;,这会正确清除该标志。

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

中断标志寄存器非常精巧,因为它们可以通过各种奇怪的逻辑来实现,这些逻辑与C编程并不顺利,例如通过写1&#34;或&#34;通过标记设置&#34;清除。因此,我强烈建议总是反汇编清除此类标志的C代码,并检查代码实际执行的操作。

答案 1 :(得分:1)

linked FAQ非常清楚(最后一段是重要部分) - 您只需要将该寄存器中的相关中断位设置为1以清除中断(将位设置为0无效)。因此不需要保留其他位的状态,并且使用写而不是读 - 修改 - 写将避免在读周期和写周期之间可能出现的竞争条件。

答案 2 :(得分:1)

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

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

这就是为什么文档对术语&#34;写逻辑1&#34;时要小心,因为它特别没有&#34;设置位&#34; - 它清除它。