www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ATmega8 Timer Problem


Autor: Roland M. (eroli)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich bin noch ziemlich neu in der uC-Programmierung.
Ich wollte ein Programm schreiben, dass 2 verschiedene Blink-Programme 
ausführt. Im ersten Programm sollen PortD und PortB blinken und im 
zweiten Programm sollen sie ganz simpel leuchten.

Das Blinken geschieht in Timer0 und funktionierte in vorherigen Tests 
auch schon.

Der Programmwechsel sollte im OverflowHandler von Timer1 stattfinden, 
aber das klappt leider nicht so ganz.

Vielleicht könnte mir jemand Denkanstöße liefern und andere Fehler in 
meinem Quelltext finden?

Vielen Dank,
Eroli

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ldi temp,  1<<TOIE0  ;Ein INT auslösen,
out TIMSK, temp    ;falls ein TC0-Überlauf-Interrupt auftritt.
...
ldi temp, 1 << TOIE1  ;Timer1-Overflow-Interrupt aktivieren...
out TIMSK, temp        ; ... und setzen

Nach dem Ausführen dieses Codes ist in TIMSK nur TOIE1 gesetzt, TOIE0 
nicht.

Autor: Roland M. (eroli)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

erstmal Danke für deine Antwort. Auf solche Stolperfallen muss man 
erstmal achten...

Habe das nun so umformuliert:
ldi temp, 0b00000101  ; Timer0-Overflow und Timer1-Overflow "erlauben"
out TIMSK, temp

Das gesamte Programm habe ich nochmal angehangen.

Leider ist das Verhalten immer noch nicht ganz richtig. Nach ca. 60 
Sekunden fängt es an zu blinken und dann hört es nie wieder auf.

Leider kann ich das auch nicht debuggen, da meine Breakpoints (je einer 
in der ersten Zeile des Overflow-Interrupts) nicht erreicht werden oder 
zumindest nicht feuern (das Programm läuft einfach weiter?)

Kann mir einer sagen, woran das liegen könnte?

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Das passt nicht so richtig:

>       ...
>  brge resetProg    ; "Programmüberlauf" --> prog = 0
>
>  pop  temp      ; LESEN von SREG vom STACK (KOPIE)
>  out  SREG, temp    ; Wiederherstellen von SREG
>  pop  temp      ; Wiederherstellen von "TEMP"
>
>resetProg:
>  ldi prog, 0x00    ; Zuruecksetzen
>       reti

resetProg wird immer ausgeführt. Bei dem Sprung zu resetProg wird SREG 
und der Stack nicht wieder rekonstruiert.

MfG Spess

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du startest nur Timer1, bei dessen ersten Überlauf wird dann Prog0 
ausgeführt (Timer 0 starten fürs Blinken). Und bei jedem weiteren 
Überlauf wird wieder Prog0 ausgeführt, weil am Ende jedes Überlaufs 
prog mit 0 geladen wird. Bei letzterem kann man schon fast "zum Glück" 
sagen, denn würde bei dem "inc prog" tatsächlich prog mal 2 werden, 
verabschiedet sich dein Programm ins Nirwana (weil dann das 
SREG-Zurückschreiben und Stack-Aufräumen gar nicht ausgeführt werden 
würde).

Autor: Roland M. (eroli)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Timer1_Overflow:
push temp        ; Sichern von "TEMP" im Stack
in   temp, SREG    ; Einlesen des SREG 
push temp        ; Schreiben von  SREG  im Stack (KOPIE)

cpi prog, 0b00000000
brne Prog1
  ;Prog0 ausfuehren:
  ldi temp, 0x00
  out PORTB, temp  ;LEDs jetzt aus
  out PORTD, temp
  ldi temp, 0b101 ;Timer0 starten mit Vorteiler 1:1024 (Teilt die Blinkfrequenz durch 1024)
  out TCCR0, temp
  rjmp ende
Prog1:
  cpi prog, 0b00000001
  brne ende
  ;Prog1 ausfuehren:
  ldi temp, 0b000 ;Timer0 beenden (Kein Blinken)
  out TCCR0, temp
  ldi temp, 0xFF
  out PORTB, temp  ;LEDs jetzt nur leuchten
  out PORTD, temp
  rjmp ende

ende:
  ldi temp, 0x00    ;Hier wird der Timer0 mit einem Startwert (z.B. 0) vorbelegt.
  out TCNT1L, temp  
  out TCNT1H, temp

  pop  temp      ; LESEN von SREG vom STACK (KOPIE)
  out  SREG, temp    ; Wiederherstellen von SREG
  pop  temp      ; Wiederherstellen von "TEMP" 

  inc prog      ; Kein "Programmüberlauf"
  cpi prog, 2      ; maximales Programm
  brge resetProg    ; "Programmüberlauf" --> prog = 0
resetProg:
  ldi prog, 0x00    ; Zuruecksetzen
reti

Ist es so besser?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Besser, aber immer noch nicht richtig. prog wird immer noch in jedem 
Interrupt wieder auf 0 gesetzt.

Autor: Roland M. (eroli)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wollte es noch editieren, aber da war es schon zu spät:
So sollte es nun aber doch funktionieren, oder?
Timer1_Overflow:
push temp        ; Sichern von "TEMP" im Stack
in   temp, SREG    ; Einlesen des SREG 
push temp        ; Schreiben von  SREG  im Stack (KOPIE)

cpi prog, 0b00000000
brne Prog1
  ;Prog0 ausfuehren:
  ldi temp, 0x00
  out PORTB, temp  ;LEDs jetzt aus
  out PORTD, temp
  ldi temp, 0b101 ;Timer0 starten mit Vorteiler 1:1024 (Teilt die Blinkfrequenz durch 1024)
  out TCCR0, temp
  rjmp ende
Prog1:
  cpi prog, 0b00000001
  brne ende
  ;Prog1 ausfuehren:
  ldi temp, 0b000 ;Timer0 beenden (Kein Blinken)
  out TCCR0, temp
  ldi temp, 0xFF
  out PORTB, temp  ;LEDs jetzt nur leuchten
  out PORTD, temp
  rjmp ende

ende:
  ldi temp, 0x00    ;Hier wird der Timer0 mit einem Startwert (z.B. 0) vorbelegt.
  out TCNT1L, temp  
  out TCNT1H, temp

  pop  temp      ; LESEN von SREG vom STACK (KOPIE)
  out  SREG, temp    ; Wiederherstellen von SREG
  pop  temp      ; Wiederherstellen von "TEMP" 

  inc prog      ; Kein "Programmüberlauf"
  cpi prog, 2      ; maximales Programm
  brge resetProg    ; "Programmüberlauf" --> prog = 0
  reti        ; Hier mögliches Ende
resetProg:
  ldi prog, 0x00    ; Zuruecksetzen
  reti

EDIT: Es Funktioniert wirklich :-)

Nochmal vielen Dank an alle helfenden Hände :-)

EDIT2:
Wie könnte ich denn ein weiterschalten zum nächsten Programm per Taster 
erzwingen? Kann ich bei einem Druck auf einen Taster einen TimerOverflow 
erzwingen?

Autor: Roland M. (eroli)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Nochmals Hallo zusammen,

kann mir vielleicht noch jemand verraten, wie man das Weiterschalten zum 
nächsten Programm per Taster zusätzlich auf die Reihe kriegt?

Außerdem wollte ich mein Programm um ein neues Blinprogramm erweitern, 
welches ich ebenfalls in Timer0 ausführen wollte. Bei diesem Programm 
sollen die LEDs der Reihe nach angehen...

Da ich immer noch nicht weiß, wie ich Interrupts debuggen kann (dort 
werden keine Breakpoints erreicht??), habe ich den Code testweise mal in 
die mainloop gepackt und dann debugged. Das Ergebnis war, dass das 
Programm am Ende immer auf RESET sprang und damit bei 0 anfing und das 
war natürlich falsch. Ich weiß jedoch nicht, woran das liegt?

Vielen Dank für eure Hilfe im vorraus,
Eroli

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Da ich immer noch nicht weiß, wie ich Interrupts debuggen kann (dort
>werden keine Breakpoints erreicht??),

Die werden schon erreicht. Das dauert nur sehr lange. Setze zum debuggen 
einfach die Prescaler der Timer auf 1.

>  ....
>  rjmp ende               <- unnötig
>ende:
>  ldi temp, 0x00          <- unnötig
>  out TCNT1L, temp        <- beim Overflow fängt der Timer
>  out TCNT1H, temp        <- wieder von Null an

Ändere den Teil:

>  pop  temp      ; LESEN von SREG vom STACK (KOPIE)
>  out  SREG, temp    ; Wiederherstellen von SREG
>  pop  temp      ; Wiederherstellen von "TEMP"

>  inc prog      ; Kein "Programmüberlauf"
>  cpi prog, 2      ; maximales Programm
>  brge resetProg    ; "Programmüberlauf" --> prog = 0
>  reti        ; Hier mögliches Ende
>resetProg:
>  ldi prog, 0x00    ; Zuruecksetzen
>  reti

mal in
  inc prog      ; Kein "r18rammüberlauf"
  cpi prog, 3      ; maximales r18ramm
  brcs resetr18    ; "r18rammüberlauf" --> r18 = 0
  clr prog          ; Zuruecksetzen
resetr18:
  pop  temp      ; LESEN von SREG vom STACK (KOPIE)
  out  SREG, temp    ; Wiederherstellen von SREG
  pop  temp      ; Wiederherstellen von "TEMP" 
  reti

um.

>ldi temp, 0b101
>out TCCR1B, temp

macht man besser so:

ldi temp,1<<CS12|1<<CS10
out TCCR1B, temp

Ich habe dein Programm nur mal überflogen. Das ist wahrscheinlich nicht 
alles.

MfG Spess

Autor: Roland M. (eroli)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Habe deine Vorschläge mal berücksichtigt, aber einige Fragen:

1) Warum wird der Stack im Timver1Overflow nur rekonstruiert, wenn ein 
"Programmüberlauf" stattfindet?

2) Zum Debuggen: In der Schaltung wird nach ca. 60 Sekunden das erste 
Mal das Programm gewechselt. Wenn ich den Debugger anschmeisse und in 
AVR Studio4 auf Debug-->Run gehe, wird dann nicht bis zum Erreichen 
eines Haltepunkts laufen gelassen oder wird das debuggen quasi beendet 
und nur noch ausgeführt?

Habe mit obiger Methode (Debug-->Run) schon ca. 10 Minuten darauf 
gewartet, dass ein Haltepunkt erreicht wird - ohne Erfolg.

Mit deinen Änderungen sehe ich folgendes Verhalten in meiner Schaltung: 
Erst leuchtet alles, so wie es soll und nach ca. 60 sekunden fangen sie 
zu blinken an, aber das machen sie dauerhaft. Das nächste Programm wird 
nicht mehr erreicht, aber es wird auch nicht mehr zum ersten Programm 
(dauerhaftes leuchten) zurückgeschaltet...

Irgendwie ist da der Wurm drin...

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>1) Warum wird der Stack im Timver1Overflow nur rekonstruiert, wenn ein
>"Programmüberlauf" stattfindet?

Das bezog sich auf das Programm von:

Beitrag "Re: ATmega8 Timer Problem"

>2) Zum Debuggen: In der Schaltung wird nach ca. 60 Sekunden das erste
>Mal das Programm gewechselt. Wenn ich den Debugger anschmeisse und in
>AVR Studio4 auf Debug-->Run gehe, wird dann nicht bis zum Erreichen
>eines Haltepunkts laufen gelassen oder wird das debuggen quasi beendet
>und nur noch ausgeführt?

So richtig verstehe ich die Frage nicht.
Ich gehe mal davon aus, das du mit 'Debugger' den Simulator meinst.

Mit Debug-->Run wird das Programm simuliert, bis ein Haltepunkt erreicht 
wird oder du den Ablauf mit 'Break' unterbrichst. Während 'Run' läuft 
werden keine Registeranzeigen aktualisiert. Die Simulation ist 
wesentlich langsamer als der reale AVR.
Wenn ich in deinem Programm die Prescaler der Timer von 1024 auf 1 
setze, kommen die Interrupts im Simulator im Sekundenrhythmus.

>Mit deinen Änderungen sehe ich folgendes Verhalten in meiner Schaltung:
>Erst leuchtet alles, so wie es soll und nach ca. 60 sekunden fangen sie
>zu blinken an, aber das machen sie dauerhaft. Das nächste Programm wird
>nicht mehr erreicht, aber es wird auch nicht mehr zum ersten Programm
>(dauerhaftes leuchten) zurückgeschaltet...

Ich hatte geschrieben

>Ich habe dein Programm nur mal überflogen. Das ist wahrscheinlich nicht
>alles.

Mit der Änderung werden erst mal alle drei 'Programme' im 
Timer1-Overflow abgearbeitet. Ob die jetzt richtig sind, kann ich dir im 
Moment auch nicht sagen.

MfG Spess

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Noch etwas: Könnte es sein, das du im Timer0_Overflow mit dem falschen 
wert für 'prg' arbeitest?
Du stellst im Timer1_Overflow ein bestimmtes Programm ein und änderst 
danach
die Programmnummer, auf die du im Timer0_Overflow wieder zugreifst.

MfG Spess

Autor: Roland M. (eroli)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

habe gestern nochmals meine Konzentration zusammengenommen und einige 
Stunden experimentiert. Dabei ist mir aufgefallen, dass da an vielen 
Stellen noch einiges ziemlich schief lief. Ich habe nach und nach alle 
Fehler ausgemerzt (und andere auch nochmal eingebaut :-D), aber nach 7 
Stunden Arbeit funktioniert mein Programm erstmal :-)

Vielen Dank an die geduldigen Helfer und die Denkanstöße :-)

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Kleiner Vorschlag:

wenn du für dein Blinkprogramm die Ports gleich im Timer1_Overflow 
inialisierst, kannst du den Teil:


>blinken:
>  sbic PORTB, 0    ;Nächsten Befehl überspringen, falls Bit0 abm PortB ist >
>    rjmp led_ein  ;Ansonsten LED einschalten (s. unten).
>  sbis PORTB,0    ;Überspringen, falls Bit0 abm PortB ist EIN (= LED ist
>    rjmp led_aus  ;Ansonsten LED ausschalten (s. unten).

>  led_ein:    ;Zum Einschalten:
>    ldi temp, 0x00
>    out PORTB, temp
>    out PORTD, temp
>    rjmp end  ;und beenden.
>  led_aus:    ;Zum Ausschalten:
>    ldi temp, 0xFF
>    out PORTB, temp
>    out PORTD, temp
>    rjmp end

auf
    ldi temp1,$FF
    in temp, PORTB
    eor temp,temp1
    out PORTB, temp
    out PORTD, temp
    rjmp end
eindampfen.

>Ich habe nach und nach alle Fehler ausgemerzt ...

Und was ist das?

>cpi prog, 3
>breq aufsteigend

Deine Programmnummer gehen doch nur von 0..2.

MfG Spess

Autor: Roland M. (eroli)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke,
werde das noch verkürzen.

>>cpi prog, 3
>>breq aufsteigend
>
>Deine Programmnummer gehen doch nur von 0..2.

Die Programmnummern sind im Timer0 um eins höher, da sie am Ende von 
Timer1 ja schon erhöht werden. Ist etwas tricky, aber wenn man es weiß, 
dann klappt es ganz gut ;-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.