Irgendwie finde ich im Datenblatt vom ATMega8 kein Interrupr füt Match on Compare vom Timer0. Sagt jetzt bloß nicht, das Timer0 das nicht unterstützt.
Druckbare Version
Irgendwie finde ich im Datenblatt vom ATMega8 kein Interrupr füt Match on Compare vom Timer0. Sagt jetzt bloß nicht, das Timer0 das nicht unterstützt.
Tja was soll ich sagen...Zitat:
Sagt jetzt bloß nicht, das Timer0 das nicht unterstützt.
Nimm den Timer 2....
Gruß Sebastian
Also das mit dem Match on Compare lasse ich erstmal sein. Ich komme nämlich bei einem kleine Programm nicht weiter. Die LED leuchtet nicht. ;-)
Wo ist da der Fehler?
Ich wette, dass da irgend ein Flag nicht gesetzt wurde.Code:.include "m8def.inc"
.def temp = r16
.org 0x000
rjmp main
.org 0x009
rjmp timer
main:
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
sbi DDRD, PD5
sei
loop:
rjmp loop
timer:
sbi PORTD, PD5
reti
Schreib besserZitat:
.org 0x009
Ist doch besser zu lesen, oder ?Code:.org OVF0addr
Damit hättest Du die Wette gewonnen, schau mal im Dattenblatt nach :Zitat:
Ich wette, dass da irgend ein Flag nicht gesetzt wurde.
TCCR0 ->Prescaller
TIMSK -> Interrupt beim Überlauf freischalten
eventuell
TCNT ->um den Timerwert vorzugeben...
Mach es andersrum, zuerst High und dann LOW schreiben, es gibt da Registerpaare, wo das nicht egal ist!!Zitat:
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
Gruß Sebastian
Ich wollte mit SBI TCCR0, CS02 ein Bit in den Register setzen, aber der Compiler meldet: "Out of range".
Mit LDI temp, 0b00000100 und dann OUT TCCR0, temp hat es dann geklappt. Aber jetzt frage ich mich, wie ich einzelne Bits in dem Register manipulieren kann, ohne andere zu beeinflussen?
Noch was:
Ne ganz komische Sache. Beim ersten Überlauf wird der Interrupt aktiviert, alles ok. Der TOV0 Flag wird auch (automatisch) zurückgesetzt und die LED geht an. Beim zweiten Überlauf kommt das Programm aber nicht mehr aus der loop-Schleife und der TOV1 Flag wird zwar gesetzt, aber nicht mehr gelöscht. Auch die Befehle ldi temp, (1<<TOV0) und out TIFR, temp haben da nicht gebracht. Woran liegt das?
Hier der Quellcode:
Code:.include "m8def.inc"
.def temp = r16
.org 0x000
rjmp main ; Reset Handler
.org OVF0addr
rjmp timer ; Timer0 Handler
main:
ldi temp, HIGH(RAMEND)
out SPH, temp
ldi temp, LOW(RAMEND)
out SPL, temp
sbi DDRD, PD5
cbi DDRD, PD2
ldi temp, 0b00000001
out TCCR0, temp
ldi temp, 0b00000001
out TIMSK, temp
sei
loop:
rjmp loop
timer:
sbis PORTD, PD5
rjmp setLED
sbic PORTD, PD5
rjmp clrLED
setLED:
sbi PORTD, PD5
ldi temp, (1<<TOV0)
out TIFR, temp
rjmp loop
clrLED:
cbi PORTD, PD5
ldi temp, (1<<TOV0)
out TIFR, temp
rjmp loop
Wenn du nur das eine Bit ändern möchtest kannst du es auch so versuchen:Zitat:
Zitat von cipoint
Code:in r16, TCCR0
ori r16, (1<<CS02)
out TCCR0, r16
Das liegt dadran, das mein eine ISR (und timer ist eine) nicht mit rjmp #label sondern mit reti verlassen wird.Zitat:
Zitat von cipoint
Grüße,
Hanni.
Danke, dann schreib' ich das Programm um.
edit: Habe Schwierigkeiten, das zu realisieren. Bin eben noch sehr unerfahren, was den Stack angeht.
Also ein Flowchart habe ich schonmal angefertigt. Mit dem Quellcode klappt das alleridngs noch nicht.
Bild hier
Der uC befindet sich zunächst in einer Endlosschleife. Im Interrupthandler vom Timer0 (Label timer) wird dann mit sbic abgefragt, ob die LED an ist. Wenn nicht, springt der uC zum Label LEDon. Dort wird die LED angemacht. Danach kehrt der uC ja aber wieder zurück zum Label timer. Dort steht leider der Befehl sbis, nach welchem der Sprung zu LEDoff steht.
Wie verhindere ich also, dass der uC nicht nach LEDoff springt, wenn er im selben Durchlauf schon in LEDon war?
edit²: Habe das jetzt so gelöst.
Ist das programmiertechnisch und stilistisch richtig?Code:include "m8def.inc"
.def temp = r16
.def oldStatus = r17
.org 0x000
rjmp main ; Reset Handler
.org OVF0addr
rjmp timer ; Timer0 Handler
main:
ldi temp, HIGH(RAMEND)
out SPH, temp
ldi temp, LOW(RAMEND)
out SPL, temp
sbi DDRD, PD5
cbi DDRD, PD2
ldi temp, 0b00000001
out TCCR0, temp
ldi temp, 0b00000001
out TIMSK, temp
sei
cbi PORTD, PD5
loop:
rjmp loop
timer:
sbic PORTD, PD5
rjmp LEDoff
sbi PORTD, PD5
reti
LEDoff:
cbi PORTD, PD5
reti
Programmiertechnisch schon, über den Stil und die Lesbarkeit kann man sicher streiten.Zitat:
Zitat von cipoint
Anstatt:
würde ich in dem Teil das folgende schreiben:Code:ldi temp, 0b00000001
out TCCR0, temp
ldi temp, 0b00000001
out TIMSK, temp
Das ganze ist meiner Ansicht nach vor allem besser lesbar.Code:ldi temp, (1<<CS00)
out TCCR0, temp
ldi temp, (1<<TOIE0)
out TIMSK, temp
Im übrigen sollte man in Interupt Routinen prinzipiell das Status Register SREG sichern. dieses kann z.B. wie folgt erfolgen:
Dieses ist insbesondere dann wichtig, wenn in deinem Loop und in der ISR Operationen durchgeführt werden, bei denen Flags im SREG verändert werden können.Code:timer:
push temp
in temp, SREG
push temp
sbic PORTD, PD5
rjmp LEDoff
sbi PORTD, PD5
rjmp timer_exit
LEDoff:
cbi PORTD, PD5
timer_exit:
pop temp
out SREG, temp
pop temp
reti
In deinem Programmablaufplan würde ich die Timer Interupt Routine komplett entkoppelt zeichnen. Zum einen, weil der µC nach dem Interupt exakt dort weitermacht, wo er aufgehört hat und zum anderen, weil es später weniger verwirrend wirkt.
Grüße,
Hanni
Aber wenn ich CS00, CS01 und CS02 manipulieren will, und zwar getrennt voneinander? Bleibt mir da nur die Möglichkeit, den kompletten Register auszulesen, mit OR oder AND zu bearbeiten und zurückzuschreiben?Zitat:
Zitat von Hanni
Für I/O Register gibt es ja sbi und sbi. Und für "normale" Register?
z.B.: ldi temp, (1<<CS00) | (1<<CS01)Zitat:
Zitat von cipoint
zum setzen von 2 Bits.