Hallo!
Ich programmiere einen Atmega 168 in Assembler. Meine Elektronik besteht
aus einem LCD display, Drehimpulsgeber, Ausgangs- und Eingangsregister
usw.
Ich lasse in einer Schleife dauernd Daten auf dem LCD anzeigen (schreibe
alles ins DDRAM vom LCD).
Hat ja alles wunderbar geklappt. Brauchte jetzt aber einen Timer1
Interrupt, da ich für Berechnungen einen genauen Zeitwert(5s) brauche.
Seitdem ich mit dem Timer1 interrupt arbeite, zeigt das LCD nach ca. 3s
in einer Zeile den Wert den ich anzeigen lasse versetzt um 3 Kästchen
nochmal was nicht sein sollte.
Also im Grunde zeigt es Blödsinn an. Ich nehme an da der Interrupt
irgendwann unterbricht gibt es beim LCD Probleme und er zeigt manche
sachen falsch an?
PS: LCD ist nicht zeitkritisch. ALso es würde auch ausreichen alle 2
sekunden zu aktualisieren ( Bis auf den Drehimpulsgeber, den muss ich so
schnell als möglich aktualisieren)
Bin dankbar um Hilfe.
Liebe Grüße
Luke
Luke schrieb:> Also im Grunde zeigt es Blödsinn an. Ich nehme an da der Interrupt> irgendwann unterbricht gibt es beim LCD Probleme und er zeigt manche> sachen falsch an?
Nö.
Die Ansteuerung eines LCD ist insofern nicht zeitkritisch, als ein
Interrupt an jeder Stelle unterbrechen darf, sofern er
* das SREG sichert und wieder herstellt
* nichts an den restlichen gebrauchten Registern verändert
D.h. wenn die ISR sauber programmiert ist, und der CPU Zustand nach der
ISR exakt demjenigen vor Aufruf der ISR entspricht, dann gibt es auch
keine Probleme. Denn: die ANsteuerung ist insofern nicht zeitkritisch,
als alle Vorgänge zwar eine UNtergrenze für einzuhaltende Zeiten haben,
aber keine Obergrenze. Wenn sich der Aufruf der ISR also nur dadurch
bemerkbar macht, dass zwischen 2 Befehlen in der LCD Ausgabe etwas mehr
Zeit vergeht als gewöhnlich, dann ist das überhaupt kein Problem. Aber:
Das darf auch nur die einzige Art und Weise sein, wie sich der ISR
Aufruf an dieser Stelle bemerkbar macht! Alle restlichen gebrauchten
Register MÜSSEN ihre Werte behalten!
> Bin dankbar um Hilfe.
Dein Programm?
Aber ehe du es postest: Überprüf mal, ob deine ISR insbesondere das SREG
sichert und wiederherstellt, bzw. alle Register, die auch in den LCD
Routinen benutzt werden. WEnn du dir nicht sicher bist, dann sichere in
der ISR ALLE benutzten Register und stell sie am Ende der ISR wieder
her. So bist du erst mal auf der sicheren Seite, auch wenn du unter
Umständen etwas Zeit verbrutzelst.
Danke für die schnelle Antwort!
Also habe jetzt meine ganzen Arbeitsregister in der ISR gesichert.
Ich hab in meinem Programm jedoch sehr viele Speicherregister die sich
im dseg befinden um alle möglichen Werte abzuspeichern. Müssen diese
Register ebenfalls abgespeichert werden?
Ich denke nur die Arbeitsregister?!
Hab ebenfalls viele Strings, die ich dann in der LCD schleife aufrufe.
Habe aber dasselbe Problem schonmal gehabt, dass mir das LCD versetzt
Blödsinn anzeigt (da war die ISR noch nicht aktiv) und da ist mir
aufgefallen dass ich in jedem Schleifendurchlauf den Cursor vom LCD
ausschalte. Habe dies dann nur einmal in der Initialisierung des LCD
gmacht und dann war es weg.
Kanns da noch immer ein Problem geben?
LG
Das sind die Programmausschnitte vom Timer1 interrupt den ich verwende.
Ist hier ein Fehler erkennbar?
Interrupt funktioniert ja super nur eben macht dann das LCD was es will.
.cseg
.org 0x0000
rjmp init
.org OVF1addr
jmp timer1_overflow
Timer1_init:
ldi temp,0b00000000
sts TCCR1A,temp
ldi temp,0b00000010
sts TCCR1B,temp
ldi temp,0b00000001
sts TIMSK1,temp
ret
timer1_overflow:
push temp
push temp3
push temp2
push temp1 ; temp 1 sichern
in temp1,sreg ; SREG sichern
call Berechnung
out sreg,temp1 ; sreg wieder herstellen
pop temp1
pop temp
pop temp3
pop temp2
reti
Luke schrieb:> timer1_overflow:> push temp> push temp3> push temp2> push temp1 ; temp 1 sichern>> in temp1,sreg ; SREG sichern>>> call Berechnung>>> out sreg,temp1 ; sreg wieder herstellen> pop temp1> pop temp> pop temp3> pop temp2
Vergleich mal die Reihenfolgen :-)
Die müssen schon sauber ineinander geschachtelt sein, so dass die pop
die exakte Umkehrung der push sind!
push temp <----------------+
push temp1 <-------------+ |
| |
... | |
| |
pop temp1 <-------------+ |
pop temp <----------------+
hast du hier eine Verdrehung, dann vertauscht du effektiv die Inhalte
der Register bei einem ISR-Aufruf.
Ein Stack ist wie ein Stapel Teller. Den Teller den du als letztes
drauflegst, den kriegst du auch als erstes wieder.
push X heißt Inhalt vom Teller X auf den Stack oben drauf
pop X heißt obersten Inhalt vom Stack auf den Teller X legen
Da sucht sich keiner zusammen, wie die korrekte Reihenfolge sein muss.
Das musst schon du machen!
aber nur, wenn innerhalb von 'Berechnung' das temp1 nicht verändert
wurde. Wird es das, dann schreibst du irgendwas nach SREG zurück, aber
sicher nicht den Wert, den du dir vor dem call Berechnung in temp1
'gesichert' hast.
Luke schrieb:> Ich nehme an da der Interrupt> irgendwann unterbricht gibt es beim LCD Probleme und er zeigt manche> sachen falsch an?
Nur wenn der Interrupt auch auf das LCD ausgibt. Das geht schief. Das
LCD ist nicht reentrant.
Luke schrieb:> ldi temp,0b00000000> sts TCCR1A,temp>> ldi temp,0b00000010> sts TCCR1B,temp>> ldi temp,0b00000001> sts TIMSK1,temp
Was mir noch auffällt, m.E. ist "out" der richtige Befehl, um
I/O-Register zu beschreiben und nicht "sts".
Icke ®. schrieb:> Luke schrieb:>> ldi temp,0b00000000>> sts TCCR1A,temp>>>> ldi temp,0b00000010>> sts TCCR1B,temp>>>> ldi temp,0b00000001>> sts TIMSK1,temp>> Was mir noch auffällt, m.E. ist "out" der richtige Befehl, um> I/O-Register zu beschreiben und nicht "sts".
Stimmt schon so wie er's hat.
Beim Mega168 sind diese Register per OUT nicht erreichbar.
Icke ®. schrieb:> Karl Heinz Buchegger schrieb:>> Stimmt schon so wie er's hat.>> Beim Mega168 sind diese Register per OUT nicht erreichbar.>> Aha, wieder was gelernt.
:-)
Ist einer der Gründe, warum ich reale Programme nicht in Assembler
schreibe. Das ist mir zu mühsam, mich immer daran zu erinnern bzw.
nachzuschlagen, bei welchem Prozessor ein OUT sein muss und bei welchem
ein STS. Das kann der Compiler viel zuverlässiger.
Karl Heinz Buchegger schrieb:> in temp1,sreg ; SREG sichern>>> call Berechnung>>> out sreg,temp1 ; sreg wieder herstellen>> aber nur, wenn innerhalb von 'Berechnung' das temp1 nicht verändert> wurde. Wird es das, dann schreibst du irgendwas nach SREG zurück, aber> sicher nicht den Wert, den du dir vor dem call Berechnung in temp1> 'gesichert' hast.
Ja das stimmt hab das schon vor push und nach pop geschrieben. Hab den
Fehler schon eingrenzen können. Das Problem dürfte irgendwo in meiner
Berechnung liegen. Schalte ich diese weg, dann gibt es kein Problem.
Muss mir jez anschaun was ich da für einen Käse programmiert hab gg
Danke für die vielen Antworten!
LG
Luke schrieb:> Das Problem dürfte irgendwo in meiner> Berechnung liegen.
Ja, das ist schon fast unheimlich. Zu 99% wird bei Codeausschnitten
immer nur der Teil gepostet, an dem es nicht (allein) liegt.
Auch scheint eine geradezu krankhafte Furcht zu bestehen, den Forum Host
zu überlasten. Dabei wäre es doch das aller einfachste, den
vollständigen Code als Anhang (Zip bei mehreren Dateien) zu senden.
Karl Heinz Buchegger schrieb:> Ist einer der Gründe, warum ich reale Programme nicht in Assembler> schreibe.
Ja, ich stoße mittlerweile auch an die Grenzen der Fußlatscherei und
werde mich wohl oder übel mit C anfreunden müssen. Die Syntax ist zwar
gräßlich, aber vieles wird leichter zu erledigen sein.