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.
Sorry die Datei oben war das falsche Format hier ist jetzt hoffentlich das richtige.
Was auf den ersten Blick auffällt: diverse “push“ ohne “pop“. Und so nebenbei: was hat dein Problem mit dem GCC zu tun?
Sorry wenn ich hier im falschen Forum gepostet haben sollte. Wo müssten die "pop" denn hin???
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.