www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Banale Assembler-Schleifenfrage


Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Ich habe ein ziemlich banales "Problem" ich habe eine Schleife die x mal 
durchlaufen werden soll, x ist ein zwei Registern, aber maximal 512 
gross.
Wie mache ich das am Besten mit möglichst wenig Branches. Es gibt da 
eine unzahl an Branches, welche geschickte kombination aus denen aber 
eine kompakte Abzähl/Überprüf-Fuktion hat ist mir schleierhaft. Kann man 
das überhaupt elegant lösen?
Danke für eure Tipps, achja, verwende einen ATmega
Gruss

Autor: jack (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus schrieb:
   > x ist ein zwei Registern, aber maximal 512 gross.

Was soll das heißen?

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dass eine so grosse Zahl nicht in einem Register Platz hat und deshalb 
auf 2 aufgeteilt ist zum Beispiel:
ldi r20, high(x)
ldi r21, low(x)

Autor: Sonic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kleines Beispiel für 'ne Pause:

PAUSE:  ldi  PZEIT1,255
  ldi  PZEIT2,1
P_WAIT:  dec  PZEIT1
  brne  P_WAIT
  ldi  PZEIT1,255
  dec  PZEIT2
  brne  P_WAIT
  ret

Sollte von 512 'runterzählen.

Autor: Sonic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm.. sehr unübersichtlich.

Schleife:   ldi  X_low,255
            ldi  X_high,1

>hier Code einfügen<

WAIT:       dec  X_low
            brne WAIT
            ldi  X_low,255
            dec  X_high
            brne WAIT
ret

müsste besser sein.

Autor: Sonic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ups.. X_high muss natürlich mit 2 initialisiert werden!

Autor: unscheinbarer WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Sollte von 512 'runterzählen.
Zählt aber von 511 runter...

Das 2. ldi PZEIT1,255 müsste man sich aufgrund des begrenzten 
Zahlenraums sparen können.
(Bin aber niocht ganz so asmbewandert...)

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, das ist ziemlich kompakt, aber wenn ich zur initialisierung
ldi X_high, 0
habe, dann funktionierts nicht? Oder täusche ich mich? Dann zieht er 
eins ab, obwohl er schon null ist??

Autor: Sonic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Zählt aber von 511 runter...

Die komplette Schleife zählt von 512 'runter. Evtl. 'ne kleine 
Zeitüberschneidung beim Posten ?!

Autor: unscheinbarer WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
111111111b ist für mich 511 dezimal, oder?

Sie wird 512 Mal durchlaufen...

Autor: Sonic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat wohl keiner bemerkt:

Schleife:   ldi  X_low,255
            ldi  X_high,1
WAIT:

>hier Code einfügen<

            dec  X_low
            brne WAIT
            ldi  X_low,255
            dec  X_high
            brne WAIT
ret

So muss es aussehen.
Kannst auch von 0 abwärtszählen, dann wird das 'N'-Flag gesetzt. Wenn 
das nicht stört zählt er halt von 256 'runter.

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich obigen code simuliere, dann erhalte ich wie bereits vermutet 
komische ergebnisse, die schleife wird nicht mit jedem wert <512 korrekt 
oft mal durchlaufen, anscheinend geht es doch nicht so einfach...
zum Beipiel mit 256 also x_low=0 und x_high=1, dann wird die Schleife 
511 mal durchlaufen. Man muss (wie ich bereits befürchtet habe) auch auf 
null testen bevor man abzählen kann :(

Autor: Sonic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm.. X_high sollte 2 sein, dann sollte die X_low-Schleife 2x 
'runtergezählt werden, sprich: 2x256=512. Hatte vergessen die X_high auf 
2 zu ändern, sorry!

Autor: Ste (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wenn ich 255 wie folgt initialisiere:
x_low = 255
und x_high = 1
dann gehts

wenn ich für 256 folgendes eingebe:
x_low = 0
x_high = 2
dann machts die schleife eben 511 mal

deshalb wäre es irgendwie von Vorteil, wenn es eine Möglichkeit gibt die 
auch  geht...
An so einem einfachen Ding verzweifle ich noch

Autor: Sonic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>wenn ich 255 wie folgt initialisiere:
x_low = 255 und x_high = 1
dann gehts

Na, ist doch auch richtig. In Assembler und C wird ab 0 gezählt, also 
0..255 sind 256 Schritte. Sobald beim Abwärtszählen von 255 die 0 
erreicht wird (und das Zero-Flag gesetzt wird) sind 256 Schritte 
durchlaufen. Bau' die Schleife so auf und es funktioniert!

Autor: Bernhard S. (bernhard)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Notfalls durch "NOP" ein Feinabgleich vornehmen


Schleife:   ldi  X_low,255
            ldi  X_high,1
WAIT:
            dec  X_low
            brne WAIT
            ldi  X_low,255
            dec  X_high
            brne WAIT

            nop      ; 1 x nix tun

ret

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Sonic

Nicht ganz.
Das Problem ist, dass zuerst dekrementiert und erst dann
auf 0 geprüft wird. Du musst das umdrehen.
Geh ins extrem: low gleich 0, high gleich 0.
Wie oft werden die Schleifen durchlaufen?
Exakt: 65536 mal

Autor: Sonic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry nochmal, X_high muss 2 sein, sonst geht's nicht. Ansonsten ist die 
Schleife so korrekt, läuft 512 Schritte durch.

Autor: Karl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich glaub ich bin zu blöd,
bei x_low = 0
und x_high = 2
bekomme ich 511 durchläufe

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
lass den reload von low mit 255 weg.

Autor: Karl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Karl, so kam ich der Sache auf die Spur, man musste aber noch 
überprüfen ob denn von high nicht abgezogen wird obwohl schon null, 
folgendes ist entstanden:
ldi  X_low,255
ldi  X_high,0
WAIT:

//>hier Code einfügen<

            dec  X_low
            brne WAIT
      tst X_high
      breq finito
            dec  X_high
            rjmp WAIT
finito:

wer was einfachere kennt, bei dem man die Zahlen einsetzen kann und es 
läuft dann auch so viel mal, der möge sich melden....

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wozu die Umstände, der AVR kann doch 16Bit rechnen und höher:
ldi r16, low(512)
ldi r17, high(512)
loop:

; tue was 512 mal

subi r16, low(1)
sbci r17, high(1)
brne loop


Peter

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So implementierts der Compiler

  for( Counter = i; Counter != 0; --Counter )
  72:  c0 91 60 00   lds  r28, 0x0060
  76:  d0 91 61 00   lds  r29, 0x0061
  7a:  20 97         sbiw  r28, 0x00  ; 0
  7c:  19 f0         breq  .+6        ; 0x84 <main+0x1a>
    foo();
  7e:  ee df         rcall  .-36       ; 0x5c <foo>
  80:  21 97         sbiw  r28, 0x01  ; 1
  82:  fb cf         rjmp  .-10       ; 0x7a <main+0x10>
  84:  00 c0         rjmp  .+0        ; 0x86 <_exit>

Autor: Karl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieso einfach wenns auch kompliziert geht?
Danke vielmals

Autor: Bernhard S. (bernhard)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter

diese Schleife gefällt mir, aber müsste es nicht so sein?

  ...
  subi r16, low(1)
  brne loop
  sbci r17, high(1)
  brne loop

Bernhard

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernhard Schulz wrote:

> diese Schleife gefällt mir, aber müsste es nicht so sein?

Nein, der AVR hat ne sogenannte "Zero-Propagation":

Ein Folge von SUBI, SBCI, ... SBCI setzt nur dann das Zero-Flag, wenn 
sämtliche Ergebnisbytes Null sind.
Gilt analog für CP, CPC, ... CPC.


Peter

Autor: Bernhard S. (bernhard)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Peter,

wieder was für's Leben gelernt :)


Bernhard

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.