ich möchte im Timer Interrupt Flag Register mit dem Befehl "cbi TIFR" ein Flag 0 setzen. Doch das löst nur die folgende Fehlermeldung aus: warten2.asm(233): error: Operand 1 out of range: 0x38 Woran mag das liegen? Das TIFR ist doch auch ein I/O-Register, das mit cbi, sbi anzusprechen sein müsste?!? (zumindest funktionieren die Befehle "in" und "out" auf dem Register)
das heisst wohl, dass sbi/cbi nur auf die register $0 bis $31 anzuwenden sind, oder? gibt es dazu einen eleganteren Umweg (am besten mit nur 1 Befehl)?
das hat aber glaub ich eine (zwar sehr kleine) unzuverlässigkeit. wenn ein flag nach dem IN befehl gesetzt wird, überschreib ich nachher mit out diese flag, deswegen hätte ich gerne das ganze in einem befehl gehabt
Das ist wohl wahr, aber erstens kann sowas ja nur in einem Interrupt passieren und zweitens ist die Wahrscheinlichkeit, dass der genau dort feuert äusserst gering. Wenn du ganz sicher sein willst, kannst du ja immer noch die Ints kurzzeitig ausschalten (cli, in, andi/ori, out, sei).
@Markus: Yep, das ist eine Schwäche der AVRs. http://www.mikrocontroller.net/articles/Interrupt#Interrupt-feste_Programmierung
> das hat aber glaub ich eine (zwar sehr kleine) unzuverlässigkeit. > wenn ein flag nach dem IN befehl gesetzt wird, überschreib ich > nachher mit out diese flag, deswegen hätte ich gerne das ganze in > einem befehl gehabt Wenn du den ausführst, nachdem das Flag gesetzt wurde, überschreibst du's doch auch.
Wenn Du in einem Register, das nur Interrupt-Flags enthält (TIFR, GIFR...) ein Bit löschen willst (und das ginge sowieso nicht mit cbi, selbst dann, wenn das Register im bitadressierbaren Bereich läge, da ein Interrupt-Flag gelöscht wird, indem man eine eins hineinschreibt), dann schreib einfach die Bitmaske, in der die zu löschenden Bits '1' sind, mit out in das Register! Also wenn Du z.B. das OCF0 löschen willst, dann einfach mit ldi r16, (1 << OCF0) out TIFR, r16 Da das Schreiben einer '0' sowieso keinen Effekt hat, funktioniert das ganz hervorragend. Und in solchen Fällen: Finger weg von 'in -> ori -> out'! Damit löschst Du alle Flags im Register, die zum Zeitpunkt des Einlesens (in) gesetzt waren! Immer eine direkte Zuweisung benutzen. Das gilt auch in C (also kein '|=' sondern ein '='). Im Datenblatt der AVRs steht übrigens auch noch, dass sbi und cbi alle Bits im betreffenden Register betreffen! Wenn Du in einem Register, das bitadressierbar ist und das gleichzeitig Interrupt-Flags enthält (also z.B. ADCSR(A)) ein Bit mit sbi setzt, löschst Du gleichzeitig alle Interrupt-Flags in diesem Register (also im Beispiel das ADIF)!
Ach, übrigens: Die Information über sbi und cbi steht in den AVR-Datenblättern als Fußnote unter dem Register Summary. Ich hab das damals auch eher zufällig entdeckt. Sonst habe ich diese Information nirgends gefunden, auch nicht im Instruction Set Manual (wo sie imho eigentlich hingehört)... Die generellen Infos zum Löschen von Interrupt Flags gibts übrigens auch in der AVR Checkliste auf dieser Seite.
Aus dem Instruction Set Manual, zu CBI: "Clears a specified bit in an I/O Register. This instruction operates on the lower 32 I/O Registers – addresses 0-31."
Richtig, aber die Zusatzinfo, dass cbi und sbi alle Interrupt Flags im betroffenen Register löschen steht anscheinend nur im Datenblatt...
Das steht da nicht drin, weil es wirklich rein garnichts mit diesen Befehlen zu tun hat. Das ist eine Eigenschaft des Registers und ist völlig unabhängig davon, mit welchen Befehlen man das macht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.