Hallo Leute, ich bräuchte für Umrechnung der Entfernung in cm eine Divisionsroutine, die mir eine 16-bit Zahl durch eine konstante 8-Bit Zahl dividieren würde (genauer gesagt ist diese Konstante 58). Ich programmiere in Assembler, auf dem Atmega8. Habe sehr viele Beiträge bereits gelesen, konnte jedoch keine passende Lösung finden. mfg Anton
Von Atmel gibts ne Appnote für Divisionen/Multiplikationen. Schau dir die an, entsprechende Routinen sind dabei (in ASM).
Da der ATmega einen Mul-Befehl hat, ist es einfacher mit dem Reziproken zu multiplizieren und das Ergebnis entsprechend nach rechts zu schieben. Peter
Peter Dannegger schrieb: > Da der ATmega einen Mul-Befehl hat, ist es einfacher mit dem Reziproken > zu multiplizieren und das Ergebnis entsprechend nach rechts zu schieben. > > > Peter könntest du das bitte näher erläutern, habe es nicht so ganz verstanden, wie es mit mul Befehl gehen soll .. mfg Anton
Anton schrieb: > könntest du das bitte näher erläutern 1/58 * 65536 = 1130 D.h. mit 1130 multiplizieren und um 16 Bits nach rechts schieben. Peter
Du dividierst zuerst durch 64 und addierst einen Korrekturfaktor. z.B. 10000/58=172,413 10000/64=156 156,25/8=19 /8=2 /4=0 /2=0 156+19-2-0-0=173 anderes Beispiel: 65536/58=1129,931 65536/64=1024 /8=128 /8=16 /4=4 /2=2 1024+128-16-4-2=1130 Oder wie Peter beschrieben hat, nur statt shr16 vom 32-bit-Ergebnis nur das upper-word verwenden. Abhängig vom Eingangsbereich kannst Du vorher noch erweitern, um besser runden zu können.
Es ginge auch ganz klassisch: Vom Dividend solange den Divisor abziehen und mitzählen bis das Subtraktionsergebnis negativ wird. Dann wieder einen Schritt rückgängig machen und du hast dein Ergebnis + Rest.
8bit = 256 Werte Wenn du genügend Speicher dafür hast, dann kannst du es auch über eine Lookuptabelle machen. Ist schneller, erfordert aber Vorarbeit.
Anton schrieb: > Peter Dannegger schrieb: >> Da der ATmega einen Mul-Befehl hat, ist es einfacher mit dem Reziproken >> zu multiplizieren und das Ergebnis entsprechend nach rechts zu schieben. >> >> Peter > > könntest du das bitte näher erläutern, habe es nicht so ganz verstanden, > wie es mit mul Befehl gehen soll .. > mfg Anton Einfach nem guten C-Compiler bei der Arbeit zuschauen ;-)
1 | unsigned int div58 (unsigned int x) |
2 | {
|
3 | return x/58; |
4 | }
|
übersetzt avr-gcc zu (r24 = r24 / 58):
1 | div58: |
2 | movw r18,r24 ; 6 *movhi/1 [length = 1] |
3 | ldi r26,lo8(-97) ; 7 *movhi/5 [length = 2] |
4 | ldi r27,lo8(70) |
5 | call __umulhisi3 ; 8 *umulhi3_highpart_call [length = 2] |
6 | swap r25 ; 25 *lshrhi3_const/5 [length = 6] |
7 | swap r24 |
8 | andi r24,0x0f |
9 | eor r24,r25 |
10 | andi r25,0x0f |
11 | eor r24,r25 |
12 | ret ; 24 return [length = 1] |
Für __umulhisi3 siehe http://gcc.gnu.org/viewcvs/trunk/libgcc/config/avr/lib1funcs.S?view=markup#l357
Und falls es allgemeiner sein soll und langsamer sein darf:
1 | #define VAL 24 |
2 | #define REST 22 |
3 | #define CNT 20 |
4 | #define DIVISOR 21 |
5 | |
6 | ;; REST <- VAL % DIVISOR |
7 | ;; VAL <- VAL / DIVISOR |
8 | |
9 | udivmod16_8: |
10 | clr REST |
11 | ldi CNT, 16 |
12 | |
13 | 2: lsl VAL |
14 | rol VAL+1 |
15 | rol REST |
16 | cp REST, DIVISOR |
17 | brlo 3f |
18 | inc VAL |
19 | sub REST, DIVISOR |
20 | 3: dec CNT |
21 | brne 2b |
22 | ret |
Meine Version. Die 10 unten in 58 ändern
1 | ;-------------------------------------------------------------------------------- |
2 | ; 16Bit Division durch 8Bit Konstante. In diesem Fall 10. |
3 | ; Übergaberegister & Ergebniss in temp2/temp3 (low/high), Rest = temp1 |
4 | ;-------------------------------------------------------------------------------- |
5 | div:ldi temp4,16 ;16* schieben |
6 | clr temp1 ;Rest =0 |
7 | dv1:lsl temp2 |
8 | rol temp3 |
9 | rol temp1 |
10 | cpi temp1,10 ;Solange Bits in temp1 (Rest) schieben bis >= 10 |
11 | brcs dv2 ;Wenn der Rest <10 ist, das 0-Bit in temp2 (LSL, oben) stehen lassen |
12 | inc temp2 ;Ansonsten Bit0 setzen und 10 vom Rest abziehen |
13 | subi temp1,10 |
14 | dv2:dec temp4 ;Das ganze 16 mal |
15 | brne dv1 |
16 | ;------------------------------------------------- |
17 | ; Ende Div Routine. |
Hallo, sorry das ich das alte Thema ausgrabe. Der Code von Jürgen Funktioniert aber nur mit Werten unter 100 oder? Mit 158 kommt bei mir ein Falsches Ergebis raus nämlich statt 414 kommt 388.
Thomas Gruber schrieb: > Der Code von Jürgen Funktioniert aber nur mit Werten unter 100 oder? Nur bis 127. Willst Du bis 255, mußt Du noch den Übertrag bei "rol temp1" berücksichtigen.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.