Forum: Mikrocontroller und Digitale Elektronik Problem mit AtMega8: Wert aus Interrupt zurückgeben :-(


von Walter Pr. (Gast)


Lesenswert?

Hallo Freunde,
mann - ich weiß gar nicht mehr wieviele TAGE ich mit diesem Problem 
schon verbringe, bitte um Hilfe!? Ich habe schon ein großes Programm 
(Infrarotumwandler) laufen, alles läuft super.

- ich starte einen Timer0 und dieser wird nach 2 Sekunden beendet > OK

- ich möchte den Wert "timerstatus" 1 zurückgeben, um es im 
Hauptprogramm auszuwerten > geht nicht!


Codeschnipsel:
1
---------INTERRUPTROUTINE
2
3
OVF0_addr:        ; Timer0 Overflow Handler
4
5
push    temp1               ; temp 1 sichern
6
in      temp1,sreg          ; SREG sichern
7
push    temp1
8
 
9
inc     timercount          ; zu 28. zählen (~ 2 Sekunden)
10
11
ldi   temp1,28    
12
cpse   timercount,temp1    ; überspringe, "timercount" gleich 28    rjmp   end_OVF0 
13
14
; Überlauf 28 erreicht
15
    
16
ldi     temp1, (0<<TOIE0)   ; TOIE0: Interrupt bei Timer Overflow
17
out     TIMSK, temp1  ; Timer0 wieder ausschalten
18
19
sbi PORTB,1    ;portB bit1 setzen (1: led an 5v ist an)
20
rcall pause500ms
21
cbi PORTB,1       ;led aus
22
23
ldi     temp1,1                 
24
sts     timerstatus, temp1     ;timerstatus auf 1 setzen  
25
        
26
end_OVF0:
27
 
28
pop     temp1
29
out     sreg,temp1          ; sreg wieder herstellen
30
pop     temp1
31
reti                        ; das wars. Interrupt ist fertig
32
33
--------- HAUPTPROGRAMM
34
35
lds     temp,timerstatus
36
cpi     temp,0                ; Werte gleich?
37
breq  merker_abfrage        ; ja: springe zu ...
38
rjmp  timer0ueberlauf       ; nein: springe zu ...

Und hier liegt das Problem, das Programm springt nie zu "timerueberlauf 
:-(. Habe meiner Meinung nach schon alle Variationen getestet (aktuell 
im Beispiel mittels SRAM, ich hab aber schon alle möglich Register und 
ähnliche getestet!!), "timerstatus" funktioniert nicht.


Bitte um Hilfe, wie macht man das richtig?

Grüße, Walter

von Krapao (Gast)


Lesenswert?

> rjmp  timer0ueberlauf       ; nein: springe zu ...

Das Label timer0ueberlauf gibt es in deinem Codeschnippsel nicht; 
viele andere (merker_abfrage) übrigens auch nicht.

Damit das rjmp ausgeführt wird muss timerstatus ungleich 0 werden. 
Dazu muss die ISR OVF0_addr ausgeführt werden.

Ich sehe in HAUPTPROGRAMM nicht, wie das geschehen soll: Weit und breit 
keine Initialisierung von Timer0 inkl. sei zu sehen.

von spess53 (Gast)


Lesenswert?

Hi

Hänge mal dein komplettes Programm an. In dem Schnipsel kann ich auf den 
ersten Blick, außer teilweise etwas umständlicher Programmierung keinen 
wirklichen Fehler entdecken.

MfG Spess

von Krapao (Gast)


Lesenswert?

> cpse   timercount,temp1    ; überspringe, "timercount" gleich 28    rjmp 
end_OVF0

Beachte, wo die rjmp ... Anweisung steht - im Kommentar

von Krapao (Gast)


Lesenswert?

Dieses Minimalbeispiel arbeitet IMHO richtig:

1
.include "m8def.inc"
2
 
3
.def temp = r16
4
.def temp1 = r17
5
.def timercount = r18
6
7
  .DSEG                 ; Umschalten auf das SRAM Datensegment
8
timerstatus:   .BYTE  1 ; 1 Byte unter dem Namen 'timerstatus' reservieren
9
10
  .CSEG                 ; Umschalten auf das FLASH Codesegment
11
.org 0
12
  rjmp reset
13
14
.org OVF0addr
15
  rjmp Timer0_OVF_ISR
16
17
reset:
18
; Stack einrichten
19
  ldi temp, HIGH(RAMEND)
20
  out SPH, temp
21
  ldi temp, LOW(RAMEND)
22
  out SPL, temp
23
; Daten initialisieren
24
  ldi  temp1,0                 
25
  sts  timerstatus, temp1 ; timerstatus auf 1 setzen  
26
; Timer 0 einrichten
27
  ldi temp1, (1<<CS02) | (1<<CS00) ; Teiler 1024
28
  out TCCR0, temp1
29
  ldi temp1, (1<<TOIE0)
30
  out TIMSK, temp1
31
  sei
32
; --------- HAUPTPROGRAMM
33
loop:
34
  lds  temp,timerstatus
35
  cpi  temp,0                ; Werte gleich?
36
  breq merker_abfrage        ; ja: springe zu ...
37
  rjmp timer0ueberlauf       ; nein: springe zu ...
38
39
merker_abfrage:
40
  nop
41
  rjmp loop
42
43
timer0ueberlauf:
44
  nop
45
  rjmp loop
46
47
pause500ms:
48
  ; so lange will man im Simulator nicht warten :-)
49
  ret
50
51
; --------- ISR
52
Timer0_OVF_ISR:
53
  push temp1
54
  in   temp1,SREG
55
  push temp1
56
  inc  timercount         ; zu 28. zählen (~ 2 Sekunden)
57
  ldi  temp1,28    
58
  cpse timercount,temp1   ; überspringe, "timercount" gleich 28    
59
  rjmp end_OVF0 
60
  ; Überlauf 28 erreicht
61
  ldi  temp1, (0<<TOIE0)  ; TOIE0: Interrupt bei Timer Overflow
62
  out  TIMSK, temp1       ; Timer0 wieder ausschalten
63
  sbi  PORTB,1            ; PortB Bit1 setzen (1: led an 5v ist an)
64
  rcall pause500ms
65
  cbi  PORTB,1            ; led aus
66
  ldi  temp1,1                 
67
  sts  timerstatus, temp1 ; timerstatus auf 1 setzen  
68
end_OVF0:
69
  pop  temp1
70
  out  SREG,temp1         ; sreg wieder herstellen
71
  pop  temp1
72
  reti                    ; das wars. Interrupt ist fertig

von Krapao (Gast)


Lesenswert?

Mist, Copy & Paste...

>  ldi  temp1,0
>  sts  timerstatus, temp1 ; timerstatus auf 1 setzen

Soll natürlich

>  ldi  temp1,0
>  sts  timerstatus, temp1 ; timerstatus auf 0 setzen

heissen.

von Walter Pr. (Gast)


Angehängte Dateien:

Lesenswert?

danke an alle vorerst, ich hab mal etwas mehr Code angehängt (stark 
gekürzt)! Der 2 Sekunden-Timer funktionierte immer, das sehe ich am 
kurzen LED blinken am Start und nach 2 Sekunden.

Einige Zeilen hat mir vorhin leider das Texteinfügen hier im Beitrag 
"verschandelt". @Krapao: ich check das gleich mal...


Danke

von Walter Pr. (Gast)


Lesenswert?

hmmm... hab noch keine Lösung gefunden, zweifle stark an mir selbst 
;-)...


".equ rFlg=0   ; Flaggenregister zur Kommunikation"
gehört raus, das ist von früheren Versuchen !

Meine aktuelle Not-Idee: in der Interruptroutine einen Port setzen und 
im Hauptprogramm abfragen??


Danke, Walter

von Daniel (Gast)


Lesenswert?

Ich kenn zwar kein Assembler, aber ich könnte mir gut vorstellen, dass 
dir das Stichwort "volatile" weiterhelfen wird.

Grüße

Daniel

von spess53 (Gast)


Lesenswert?

Hi

>Ich kenn zwar kein Assembler, aber ich könnte mir gut vorstellen, dass
>dir das Stichwort "volatile" weiterhelfen wird.

Nein. Das ist dem Assembler unbekannt.

MfG Spess

von Walter Pr. (Gast)


Lesenswert?

Mit dem Begriff "volatile" hab ich auch schon einen Abend verbracht, 
aber es war nichts Vergleichbares für Assembler zu finden (die Register 
irgendwie global zu definieren)...

Ich versteh's einfach nicht: wenn ich der ISR z.B. "status = 1" 
definiere, warum ich im Hauptprogramm dann keinen Sprung daraus ableiten 
kann???

Verändert das "reti" irgendwas an den Registern?


Walter

von Krapao (Gast)


Lesenswert?

1
;timer0ueberlauf Abfrage
2
3
  lds     temp,timerstatus
4
  cpi     temp,0                ; Werte gleich?
5
        breq  merker_abfrage      ; ja: springe zu ...
6
  rjmp  timer0ueberlauf       ; nein: springe zu ...
7
        
8
9
merker_abfrage:
10
11
####### unwichtiges entfernt/gekürzt ##########
12
13
14
15
;**********  ir-befehle auswerten *****************************************
16
17
18
;läuft timer?  in Sonderfällen stoppen >>>>> funktioniert
19
  
20
  rcall timer0stoppen    ;timer für Farbe läuft noch, Farbtaste abbrechen und neue auswerten

Du stoppst bei JEDEM Durchlauf von merker_abfrage den Timer0! Der Timer 
läuft nur äußerst kurz!

Beim nächsten Einschalten läuft er nochmal ein Stückchen, weil TCNT0 nur 
vom Überlauf selbst gelöscht wird. So hangelt sich der Timer sich immer 
weiter vor.

von Krapao (Gast)


Angehängte Dateien:

Lesenswert?

ICh denke, es liegt ein Logikproblem vor und dazu muss man wissen, was 
es mit den Kommandos merker, satgelb, command D4 und satgelblang auf 
sich hat bzw. was wann passieren soll.

Zur leichteren Simulation und zum besseren Überblick habe ich die Source 
leicht verändert und Angaben eingefügt, wo Breakpoints hin kommen können 
(Anhang).

von Walter Pr. (Gast)


Lesenswert?

DANKE - ich hab selbst gelöst (nach geschätzten mehr als 20 Stunden 
herumprobieren)!!!!

Besonderer Danke an Krapao, der sich wirklich hineingefühlt hat. Ich 
glaub durch meinen Forumspost stieg meine Lust zum Denken wieder an ;-).

@Krapao: ok, das sah jetzt im Code so aus, aber in Wirklichkeit kam das 
Programm nur an diese Stelle "rcall timer0stoppen", wenns auch gewünscht 
war.


Mein Programm hat nämlich 2099 Textzeilen (schlecht programmiert, aber 
funktioniert ;-) ), das wollte ich niemand zumuten.


Wo lag der Fehler?:

- ich hab als letzte Möglichkeit den Weg über Port setzen und abfragen 
getestet > auch kein Erfolg.

- plötzlich kam nach einem zufälligen Tastendruck ca. 7 Sekunden 
später reproduzierbar der gewünschte Sprung !!

- die Analyse ergab, mein Programm kam nach dem "RETI" nicht wie geplant 
regelmässig zur "detect_start" zurück, sondern hing ca. 30 Zeilen 
entfernt in einer "detect_start2" Schleife fest und wartete auf ein 
Fernbedienungssignal... :-P


DANKE nochmal für die Gedankenanstösse - Walter

von Krapao (Gast)


Lesenswert?

Das ist oft so. Durch die Beschreibung des Problems kommen einem meist 
Ideen, die man zur Lösung brauchen kann.

von Walter Pr. (Gast)


Lesenswert?

@Krapao:
stimmt, ich sollte mein Programm optimieren und den ganzen Code (naja, 
es funktioniert auch so und im Mega8 ist noch Platz genug für 
umständliche Programmierung) strukturieren.
Aber danke, dein Code wird mich zum Optimieren anregen...

Mein Programm empfängt und sendet Fernbedienungssignale, das finde ich 
etwas schwer zu simulieren. Wegen des kritischen Timings.

Ok, ich hab Hilfe im Forum gesucht, wollte aber meinen Code nicht 
einfach öffentlich machen, weil doch schon jahrelange Arbeit drinsteckt! 
Natürlich ist mit einem kleinem Bruchteil des Codes alles schwer zu 
verstehen.

LG.

von Walter S. (avatar)


Lesenswert?

Walter Pr. schrieb:
> Ok, ich hab Hilfe im Forum gesucht, wollte aber meinen Code nicht
> einfach öffentlich machen, weil doch schon jahrelange Arbeit drinsteckt!

zum einen hätte mein Deutschlehrer da "Logik?" an den Rand geschrieben, 
zum anderen wenn du schon selbst schreibst

Walter Pr. schrieb:
> umständliche Programmierung

brauchst du nicht befürchten, dass dir da jemand was wegnimmt

von Karl H. (kbuchegg)


Lesenswert?

Walter Pr. schrieb:
> @Krapao:
> stimmt, ich sollte mein Programm optimieren und den ganzen Code (naja,
> es funktioniert auch so und im Mega8 ist noch Platz genug für
> umständliche Programmierung) strukturieren.
> Aber danke, dein Code wird mich zum Optimieren anregen...

Nein, du sollst ihn nicht optimieren (zumindest jetzt noch nicht).
Du sollst ihn in erster Linie verständlich machen!

Und erst dann, wenn du dann feststellst, dass du
* zu langsam bist
* rausbekommen hast, wo die Rechenzeit draufgeht
erst dann beginnt man mit Optimierung, mit dem Feintuning. Wobei man 
auch da zuerst einmal nachsieht, ob man auf Algorithmenebene etwas 
erreichen kann.

> Ok, ich hab Hilfe im Forum gesucht, wollte aber meinen Code nicht
> einfach öffentlich machen, weil doch schon jahrelange Arbeit drinsteckt!

Dann hast du jetzt am eigenen Leib erfahren, dass es wichtig ist, dass 
Code in erster Linie verständlich und nachvollziehbar ist. Das ist die 
oberste Prämisse, denn nach einigen Monaten/Jahren hat man die Details 
der veranstalteten Schweinerein schon längst vergessen.

Code ist nie fertig. In jedem realen Code, abseits von Micky-Mouse 
Lehrbuchbeispielen, gibt es immer wieder Dinge, die man besser, 
verständlicher, übersichtlicher ausdrücken kann. Und sei es nur, dass 
man durch die Code-Formatierung und zwischenschieben von 
Blockkommentaren wieder einen Schritt in Richtung 'Verbesserung' macht.
Es gibt 2 Sorten von Programmierern:
* die einen, die dauern jammern, dass ihr Code so unübersichtlich ist,
  dass sie sich nicht mehr auskennen, dass sie den Überblick verloren
  haben und die nichts dagegen tun. Das sind auch die Programmierer,
  die sich sagen: Ich hab jetzt Stunden damit verbracht, das irgendwie
  zum laufen zu bekommen (ich weiß zwar nicht genau wie, interessiert
  mich auch nicht), aber ich rühr das jetzt auf keinen Fall mehr an.
  Das sind meistens die, die die tollsten Fehler in ihren Programmen
  haben
* und es gibt diejenigen, die auch schon mal ein paar Stunden nur
  zur Codepflege investieren.
  Die haben zwar auch ab und an mal Fehler im Programm, aber die
  sind meistens von der Art, dass es sich einfach nur um leicht
  zu behebende Irrtümer oder Tippfehler handelt oder aber die sich
  durch etwas andere Codestrukturierung beheben lassen. Die generelle
  Codestruktur ist aber in Ordnung, so dass sich Fehler meistens nur
  lokal auswirken.

PS: die erste Sorte der Programmierer erkennt man zb auch daran, dass 
sie 'Variablennamen' benutzen, die entweder kein Mensch versteht (weil 
bis zur Unkenntlichkeit verstümmelt abgekürzt) oder aber die so banal 
sind, dass sie komplett nichtssagend sind. Wie zb Test1, Test2, Test3, 
Merker1, Merker2, etc.

von Peter D. (peda)


Lesenswert?

Walter Pr. schrieb:
> ich sollte mein Programm optimieren und den ganzen Code (naja,
> es funktioniert auch so und im Mega8 ist noch Platz genug für
> umständliche Programmierung) strukturieren.

Der Punkt ist nicht, daß der Flash knapp wird, sondern daß Du damit 
Deine eigene Zeit vergeudest.
Du brauchst viel Zeit, um den Code später selber wieder verstehen zu 
können. Und nochmehr Zeit, um in dem Wust Fehler zu suchen oder 
Erweiterungen vorzunehmen.

Übersichtlich und modular zu programmieren braucht zu Anfang etwas mehr 
Zeit, die man aber in der späteren Projektphase 100-fach wieder 
reinholt.

Walter Pr. schrieb:
> Mein Programm empfängt und sendet Fernbedienungssignale, das finde ich
> etwas schwer zu simulieren. Wegen des kritischen Timings.

FBs haben nur sehr kleine Datenraten, da sollte kein Timing kritisch 
sein.
Vermutlich ist nur der Programmablaufplan schlecht erstellt oder 
garnicht existent.


Walter S. schrieb:
> Walter Pr. schrieb:
>> umständliche Programmierung
>
> brauchst du nicht befürchten, dass dir da jemand was wegnimmt

Stimmt, schlechter Code ist der beste Kopierschutz.


Peter

von Walter Pr. (Gast)


Lesenswert?

>>> umständliche Programmierung
>> brauchst du nicht befürchten, dass dir da jemand was wegnimmt

>Stimmt, schlechter Code ist der beste Kopierschutz.

haha, mag sein. Trotzdem weiss ich, dass einige Leute gerne die fertige 
HEX-Datei hätten ;-).


Danke nochmal für die Hilfe und den netten Umgangston hier im Forum,
Walter


PS: der Timer läuft zwar jetzt soweit, nur irgendwie steckt nun woanders 
der Hund drinnen - aber ok, ich such erst mal selbst den Fehler und erst 
wenns nicht mehr weiter geht, meld ich mich wieder...

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.