mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Teilen durch 3 in Assembler


Autor: Jürgen Broß (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

kennt jemand eine einfache Prozedur wie man in AVR Assembler (AtTiny13)
ein Byte (unsigned) durch 3 ohne Rest teilen kann? Vielen Dank.

Nur zur Info: der AtTiny13 kennt weder einen Divisions- noch einen
Multiplikationsbefehl.

Jürgen

Autor: Thorsten Fritzke (thorsten)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
moin moin

so auf den sprung würde ich das mit einer schleife machen, die so lange
3 abzieht bis das register (oder was auch immer) 0 oder kleiner als 0
wird. dabei gleichzeitig ein anderes immer um 1 inc'en.

dann hast du im 2. register den ganzzahligen faktor für 3.

mfg

Autor: Sebastian Frank (nemie)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn es nur ein Byte ist, addiere doch in einer Schleife solange 3 zu
einem Register bis das Register größer ist als deine Zahl. Die Anzahl
der Durchläufe ist dann dein Ergebnis

Seb

Autor: Rupert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenns nicht so genau sein muss, versuch einfach 1/3 durch Summe aus
Brüchen mit Zweierpotenzen darzustellen, z.B.:

1/3 = 1/4 + 1/8 - 1/16 + 1/32 - 1/64 + ...

das wären 0.328 wenn ich mich nicht verrechnet hab, also schon recht
nahe an den 0.333. Die Brüche machst Du in Assembler durch Rechtsshift.

Autor: Tobias Floery (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst binär dividieren genau gleich wie du's in der Grundschule
gelernt hast:

z.B.: 90 / 3
01011010 : 11 =
01 <= 11 ==> ergebnis = 0
 10 <= 11 ==> ergebnis = 00
 101 >= 11 ==> ergebnis = 001
  101 >= 11 ==> ergebnis = 0011
   100 >= 11 ==> ergebnis = 00111
    011 >= 11 ==> ergebnis = 001111
      00 <= 11 ==> ergebnis = 0011110
       0 Rest
Also ergebnis = 11110 = 0x1E oder 30

Ob's dafür nen schönen Algo. gibt weiß nicht...

Autor: Jürgen Broß (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@all,
vielen Dank für die zahlreichen Ideen.

@Thorsten, @Sebastian
Diese Lösungen funktionieren auch mit anderen Zahlen als 3 und
beschreiben das konventionelle dividieren. Ich habe es im Moment so
implementiert.

@Rupert
Das ist ein mir bislang unbekannter Ansatz. Ich werde mal ausrechnen
wie groß der Aufwand und die Genauigkeit für's Teilen durch 3 ist.

@Tobias
Danke für die Beispielrechnung. Aber ohne Divisionsbefehl funktioniert
das glaube ich nicht. Oder ich müßte wieder ganz normal
Subtrahieren/Addieren wie beim Beispiel von Thorsten und Sebastian.

Nochmals Danke für eure Ideen

Jürgen

Autor: Andi K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie wärs hiermit:
http://www.atmel.com/dyn/resources/prod_documents/AVR200.zip

In vielen Fällen läuft das etwas fixer ab und geht voll nach dem
Verfahren von Tobias.

MfG
Andi

Autor: Michael P. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Multiplizieren mit 1/3 bzw. 85/256 bzw. mit 85 Multiplizieren und dann
von dem 16 bit Ergebnis nur das obere Byte nehmen.
Mfg
Michael

Autor: Jürgen Broß (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

@Tobias
Da war ich wohl zu vorschnell mit der Behauptung, daß dein Vorschlag
eine Division benötigt. Ich hab's gemerkt, als ich es mit den
Atmel-Algorithmen von Andi verglichen habe. Ist mir echt peinlich, ich
hoffe du nimmst es mir nicht übel.

@Andi
Vielen Dank für den Hinweis auf die Atmel Website. Die Datei hatte ich
irgendwie übersehen.

@Michael
Das ist auch ein interessanter Ansatz wenn nur ein
Multiplikationsbefehl und kein Divisionsbefehl zur Verfügung steht.

Also vielen Dank nochmal für eure Hinweise.

Jürgen

Autor: Tobias Floery (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kein Problem. Den Ansatz mit 1/3 multiplizieren habe ich mir gerade
überlegt und dabei gibts nur ein Problem: 1/3 lässt sich wie im
dezimalen im binären nicht eindeutig (also periodisch) anschreiben.
1/3 binär wäre 0,01010101... usw. Also wieder nur mit begrenzter
Genauigkeit darstellbar.

Wenn wir jetzt wieder 90 mit 1/3 multilpizieren sieht das so aus:

01011010 * 0,01010101
Jetzt Komma verschieben (Grundschule...), 8 stellen
001011010 * 1010101
--------------------
001011010
  001011010
    001011010
      001011010
--------------------- addieren
001110111100010
Komma wieder hinzu
0011101,11100010 ==> 29,xxx also fast 30.

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> Wenn wir jetzt wieder 90 mit 1/3 multilpizieren....

Dann "runde" 90 vorher indem du 90 + (3 -1) drauf addierst.
Wenn du zb. 89 / 3 rechnen willst, mit einer Ganzzahldivision, dann
solltest du auch (89 + 2) / 3 rechnen um ein korrektes Resultat zu
erhalten.

Gruß Hagen

Autor: Andi K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oder einfach nichtr mit 85 sondern mit 86 multiplizieren um nicht
29,irgendwas, sondern 30,irgendwas zu nekommen.

90 * 85 / 256 = 29,88   falsch
90 * 86 / 256 = 30,23   richtig
255 * 85 / 256 = 84,67  falsch
255 * 86 / 256 = 85,66  richtig
3 * 85 / 256 = 0,996    falsch
3 * 86 / 256 = 1,01     richtig

Wie man sieht, kommt man mit 86 an der Ganzzahl vor dem Komma genau
hin.
Für Zahlen mit 8 Bit ist das in Ordnung.
Erst bei Zahlen mit 16 Bit wird es irgend wann um 1 zuviel und mit 85
um 1 zu wenig.
Dann lieber doch gleich eine richtige Div-Routine verwenden sofern man
mit 16 Bit-Zahlen rechnen will.

MfG
Andi

Autor: jornbyte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bei 8 Bit mache ich es so:

.include  "8515DEF.INC" ;oder was auch immer

.CSEG
.ORG  0

Reset:
    ldi    yl,low(RAMEND)
    out    SPL,yl
    ldi    yh,high(RAMEND)
    out    SPL+1,yh
;******

;a=25
    ldi    r24,25
;b=3
    ldi    zl,3
;c=a/b
    rcall  Div8u
;ergebnis ist in zl

;****** 8/8 unsigned division ******
Div8u:  mov    r25,zl
    mov    zl,r24
    sub    r22,r22
    ldi    r23,0x09
d8u1:  rol    zl
    dec    r23
    brne  d8u2
    ret
d8u2:  rol    r22
    sub    r22,r25
    brcc  d8u3
    add    r22,r25
    clc
    rjmp  d8u1
d8u3:  sec
    rjmp  d8u1

Autor: Andi K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vergesst den letzten Beitrag von mir!
So oder so hat man z. B. bei 251 als Ergebnis 84 wie bei 252.
Auch, wenn man mit 85 multipliziert und vorher den Eingangswert um 2
erhöht.
Es bringt wirklich nur eine Div-Funktion was in der Form einer Schleife
und immer 3 subtrahieren bis Unterlauf oder die "echte" Div-Funtion
aus der App-Note die man, wenn es nur /3 sein soll darauf optimieren
könnte.

MfG
Andi

Autor: Andi K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@jornbyte: Das ist ja das aus dem AVR200.asm (App-Note).
Man kann es aber noch etwas optimieren um 8 Takte zu sparen.
Sind zwar "nur" 8% von den angegeben 97 aber immerhin.

Hier das umgestellte aus der App-Note:

div8u:  sub     drem8u,drem8u ;clear remainder and carry
        ldi     dcnt8u,9      ;init loop counter
d8u_1:  rol     dd8u          ;shift left dividend
        dec     dcnt8u        ;decrement counter
        breq    d8u_2         ;if done
        rol     drem8u        ;shift dividend into remainder
        sub     drem8u,dv8u   ;remainder = remainder - divisor
        brcc    d8u_3         ;if result negative
        add     drem8u,dv8u   ;restore remainder
        clc                   ;clear carry to be shifted into result
        rjmp    d8u_1         ;else
d8u_3:  sec                   ;set carry to be shifted into result
        rjmp    d8u_1
d8u_2:  ret                   ;return

Es ist lediglich das "RET" nach unten gestellt und das breq statt
brne benötigt nicht 2 sondern nur 1 Takt * 8 = 8 Takte gespart.

MfG
Andi

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.