Forum: Compiler & IDEs Atmega32 Timer0 und Timer1


von danny_v1 (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Uwe (de0508)


Lesenswert?

Wie bitte ?

ich sehe keinen Code!

von danny_v1 (Gast)


Angehängte Dateien:

Lesenswert?

Sorry die Datei oben war das falsche Format hier ist jetzt hoffentlich 
das richtige.

von Stefan E. (sternst)


Lesenswert?

Was auf den ersten Blick auffällt: diverse “push“ ohne “pop“.

Und so nebenbei: was hat dein Problem mit dem GCC zu tun?

von danny_v1 (Gast)


Lesenswert?

Sorry wenn ich hier im falschen Forum gepostet haben sollte.

Wo müssten die "pop" denn hin???

von Rolf Magnus (Gast)


Lesenswert?

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

von danny_v1 (Gast)


Lesenswert?

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.

von STK500-Besitzer (Gast)


Lesenswert?

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.

von danny_v1 (Gast)


Lesenswert?

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?

von Rolf Magnus (Gast)


Lesenswert?

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.

von danny_v1 (Gast)


Lesenswert?

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

von Rolf Magnus (Gast)


Lesenswert?

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.

von danny_v1 (Gast)


Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

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.

von danny_v1 (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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

von danny_v1 (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.