Hallo,
ich programmiere normalerweise in Bascom muss aber diesmal etwas in
Assembler machen was komplettes Neuland für mich ist.
Im Anhang ist eine Datei in der ich mich versucht habe die beiden Timer
des Atmega32 (Timer0 und Timer1 zu aktivieren), Timer0 soll 10000mal pro
sek einen Interrupt auslösen und Timer1 2mal pro sek. Kann da vielleicht
mal einer drüberschauen und mir sagen was ich da falsch mache, hab mich
auch schon über Timer in Assembler eingelesen aber so wirklich hab ich
das nicht verstanden. Timer0 macht so halbwegs was er soll aber Timer1
noch nicht so richtig und beide zusammen tuns auch noch nicht so
richtig.
Wäre dankbar über eure Hilfe!
Vielleicht kann mir ja jemand bei dem Code helfen.
Danke
schöne Grüße.
danny_v1 schrieb:> Sorry wenn ich hier im falschen Forum gepostet haben sollte.>> Wo müssten die "pop" denn hin???
Die Frage sollte sich eigentlich von selbst beantworten, wenn du weißt,
warum das push da stehen muß.
OK,
ich würde mal schätzen das die ans Ende des Interrupt gehören, bin mir
aber nicht sicher.
Aber das kann ja eigentlich noch nicht der ganze Fehler sein.
danny_v1 schrieb:> ich würde mal schätzen das die ans Ende des Interrupt gehören, bin mir> aber nicht sicher.
unter der Bedingung, dass "pop" das Gegenstück zu "push" ist, solltest
du dir mal angucken, was dein Push macht und dann überlegen, was pop
machen müsste.
Soweit ich das verstanden habe sichere ich mit dem push, mein Register
(temp) und mit dem pop geb ich den wert wieder auf das Register temp
zurück, oder?
danny_v1 schrieb:> OK,>> ich würde mal schätzen das die ans Ende des Interrupt gehören, bin mir> aber nicht sicher.
Richtig.
> Aber das kann ja eigentlich noch nicht der ganze Fehler sein.
Warum nicht? Wenn nicht zu jedem push exakt ein pop gemacht wird, kommt
alles komplett durcheinander. Ich bin erstaunt, daß überhaupt irgendwas
so ähnlich funktioniert wie gedacht.
danny_v1 schrieb:> Soweit ich das verstanden habe sichere ich mit dem push, mein Register> (temp)
Genauer: Du kopierst den Wert auf den Stack, also in den Speicher. Der
Stack ist dabei wie ein Stapel aufgebaut (daher der Name). Das nächste
push legt dann quasi den nächsten Wert auf den Stapel drauf.
> und mit dem pop geb ich den wert wieder auf das Register temp> zurück, oder?
Mit pop wird der zuletzt auf dem Stack gespeicherte Wert wieder
zurückgelesen in das Register, das du angibst. reti benutzt übrigens
auch den zuletzt auf dem Stack gespeicherten Wert als
Rücksprung-Adresse. Und jetzt überleg mal, was passiert, wenn du ein
push ohne dazugehöriges pop machst und danach ein reti.
dann spring ich zur falschen Adresse, da der falsche Wert im Stack noch
oben drauf liegt, richtig? Also müsste das im Beispiel vom Timer0 dann
so Aussehen???
timer0_overflow:
push TEMP
in TEMP,SREG
push TEMP
ldi TSW,timerwert
out tcnt0,TSW
;..........Programmcode Timer0
pop temp
out SREG, temp
pop temp
reti
danny_v1 schrieb:> dann spring ich zur falschen Adresse, da der falsche Wert im Stack noch> oben drauf liegt, richtig?
Richtig.
> Also müsste das im Beispiel vom Timer0 dann so Aussehen???
Ja, so paßt es.
Gut, da bin ich ja schonmal ein Stück weiter. Mit dem Timer1
funktioniert das dann ja sicher genauso.
Macht es einen Unterschied ob ich den Interrupt mit "rjmp" oder "call"
aufrufe???
Und dann hab ich festgestellt das das Programm nur funktioniert wenn ich
nach jeden Interrupt die Timer neu initialisiere, ist das normal???
danny_v1 schrieb:> Macht es einen Unterschied ob ich den Interrupt mit "rjmp" oder "call"> aufrufe???
Ja.
danny_v1 schrieb:> Und dann hab ich festgestellt das das Programm nur funktioniert wenn ich> nach jeden Interrupt die Timer neu initialisiere, ist das normal???
Nein.
und woran liegt das dann?
wäre schön wenn mal jemand was konkretes schreiben würde wie ich den
code abändern muss.
Hab den aktuellen nochmal in den Anhang gelegt.
danny_v1 schrieb:> und woran liegt das dann?> wäre schön wenn mal jemand was konkretes schreiben würde wie ich den> code abändern muss.
Es wäre schön, wenn du mal ein bischen mitdenken würdest.
Und es wäre schon, wenn du dir wenigstens die absoluten Grundlagen im
AVR-Tutorial mal reinziehen würdest.
Wenn du Code mittels einem CALL aufrufst, wie kommt man denn dann wieder
an die aufrufende Stelle zurück?
mit einem Return (ret oder reti)
Wenn du also hier
1
.ORG OVF0addr ;Bei Overflow Timer0 Sprung zu
2
call timer0_overflow ;Timer0_overflow
3
4
.ORG OVF1addr ;Bei Overflow Timer1 Sprung zu
5
call timer1_overflow ;Timer1_overflow
mit einem Call aus dem Interrupt Vektor in die eigentliche
Funktionalität verzweigst, wo landest du dann nach dem reti? Zb in dem
reti, der irgendwann in timer0_overflow passiert?
Und ist das das, was eigentlich passieren sollte?
Und wie passt das ins Bild, wenn du weißt, dass bei Auftreten und Beginn
der Interrupt Abarbeitung der Prozessor die Verzweigung in den Interrupt
Vektor selbst mit einem Call macht. Mit einem Call machen muss, weil die
Programmausführung ja wieder an die Stelle zurückkehren muss, die
eigentlich vom Interrupt unterbrochen wurde. Und genau das macht ja ein
Call. Wenn da also an diesen impliziten Call dann selbst auch noch einen
Call hinten nach ausführen lässt ....
Ok habs hinbekommen. Das Interrupt Tutorial war sehr hilfreich! Ja das
mit dem call und rjmp leuchtet mir jetzt ein.
Der Hauptfehler war das ich das TIMSK Register doppelt beschrieben hab
(dachte jeder Timer hat sein eigenes).
Danke für eure Hilfe.