Forum: Mikrocontroller und Digitale Elektronik unerwünschter Interrupt bei Timeraktivierung


von marko (Gast)


Lesenswert?

Hi,

ich  bekomme folgendes Problem nicht inden Griff:

Wenn ich den Timer1 im Capture-Modus das erste mal frei schalte, löst er 
gleich einen Interrupt aus. Zwischendurch im Programm wird er dann mal 
wieder gesperrt und zurückgesetzt. Beim erneuten starten des Timers 
tritt der plötzliche Interrupt nicht mehr auf.

Ich frage mich also warum der Timer1 nach einem Hardware-Reset beim 
ersten freischalten einen Interrupt gibt. Ein voriges setzen von "kein 
IRQ da" im TIFR hilft auch nicht.

Momentan schaut das wie folgt aus:

(einmalige Konfiguration beim Start des Programmes)

ldi   r16, high(15625)
out   OCR1AH, r16
ldi   r16, low(15625)
out   OCR1AL, r16
ldi   r16, 0b00010100
out   TIMSK, r16

Später, wenn der Timer1 frei (und auf 0 zurück gesetzt wird) wird 
folgendes ausgeführt.

cli
ldi   r16, 0b00000000
out   TCNT1L, r16
out   TCNT1H, r16
ldi   r16, 0b00001100
out   TCCR1B, r16
ldi   r16, 0b11111111
out   TIFR, r16
sei

von Lutz (Gast)


Lesenswert?

Ich glaube mal was im Datenblatt zu dieser Vorgehensweise gelesen zu 
haben. Aktiviere den Interrupt im Zweifelfalle erst gleich nach Start 
des Timers.

P.S.: ldi   r16, 0b11111111 ist schlecht zu verstehen (zumal nichtmal 
kommentiert), lieber r16, (1<<XXX) | (1<<YYY) schreiben.

von Lutz (Gast)


Lesenswert?

Generelle Fragen:
- Welches Käferchen genau macht denn die Sorgen?
- In Assembler bin ich nicht wirklich fit, aber macht es wirklich Sinn, 
in beide Register (H und L) den gleichen Wert zu laden?
- Welchen Wert hat denn Dein Counter zu diesem Zeitpunkt 
(Initialisierung?)
- Du weißt schon, daß Du im zweiten Block nicht mehr auf OCR1A 
zugreifst?

von marko (Gast)


Lesenswert?

ldi   r16, 0b11111111
out   TIFR, r16


ist einfach nur alle Interruptzeigeregister auf 1 (also "kein Interrupt 
vorhanden") setzen

von marko (Gast)


Lesenswert?

Lutz:

- ATMega8
- H und L gehören zu dem 16-Bit Counterregister und müssen für "0" eben 
beide zurückgesetzt werden
- Der Counter hat irgendeinen Wert. Deswegen wird er manuell auf 8 
gebracht und DANN neu gestertet.
- das B ist mir auch nicht schlüssig aber mit A geht es nicht.

von marko (Gast)


Lesenswert?

Hmm, kann es daran liegen, dass sich die "Rücksetz- und 
Freischaltroutine" innerhalb eines interruptes (wird durch einen 
Interrupt ausgelöst) befindet und der Timer1 dann nach Aktivierung 
automatisch das I-Flag aus dem SREG Bearbeitet und deswegen auslöst?

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Ein Interrupt wird immer nur dann ausgelöst, wenn sowohl I-Flag im SREG, 
als auch das Freischaltbit im Steuerregister des Timers und das 
betreffende Interruptflag im TimerFlagRegister gesetzt ist. Die 
sicherste Variante, einen Interrupt zu aktivieren, ohne daß er gleich 
auslöst, ist die Interruptursache auszuschließen und direkt vor der 
Aktivierung das Interruptflag im TimerFlagRegister durch das Schreiben 
von "1" (!) zu löschen. Wie sieht denn Dein gesamter Code aus? Die 
gezeigten Segmente sagen nicht viel aus.

von Thilo M. (Gast)


Lesenswert?

Ich setze (wie marko das wohl meinte) vor der Freigabe eines Interrupts 
grundsätzlich die INT-Flags zurück. Wenn diese von der Harware nicht 
ständig gesetzt werden sollte das funktionieren.

von Johannes M. (johnny-m)


Lesenswert?

> ldi   r16, 0b00000000
> out   TCNT1L, r16
> out   TCNT1H, r16
Das geht schief! Bei 16-Bit-Registern muss immer das High-Byte zuerst 
geschrieben werden. Beim Lesen ist es umgekehrt.

von marko (Gast)


Lesenswert?

Travel: Genau das habe ich auch versuchst, löschen aller Interrupte 
(oder deren Flags)

Das Problem ist, dss der unerwünschet Interrupt NUR dann auftritt, wenn 
der  Timer das erste Mal initalisiert wird (nach Anschalten der 
Baugruppe). Sobald das ein mal geschehen ist laufen weitere Interrupte 
(auch nach erneutem softwarezzurücksetzen) einwandfrei.


Ich habe das Programm (600 Zeilen) auf das Wesentliche heruntergekürzt.

----------------------------------
.include       "m8def.inc"               ; ATMega8 Definitionsdatei


; ########## ORGANISATION UND INTERRUPTTABELLEN ##########

.CSEG
             rjmp   START            ; Reset Einsprungmarke

.ORG INT1addr
             rjmp   IRQ_EVENTS         ; IRQ Serviceprogramm

.ORG OC1Aaddr
             rjmp   CTC_MATCH         ; Timer1 (16-Bit) Serviceprogramm


; ########## HAUPTPROGRAMMBEREICH ##########

START:                              ; Begin Hauptprogramm

(Stackinitaklisierung usw.)


; Konfiguriere Timer1 (16 Bit) für CTC-Modus
ldi      r16, high(15624)   ; Lade Low-Byte der Vergleichzahl
out      OCR1AH, r16        ; Setze Low-Byte der Vergleichszahl
ldi      r16, low(15624)    ; Lade High-Byte der Vergleichzahl
out      OCR1AL, r16        ; Setze High-Byte der Vergleichszahl


; Konfiguriere Interrupte
ldi      r16, 0b00001100    ; INT1 konfigurieren (steigende Flanke)
out      MCUCR, r16         ; Lade Konfiguration nach MCUCR
ldi      r16, 0b10000000    ; INT1 aktivieren
out      GICR, r16          ; Lade Konfiguration nach GICR


; Leerlaufschleife (wird vom Interrupt verlassen)
loop:         rjmp   loop            ; Springe


; Behandel den CTC-Timer Interrupt
CTC_MATCH:
(Schreibt sachen auf ein Display)
(Geht nach Ablauf der zeit zu CTC_STOP)
rcall CTC_STOP
reti               ; Springe zurück (und gebe wieder Interrupt frei)



CTC_STOP:
ldi     r16, 0b00001000      ; Halte Timer an
out     TCCR1B, r16
ret




; Behandle die Taster-Interrupte
IRQ_EVENTS:

(tut diverses Zeugs mit Tastern, guckt welcher gedrückt wurde und geht 
bei einem bestimmten zur TIMER1-Routuine)

TIMER:
ldi      r16, 0b00000000
out      TCNT1L, r16
out      TCNT1H, r16
ldi      r16, 0b11111111
out      TIFR, r16
ldi      r16, 0b00010000      ; Lade "Interrupt bei Capture in Timer1"
out      TIMSK, r16           ; Setze Capture-Mode
ldi      r16, 0b00001100       ; Schalte Timer1 an
out      TCCR1B, r16

reti                  ; Springe zurück (und gebe wieder Interrupt frei)

von Falk B. (falk)


Lesenswert?

@ marko (Gast)

>Das Problem ist, dss der unerwünschet Interrupt NUR dann auftritt, wenn
>der  Timer das erste Mal initalisiert wird (nach Anschalten der
>Baugruppe). Sobald das ein mal geschehen ist laufen weitere Interrupte

Logisch, dann sieht die Capture-Logik eine Flanke. Machs einfach so.

Timer initialisieren
Capture Funktion initialisieren
Capture interrupt freigeben
Capture Interrut Flag löschen
Interrupts global freigeben

MFG
Falk

von marko (Gast)


Lesenswert?

Hi Falk

In der Tat tue ich nichts anderes. Der sicherheit halber:

- Vergleichwert nach OCR1A laden
- Capture Flag für Timer1 Match A in TIMSK setzen
- TIFR komplett (alle Flags) auf "1" setzen (Interrupflags Löschen)
- Globale Interrupte freigeben (SEI)

Irgendwann kommt dann der Punkt, an dem ein Tastendruck einen Interrupt 
auslöst. Innerhalb des Interruptes wird der TCNT1 auf 0 zurückgesetzt 
und danach der TCCR1B gestartet.

Nach diversen CTC-Interrupten wird der TCCR1B wieder gesperrt. Die 
erneute Freigabe erfolgt wieder durch den Tastendruck. (und so weiter)

von Falk B. (falk)


Lesenswert?

@ marko (Gast)

>- Vergleichwert nach OCR1A laden
>- Capture Flag für Timer1 Match A in TIMSK setzen
>- TIFR komplett (alle Flags) auf "1" setzen (Interrupflags Löschen)
>- Globale Interrupte freigeben (SEI)

Sollte passen.

>Irgendwann kommt dann der Punkt, an dem ein Tastendruck einen Interrupt
>auslöst.

Warum löst eine Taste einen Interrupt aus? Taste sollte man besser 
pollen.

> Innerhalb des Interruptes wird der TCNT1 auf 0 zurückgesetzt
>und danach der TCCR1B gestartet.

???
Was willst du mit TCCR1B starten?

MfG
Falk

von marko (Gast)


Lesenswert?

Falk:

Die Tastersache (nebensächlich): da sind 2 Taster:
"Zeit rauf/runter" und "Start/Stop". Die Taster sind entprellt. Sie 
bestimmen aber wann die uUr (Timer im Sekundentakt) startet und damit 
auch wann ich den Timer lösche und starte oder eben stoppe.


TCCR1B starte (und stoppe) ich , in dem ich bei den ersten 3 Bits (0-2, 
Teiler) eben "000" (Stop) oder "100" (Systemtakt durch 256) lade.

von Falk B. (falk)


Lesenswert?

@ marko (Gast)

>Die Tastersache (nebensächlich): da sind 2 Taster:
>"Zeit rauf/runter" und "Start/Stop". Die Taster sind entprellt. Sie
>bestimmen aber wann die uUr (Timer im Sekundentakt) startet und damit
>auch wann ich den Timer lösche und starte oder eben stoppe.

Dazu braucht man dennoch keinen Interrupt. Ein Pollen im 10ms 
Timerinterrupt ist vollkommen ausreichend.

>TCCR1B starte (und stoppe) ich , in dem ich bei den ersten 3 Bits (0-2,
>Teiler) eben "000" (Stop) oder "100" (Systemtakt durch 256) lade.

Ahhh, du stopst und startest Timer1 DURCH TCCR1B!

MfG
Falk

von marko (Gast)


Lesenswert?

Genau. Der Interrupt (timer) ist NICHT zum entprellen der Tasten da. Der 
Timer ist für den sekundentakt der Uhr zuständig.

Un das Problem ist, dass bei der ersten Timeraktivierung (irgendwann 
nach dem Strom angelegt und der Start-Taster gedrück wurde) eben eine 
Sekunde sofort abgezogen wird. Das kommt daher, dass der Timer irgendwie 
beim ersten Mal sofort einen Interrupt auslöst. Bei allen nachfolgenden 
Durchläufen ist alles wie es sin soll.

Das verstehe ich nicht. Irgendwo muss was sein, was einen Flag setzt. Da 
ist aber nichts.

von Falk B. (falk)


Lesenswert?

@ marko (Gast)

>Un das Problem ist, dass bei der ersten Timeraktivierung (irgendwann
>nach dem Strom angelegt und der Start-Taster gedrück wurde) eben eine
>Sekunde sofort abgezogen wird. Das kommt daher, dass der Timer irgendwie
>beim ersten Mal sofort einen Interrupt auslöst. Bei allen nachfolgenden
>Durchläufen ist alles wie es sin soll.

Ahhhh, es dämmert. Ich glaube nicht, dass dein Timer einen Interrupt 
auslöst, das ist sehr systematisch und deterministisch. Aber wenn deine 
Tastenauswertung per Software auf einen Flanke reagiert, dann ist es 
durchaus möglich, dass deine Variablen für diese Tastenauswertung falsch 
initialisiert sind. Denn meist sind die Tasten Low aktiv, mit Pull-Ups. 
Deine Variablen werden aber meist mit Null initialisiert, wenn nich 
explizit was anderes gemacht wird. Die erste Abfrage sieht die Tasten 
jetzt auf HIGH (PINx) und wertet das als steigende Flanke, und löst 
dabei eine Aktion in deiner Software aus.

>Das verstehe ich nicht. Irgendwo muss was sein, was einen Flag setzt. Da
>ist aber nichts.

In deiner Tastenauswertung.

MfG
Falk

von marko (Gast)


Lesenswert?

Hmm, wäre schön, wenn das so wäre. Ich habe eben das Progrmm testweise 
umgebaut: es startet selbstständig (ohne Tastenaufforderung) die 
Timerinitalisierung.

Die wartezeit vom Timer1 habe ich auf ca. 3 sekunden erhöhrt. Was 
passieren SOLLTE, ist, dass nach ca. 3 sekunden die Uhr eine Sekunde 
weiter geht. Sie tut es aber sofort nach dem einschalten, wartet also 
keine 3 Sekunden sondern macht sofort einen Interrupt.

Was mich etwas verwirrt ist, dass ich TCCR1B (B) starte/stoppe aber den 
vergleichwert nach OCR1A (A) lade. Ich hab auch noch mal Im CTC-Clock 
Tutorial hier auf dem Board nachgeguckt. Das selbe Beispiel.

Ansich würde ich davon ausgehen, dass ich versehens mit zwei 
verschiedenen Timern arbeite oder versehens Sachen in 2 verschiedenen 
Timerregistern speicher. Aber nach dem Erst-Aufruf-Fehler läuft ja alles 
so, wie es soll.

von marko (Gast)


Lesenswert?

Ich habe mir inzwischen die Mühen gemacht und das Programm auf ein 
Minimum reduziert. Wie oben auch, also ohne Taster, startet das Programm 
bei dem Erstdurchlauf einen Interrupt ohne zu warten.

Mir fällt nichts anderes meher ein.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

>ldi      r16, 0b00000000
>out      TCNT1L, r16
>out      TCNT1H, r16

Sieht Dein Code immer noch so aus? Das High-Register muß zuerst 
geschrieben werden. Ach: und welcher Interrupt wird ausgelöst? Du 
sprichst immer von Capture, hast aber den Compare (!) Interrupt 
aktiviert. Noch eine Idee: initialisiere die TimerRegister TCNT0H/L vor 
dem Löschen der InterruptFlags und vor dem Aktivieren der Interrupts mal 
auf 1.

von Falk B. (falk)


Lesenswert?

@ marko (Gast)

>Ich habe mir inzwischen die Mühen gemacht und das Programm auf ein
>Minimum reduziert. Wie oben auch, also ohne Taster, startet das Programm
>bei dem Erstdurchlauf einen Interrupt ohne zu warten.

Na dann zeig mal den Quelltext. Als Anhang.

MFG
Falk

von marko (Gast)


Lesenswert?

Hmm, ja, ich hab mir die Arbeit gemacht das noch mal auf einem anderen 
Weg zu schreiben (noch simpler und ohne Wartezeiten). Plötzlich ging es. 
Beim Vergleichen fiel der Groschen: in einer Subroutine ein pop 
vergessen... NARF!

Danke für Eure tatkräftige Unterstützung! :)

von Niels H. (monarch35)


Lesenswert?

Eine Heiseforum-"Weisheit" besagt:

Mit "C" wäre das nicht passiert! :)

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
Noch kein Account? Hier anmelden.