Forum: Mikrocontroller und Digitale Elektronik Hilfe bei Schleife


von Stefan U. (stefan_032)


Lesenswert?

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.
1
1sekunde_warten:
2
clr 0_1s
3
1sekunde_temp:
4
cp 0_1s , 10
5
breq return
6
call 1sekunde_temp
7
8
9
0_5sekunden_warten:
10
clr 0_1s
11
0_5sekunden_temp:
12
cp 0_1s , 5
13
breq return
14
call 0_5sekunden_temp
15
16
17
return:
18
ret

kann dieses Programm funktionieren?

Vielen Dank

von Bernie (Gast)


Lesenswert?

Auf den ersten Blick: NEIN

Wozu hast du denn die Sprungmarken mit dem ..._temp:
am Ende, wenn du sie nicht benutzt?

von Stefan U. (stefan_032)


Lesenswert?

damit der Vergleich wieder zurückspringt

von Conny G. (conny_g)


Lesenswert?

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.

von Stefan U. (stefan_032)


Lesenswert?

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?

von Stefan U. (stefan_032)


Lesenswert?

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.

von Stefan U. (stefan_032)


Lesenswert?

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?

von troll (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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?

von Stefan U. (stefan_032)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Stefan U. (stefan_032)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Stefan U. (stefan_032)


Lesenswert?

Super, Danke!

von Rolf M. (rmagnus)


Lesenswert?

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.

von Stefan U. (stefan_032)


Lesenswert?

Alles klar. ;)

von Conny G. (conny_g)


Lesenswert?

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

von spess53 (Gast)


Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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

von Svenska (Gast)


Lesenswert?

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

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.