Hallo,
ich habe eine Frage zu einem Programmteil.
ich habe einen Timer per CTC auf 0,1s programmiert.
die Variable "0_1s" wird jedes mal bei OTC incrementiert.
Hab schon ewig nicht mehr Assembler programmiert, aber was mir auffällt:
Call speichert die return-Adresse auf dem Stack, damit ist es für eine
Schleife unpassend.
Sollte ein Jump-Befehl sein.
Den Rest kann ich gerade spontan nicht so beurteilen, bin zu lang raus
aus asm.
Ansonsten sollte man sich um den Zugriffskonflikt zwischen ISR und der
Schleife kümmern um nicht undefinierte Werte zu bekommen, also
Interrupts ausschalten während man die Variable liest.
genau das ist meine Frage. also call löscht die letzte Adresse und jump
nicht? was ist eigentlich der Unterschied zwischen call, rcall, jump und
rjump?
Ach und nochwas. Muss ich den Stack benutzen? Der Stack greift ja auf
den SRAM zu. Das heist ja das bei jedem Programm durchlauf ein paar mal
davon gelesen/geschrieben wird. Das heist das die Lebensdauer des µC
darunter leidet. Stimmt das? Der kann ja "nur" 100,000 mal benutzt
werden.
Muss mich für mein Spam entschuldigen..
Also hab jetzt in der Zwischenzeit ein bischen geforscht und
rausgefunden was der Unterschied zwischen jmp und call ist. Aber wie
weis ich ab wann ich ein rcall statt dem call nehmen muss.
Und zum Thema zurück:
wenn ich die call Befehle gegen jmp Befehle austausche, wird die
Subroutine gehen?
Stefan U. schrieb:> Ach und nochwas. Muss ich den Stack benutzen? Der Stack greift ja auf> den SRAM zu. Das heist ja das bei jedem Programm durchlauf ein paar mal> davon gelesen/geschrieben wird. Das heist das die Lebensdauer des µC> darunter leidet. Stimmt das? Der kann ja "nur" 100,000 mal benutzt> werden.
Unsinn. Der Flash lässt sich nur x-mal programmieren, der SRAM hingegen
beliebig oft beschreiben und lesen. Stack und Variablen stecken in
letzterem.
Stefan U. schrieb:> genau das ist meine Frage. also call löscht die letzte Adresse und jump> nicht?
Nein. Call löscht gar nichts. Es legt nur die aktuelle Adresse auf den
Stack, vergrößert diesen also. Du hast Funktionen gebastelt, die sich
rekursiv selbst aufrufen und damit den Stack ziemlich schnell zum
überlaufen bringen.
Stefan U. schrieb:> Ach und nochwas. Muss ich den Stack benutzen?
Sagen wir's mal so: Ohne kommt man nicht sehr weit.
Stefan U. schrieb:> Aber wie weis ich ab wann ich ein rcall statt dem call nehmen muss.
Einen rcall mußt du verwenden, wenn der benutzte µC (offenbar irgendein
AVR) keinen call hat. Wenn er beides hat, kannst du immer call
verwenden. Der braucht halt einen Tick mehr Flash, RAM und Zeit als
rcall. Bei rcall darf dafür das Ziel des Aufrufs nicht weiter als +/- 4k
vom Aufruf selbst entfernt sein. Da man bei 8k Flash oder weniger mit
rcall immer den gesamten Flash erreichen kann, ist ein call dort unnötig
und existiert deshalb auch nicht.
> Und zum Thema zurück:> wenn ich die call Befehle gegen jmp Befehle austausche, wird die> Subroutine gehen?
Wenn dein Timer tatsächlich richtig funktioniert, könnte das gehen. Dann
kannst du du aber auch gleich den breq return durch brne
0_5sekunden_temp ersetzen und den jmp ganz weglassen. Ich frage mich
nur, warum du kunstvoll mit einem Timer arbeitest, um dann doch nur in
einer Schleife Taktzyklen zu verheizen. Wozu dann überhaupt der Timer?
Danke für die Antwort!
Ich werde einen Attiny 84A benutzen. Der hat 8k also kann ich immer
rcall bzw rjmp verwenden?
@ Rolf Magnus:
brne kann ich ja nicht verwenden oder? Der Befehl hatt ja garkeinen
Bezug. Die Variable wird ja vom Interrupt beeinflusst. Somit weis der
doch garnicht was er vergleichen soll. Oder wie meinst du dass?
Ich benutze die Teimer um möglichst genau auf 0,1s zu kommen. Ich habe 2
Timer zur verfügung. Der 16Bit-Timer zählt auf 0,1s und der 8Bit-Timer
bis auf 0,5ms (Ist ein anderer Programmteil mit dem selbem Ablauf).
Für das Programm brauche ich viele Variablen und habe deswegen nurnoch
eine übrig. Deswegen kann ich es nicht mit der klassischen "Variablen
dec and brne" Schleife machen. Für das gesammte Programm werden die
Timer nicht genutzt. So nutze ich sie und spare ein paar Variablen.
Oder sehe ich da was ganz falsch?
Stefan U. schrieb:> brne kann ich ja nicht verwenden oder? Der Befehl hatt ja garkeinen> Bezug.
Was meinst du mit 'keinem Bezug'?
Der Branch, egal ob breq oder brne wertet die Flags aus, egal wie die
eingestellt wurden. Bei dir macht das eben der vorhergehende Compare
(CPI)
Der Compare führt den Vergleich durch und er nachfolgende Branch benutzt
das Ergebnis des CPI.
Aber. Ob du
1
Label1:
2
+---> cpi Register, Wert ; Wie ist das Verhaeltnis von Reg. und Wert?
3
| breq Label2 ; wenn gleich ---+
4
+--- rjmp Label1 ; |
5
; |
6
Label2: ...... ; <---------------------+
machst, oder ob du
1
Label1:
2
cpi Register, Wert ; <--------------------+
3
brne Label1 ; wenn ungleich -------+
4
5
......
machst, kommt sich ja offensichtlich aufs gleiche raus. Durchdenk das
mal, in welchem Fall der Sprung zurück zum Compare geht. Es geht in
beiden Fällen immer dann zurück (und damit wird die Schleife gebildet),
wenn der Wert im Register ungleich dem Vorgabewert ist, wie die
eingezeichneten Pfeile ja zeigen. Logisch gesehen, sind die beiden
Alternativen von daher gleichwertig.
Die erste Version legt das Augenmerk auf die Fragestellung: Unter
welcher Bedingung wird die Schleife abgebrochen? Nämlich dann, wenn
Register und Wert gleich sind.
Die zweite Version betont die Fragestellung: Unter welcher Bedingung
wird die Schleife wiederholt? Sie wird wiederholt, solange Register und
Wert ungleich sind.
Und zumindest in diesem Fall ist die zweite Version um einiges
einfacher, während die erste Version ein bischen was von 'von hinten
durch die Brust ins Auge' an sich hat.
> Die Variable
Das Register
> wird ja vom Interrupt beeinflusst.
Ja und? Das hat ja nichts damit zu tun, auf welche Art und Weise du den
Vergleich auswertest.
> Somit weis der> doch garnicht was er vergleichen soll.
Natürlich 'weiß' er das. Steht ja dort
cpi Register, Wert
> Ich benutze die Teimer um möglichst genau auf 0,1s zu kommen.
Wenn es noch andere Interrupts im System gibt, dann ist das ok. Gibt es
dir nicht, dann hast du mit Zitronen gehandelt, dann wären ineinander
geschachtelte Schleifen besser.
Die andere Frage lautet: Wozu? Was ist so wichtig daran, dass du
möglichst genau 1 Sekunden brauchst?
> Timer nicht genutzt. So nutze ich sie und spare ein paar Variablen.
Register
> Oder sehe ich da was ganz falsch?
Man kann auch ein paar Register im Programm dazu abstellen,
zwischendurch auch mal andere Aufgaben zu übernehmen.
Danke für die Antwort.
Jetzt habe ich es verstanden! ;)
Die 0,5ms zählen mir Impulse. Also wie viele 0,5ms Schritte sind
zwischen zwei Pin-Interrupts vergangen.
So messe ich die Frequenz eines Signals. Dieses hat max. 300Hz, deswegen
die 0,5ms. Um noch ein bisschen Luft zu haben.
Auch werden zum Verarbeiten der Frequenz die 0,5ms und die 0,1s
gebraucht.
Ich hab mir erst das Programmieren beigebracht und habe mein Problem
nach meiner Unerfahrenheit nach gelößt. Sprich so wie mein
"Gedankenblitz" gerade aussah. Deswegen kann es auch für euch ein wenig
suspect rüberkommen.
Noch eine letzte Frage. Wie oben schon geschrieben:
"Ich werde einen Attiny 84A benutzen. Der hat 8k. Kann ich also immer
rcall bzw rjmp verwenden?"
Stefan U. schrieb:> "Ich werde einen Attiny 84A benutzen. Der hat 8k. Kann ich also immer> rcall bzw rjmp verwenden?"
wenn der Sprung zu weit führen würde, dann teilt dir das der Assembler
schon mit. Für den ist das eine leichte Übung, die errechnete
Sprungdistanz mit dem technologisch vorgegebenem Maximum zu vergleichen
und bei Bedarf einen Fehler auszugeben.
Stefan U. schrieb:> Noch eine letzte Frage. Wie oben schon geschrieben:>> "Ich werde einen Attiny 84A benutzen. Der hat 8k. Kann ich also immer> rcall bzw rjmp verwenden?"
Sorry, hab mich da vertan. Die maximale Sprungweite für rjmp ist +/-2k,
also kann es nur bei Prozessoren bis 4k den ganzen Speicher erreichen.
Aber wie Karl Heinz schon schreibt, kannst du trotzdem rjmp verwenden,
und wenn dir der Assembler meldet, daß das Sprungziel zu weit weg ist,
ersetzt du es eben durch jmp.
> und wenn dir der Assembler meldet, daß das Sprungziel zu weit weg ist,> ersetzt du es eben durch jmp.
Wenn er immer jmp verwenden würde, dann bedeutet das 1-2 Bytes mehr für
den Befehl und ein paar Taktzyklen mehr?
Wenn er also nicht mit Bytes und Zeit knausern müsste, könnte er auch
einfach immer jmp verwenden?
Ich fände nämlich, dass man ein Anfänger nicht gleich ins Zeit und Bytes
optimieren schicken muss, das macht es nur unnötig kompliziert.
Hi
>Wenn er also nicht mit Bytes und Zeit knausern müsste, könnte er auch>einfach immer jmp verwenden?AVRs mit <=8k Flash kennen kein 'jmp' oder 'call'.
MfG Spess
Rolf Magnus schrieb:> Stefan U. schrieb:>> Noch eine letzte Frage. Wie oben schon geschrieben:>>>> "Ich werde einen Attiny 84A benutzen. Der hat 8k. Kann ich also immer>> rcall bzw rjmp verwenden?">> Sorry, hab mich da vertan. Die maximale Sprungweite für rjmp ist +/-2k,> also kann es nur bei Prozessoren bis 4k den ganzen Speicher erreichen.
Ja, aber +/-2k Words. Deine obige Aussage mit den 8k Flash passt
schon.
Konrad G. schrieb:>> und wenn dir der Assembler meldet, daß das Sprungziel zu weit weg ist,>> ersetzt du es eben durch jmp.>> Wenn er immer jmp verwenden würde, dann bedeutet das 1-2 Bytes mehr für> den Befehl und ein paar Taktzyklen mehr?
Der Befehl ist zwei Bytes länger und braucht einen Taktzyklus mehr als
rjmp. Wenn man davor einen Skip-Befehl hat, verlängert sich dessen
Ausführungszeit nochmal um einen Taktzyklus.
> Wenn er also nicht mit Bytes und Zeit knausern müsste, könnte er auch> einfach immer jmp verwenden?
Sofern sein AVR einen jmp hat, ja. Auch bei der Interrupt-Vektor-Tabelle
muß man darauf achten, wie groß die Einträge sind und ob da ein jmp
überhaupt reinpaßt.
Stefan Ernst schrieb:>> Sorry, hab mich da vertan. Die maximale Sprungweite für rjmp ist +/-2k,>> also kann es nur bei Prozessoren bis 4k den ganzen Speicher erreichen.>> Ja, aber +/-2k Words. Deine obige Aussage mit den 8k Flash passt> schon.
Ah, hatte ich das doch richtig in Erinnerung und mich jetzt nur selbst
ausgetrickst. ;-)
> Ich fände nämlich, dass man ein Anfänger nicht gleich ins Zeit und Bytes> optimieren schicken muss, das macht es nur unnötig kompliziert.
Einen anderen Grund gibt es für Assembler nicht. Wer nicht mit Zeit und
Bytes knausern muss, nimmt eine Hochsprache und/oder einen schnelleren
Controller.