2016-05-24 12 views
1

Ich studiere TWI von Atmel ATMega und der Beispielcode Bug mich. Es heißt, dass die Interrupt-Flag TWINT durch das Schreiben einer logischen Eins, um es gelöscht werden müssen, so nehme ich an, dass es wie dies in C ist START-Bedingung es soWas ist der Unterschied zwischen dem Setzen eines Bits und dem Schreiben von Logik Eins auf ein Bit?

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

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

jedoch im Beispielcode zu senden

es wird auch gesagt, in der Atmel-Seite, dass TWCR |=(1<<TWINT) falscher Weg ist Interrupt-Flag löschen http://www.atmel.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_intbits.html so was ein wenig und das Schreiben auf ein Bit zwischen Einstellung es anders zu machen, da es falsch ist, TWCR |=(1<<TWINT)

zu verwenden

Ich verwende das Datenblatt des Atmel 2549 8-Bit Mikrocontrollers. Der Beispielcode ist aus Abschnitt 24.6

+0

Das ist eine gute Frage. Es ergibt sich aus dem "write 1 clear" Verhalten bestimmter Arten von Hardware-Registern, was in der Welt der Hardware-Schnittstellen recht häufig vorkommt, kann aber eine ungewohnte Überraschung für diejenigen sein, die aus einem eher alltäglichen Software-Hintergrund kommen. Bitte beachten Sie dieses Detail, bevor Sie zu der Frage abstimmen. –

Antwort

5

Wie man ordnungsgemäß in Register schreibt, geschieht von Fall zu Fall. Der Link, den Sie verweisen sprechen von unterbrechen Flagregister, die durch das Schreiben eines 1.

gelöscht Angenommen, Sie haben die 8-Bit-REG mit zwei Fahnen registrieren. Sie möchten das lsb-Flag löschen. Wenn Sie

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

schreiben Dann wird diese in Maschinencode übersetzen „in REG, schreiben Wert 1 Bit 0“, die korrekt die Flagge löscht.

Wenn Sie jedoch REG |= FLAG0 tun, liest das Programm zuerst das Register und speichert den gelesenen Wert an einem temporären Speicherort. Nehmen wir an, das Register hat den Wert 0x03, beide Flags sind gesetzt. Ihr Code wird 0x01 an diesen temporären Speicherort schreiben, aber wegen des bitweisen OR wird auch der Wert von anderen, nicht verwandten Flags beibehalten. Sie schreiben also den Wert 0x03 bis REG zurück und löschen sowohl das gewünschte Flag als auch ein nicht verknüpftes Flag.

Interrupt-Flag-Register sind sehr heikel, weil sie durch alle Arten von seltsamer Logik implementiert werden können, die nicht gut mit C-Programmierung zusammenpasst, wie "Löschen durch Schreiben 1" oder "Löschen durch Lesen mit Flag gesetzt" . Daher empfehle ich dringend die Praxis, C-Code immer zu disassemblieren, der solche Flags löscht, und zu überprüfen, was der Code tatsächlich tut.

1

Der linked FAQ ist ziemlich klar (der letzte Abschnitt ist der wichtige Teil) - Sie müssen nur relevante Interrupt-Bits in diesem Register auf 1 setzen, um Interrupts zu löschen (Bits auf 0 setzen hat keine Wirkung). Daher ist es nicht notwendig, den Zustand anderer Bits zu bewahren, und die Verwendung eines Schreibens statt eines Lese-Modifizieren-Schreibens vermeidet eine potentielle Race-Bedingung, die zwischen dem Lesezyklus und dem Schreibzyklus auftreten kann.

+1

Aber die Frage ist, warum die Atmel-Dokumente angeben, dass Sie die erste Version nicht machen sollten. –

+0

@OliverCharlesworth: Oh, ich sehe - Antwort aktualisiert. –

1

Die | = - Zuweisung ist eine Lese-Modifizier-Schreib-Operation, aber nicht alle Hardwareregister verhalten sich wie Speicherplätze - in diesem Fall werden die Bitwerte von der Hardware gesetzt und von der Software gelesen und/oder gelöscht. Das Schreiben per Software speichert den geschriebenen Wert nicht, aber bei diesen Bits wird das Bit gelöscht. Andere Bits in TWCR haben ein unterschiedliches Verhalten, aber keines kann auf einen bestimmten Wert gesetzt werden, und das Schreiben von Null auf eines davon hat keine Auswirkungen.

Daher ist das Lesen-Modifizieren-Schreiben unnötig, und falsch - es kann unbeabsichtigt das Löschen eines Bits verursachen.

Aus diesem Grund ist die Dokumentation vorsichtig mit dem Begriff "Schreiben einer logischen Eins", weil es speziell nicht "das Bit setzt" - es löscht es.