Forum: Mikrocontroller und Digitale Elektronik ATmega8 Timer Problem


von Roland N. (eroli)


Angehängte Dateien:

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

von Stefan E. (sternst)


Lesenswert?

1
ldi temp,  1<<TOIE0  ;Ein INT auslösen,
2
out TIMSK, temp    ;falls ein TC0-Überlauf-Interrupt auftritt.
3
...
4
ldi temp, 1 << TOIE1  ;Timer1-Overflow-Interrupt aktivieren...
5
out TIMSK, temp        ; ... und setzen

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

von Roland N. (eroli)


Angehängte Dateien:

Lesenswert?

Hallo,

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

Habe das nun so umformuliert:
1
ldi temp, 0b00000101  ; Timer0-Overflow und Timer1-Overflow "erlauben"
2
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?

von spess53 (Gast)


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

von Stefan E. (sternst)


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).

von Roland N. (eroli)


Lesenswert?

1
Timer1_Overflow:
2
push temp        ; Sichern von "TEMP" im Stack
3
in   temp, SREG    ; Einlesen des SREG 
4
push temp        ; Schreiben von  SREG  im Stack (KOPIE)
5
6
cpi prog, 0b00000000
7
brne Prog1
8
  ;Prog0 ausfuehren:
9
  ldi temp, 0x00
10
  out PORTB, temp  ;LEDs jetzt aus
11
  out PORTD, temp
12
  ldi temp, 0b101 ;Timer0 starten mit Vorteiler 1:1024 (Teilt die Blinkfrequenz durch 1024)
13
  out TCCR0, temp
14
  rjmp ende
15
Prog1:
16
  cpi prog, 0b00000001
17
  brne ende
18
  ;Prog1 ausfuehren:
19
  ldi temp, 0b000 ;Timer0 beenden (Kein Blinken)
20
  out TCCR0, temp
21
  ldi temp, 0xFF
22
  out PORTB, temp  ;LEDs jetzt nur leuchten
23
  out PORTD, temp
24
  rjmp ende
25
26
ende:
27
  ldi temp, 0x00    ;Hier wird der Timer0 mit einem Startwert (z.B. 0) vorbelegt.
28
  out TCNT1L, temp  
29
  out TCNT1H, temp
30
31
  pop  temp      ; LESEN von SREG vom STACK (KOPIE)
32
  out  SREG, temp    ; Wiederherstellen von SREG
33
  pop  temp      ; Wiederherstellen von "TEMP" 
34
35
  inc prog      ; Kein "Programmüberlauf"
36
  cpi prog, 2      ; maximales Programm
37
  brge resetProg    ; "Programmüberlauf" --> prog = 0
38
resetProg:
39
  ldi prog, 0x00    ; Zuruecksetzen
40
reti

Ist es so besser?

von Stefan E. (sternst)


Lesenswert?

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

von Roland N. (eroli)


Lesenswert?

Wollte es noch editieren, aber da war es schon zu spät:
So sollte es nun aber doch funktionieren, oder?
1
Timer1_Overflow:
2
push temp        ; Sichern von "TEMP" im Stack
3
in   temp, SREG    ; Einlesen des SREG 
4
push temp        ; Schreiben von  SREG  im Stack (KOPIE)
5
6
cpi prog, 0b00000000
7
brne Prog1
8
  ;Prog0 ausfuehren:
9
  ldi temp, 0x00
10
  out PORTB, temp  ;LEDs jetzt aus
11
  out PORTD, temp
12
  ldi temp, 0b101 ;Timer0 starten mit Vorteiler 1:1024 (Teilt die Blinkfrequenz durch 1024)
13
  out TCCR0, temp
14
  rjmp ende
15
Prog1:
16
  cpi prog, 0b00000001
17
  brne ende
18
  ;Prog1 ausfuehren:
19
  ldi temp, 0b000 ;Timer0 beenden (Kein Blinken)
20
  out TCCR0, temp
21
  ldi temp, 0xFF
22
  out PORTB, temp  ;LEDs jetzt nur leuchten
23
  out PORTD, temp
24
  rjmp ende
25
26
ende:
27
  ldi temp, 0x00    ;Hier wird der Timer0 mit einem Startwert (z.B. 0) vorbelegt.
28
  out TCNT1L, temp  
29
  out TCNT1H, temp
30
31
  pop  temp      ; LESEN von SREG vom STACK (KOPIE)
32
  out  SREG, temp    ; Wiederherstellen von SREG
33
  pop  temp      ; Wiederherstellen von "TEMP" 
34
35
  inc prog      ; Kein "Programmüberlauf"
36
  cpi prog, 2      ; maximales Programm
37
  brge resetProg    ; "Programmüberlauf" --> prog = 0
38
  reti        ; Hier mögliches Ende
39
resetProg:
40
  ldi prog, 0x00    ; Zuruecksetzen
41
  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?

von Roland N. (eroli)


Angehängte Dateien:

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

von spess53 (Gast)


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
1
  inc prog      ; Kein "r18rammüberlauf"
2
  cpi prog, 3      ; maximales r18ramm
3
  brcs resetr18    ; "r18rammüberlauf" --> r18 = 0
4
  clr prog          ; Zuruecksetzen
5
resetr18:
6
  pop  temp      ; LESEN von SREG vom STACK (KOPIE)
7
  out  SREG, temp    ; Wiederherstellen von SREG
8
  pop  temp      ; Wiederherstellen von "TEMP" 
9
  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

von Roland N. (eroli)


Angehängte Dateien:

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...

von spess53 (Gast)


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

von spess53 (Gast)


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

von Roland N. (eroli)


Angehängte Dateien:

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 :-)

von spess53 (Gast)


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
1
    ldi temp1,$FF
2
    in temp, PORTB
3
    eor temp,temp1
4
    out PORTB, temp
5
    out PORTD, temp
6
    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

von Roland N. (eroli)


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 ;-)

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.