SINUS - COSINUS / KOSINUS - BEISPIEL (Assembler) ATmega8

OP #371845
Lesenswert?

Ein kleines Beispiel einer 8 Bit SINUS- und COSINUS (KOSINUS)

Berechnung in Assembler.



Berechnungsverfahren:

In einer Tabelle wurden 91 Sinus-Werte (0-90°) hinterlegt.

Alle Sinus und Cosinus-Werte (0...65535°) werden durch Spiegelung aus
diesen Tabellen-Werten berechnet.

Das Ergebnis ist ein 8Bit -Wert (-100...+100)


Anmerkung:

Für andere µC muss ggf. folgendes geändert werden:

- inc-Datei
- Interrupt-Vektoren
- STACK-Initialisierung


Bernhard
Angehängte Dateien:
#371846
Lesenswert?

kleiner Tip.
Wenn du Konstanten addieren musst, kannst du das,
indem die negatiev Konstante subtrahiert wird.

zb. hier
  ldi temp3, low(90)
  ldi temp4,high(90)
  ; 90° ADDIEREN
  add temp1,temp3
  adc temp2,temp4

-------------------------------
wird zu:
        ; 90° ADDIEREN
        subi   temp1, low( -90 )
        sbci   temp2, high( -90 )

Aus irgendwelchen unerfindlichen Gründen hat Atmel
dem µC kein add_immediate spendiert.

die subi und sbci Befehle können auch an anderen Stellen
im Code nutzbringend eingesetzt werden.
Moderator #3862759
Lesenswert?

Bei Antriebssteuerungen u.ä. werden Winkel oft nicht in Grad, sondern in
Einheiten von 360°/2^(8·n) dargestellt, d.h. der Vollkreis wird in 2^8,
2^16 oder 2^32 Teile unterteilt. Das hat mehrere Vorteile:

- Der Wertebereich eines uint8_t, uint16_t bzw. uint32_t wird voll
  genutzt, wodurch man bei gegebener Variablengröße die höchste
  Winkelauflösung erreicht.

- Bei der Berechnung von Winkeln werden die Ergebnisse automatisch
  normiert, d.h. auf den Bereich [0°,360°) reduziert.

- Die Berechnung von Winkeländerungen liefert ohne Fallunterscheidungen
  auch dann die erwarteten Ergebnisse, wenn zwischen dem Vorher- und dem
  Nachherwinkel ein 360°-Sprung liegt.

- Der Quadrant, in welchem ein Winkel liegt, kann mit einfachen
  Bitoperationen bestimmt werden.

Hier sind Sinus-/Cosinus-Routinen für 8-Bit-Argumente und -Ergebnisse:
1
zl  = 30
2
zh  = 31
3

4
cos:
5
  subi zl,-0x100/4
6
sin:
7
  push zh
8
  bst zl,7
9
  sbrc zl,6
10
  neg zl
11
  andi zl,0x7f
12
  ldi zh,hi8(sintab)
13
  lpm zl,Z
14
  brtc 1f
15
  neg zl
16
1:
17
  pop zh
18
  ret
19

20
.p2align 8
21
sintab:
22
  .byte   0,   3,   6,   9,  12,  16,  19,  22,  25,  28,  31,  34,  37
23
  .byte  40,  43,  46,  49,  51,  54,  57,  60,  63,  65,  68,  71,  73
24
  .byte  76,  78,  81,  83,  85,  88,  90,  92,  94,  96,  98, 100, 102
25
  .byte 104, 106, 107, 109, 111, 112, 113, 115, 116, 117, 118, 120, 121
26
  .byte 122, 122, 123, 124, 125, 125, 126, 126, 126, 127, 127, 127, 127

Argument und Ergebnis werden beide in R30 übergeben. Ein Winkelschritt
entspricht dabei 360°/256 ≈ 1,4°. Die Sinustabelle enthält 65 Einträge,
d.h. für die Argumente 0° (0x00) bis einschließlich 90° (0x40). Die
Ergebnisse liegen im Bereich [-127,+127]. Die Ausführungsdauer (ohne
CALL und RET) beträgt 14 Zyklen für den Sinus und 15 Zyklen für den
Cosinus.

Die Sinus-Tabelle wird an eine durch 256 teilbare Adresse gelegt, was
die Adressbestimmung aus dem Index vereinfacht.

Die verwendete Syntax ist die des GNU-Assemblers. Für den
Atmel-Assembler müsste man ein paar DInge anpassen.

Eine entsprechende Routine könnte man auch für 16-Bit-Argumente und
-Ergebnisse schreiben. Da die Tabelle dann aber 16385 16-Bit-Werte
enthält, wird sie über 32-KiB groß. Deswegen ist hier eine kleinere
Tabelle und eine lineare Interpolation zwischen einzelnen Stützstellen
sinnvoll. Die Stützstellen wählt man am besten äquidistant mit einem
Abstand von 2^n, so dass man sich eine aufwendige Division spart. Dann
laufen die 16-Bit-Routinen – gemessen an der erreichten Genauigkeit –
ebenfalls recht fix.
Gast #3864438
Lesenswert?

Yalu X. schrieb:

> Bei Antriebssteuerungen u.ä. werden Winkel oft nicht in Grad,
> sondern in Einheiten von 360°/2^(8·n) dargestellt, d.h. der
> Vollkreis wird in 2^8, 2^16 oder 2^32 Teile unterteilt. Das
> hat mehrere Vorteile: [...]

Stimmt alles. Hat aber den Schönheitsfehler, dass kleine Winkel
(z.b. 1°) nicht exakt darstellbar sind.
Um dem bei 16Bit-Darstellung abzuhelfen, könnte man 20" als
Einheit wählen; der Vollkreis würde dann in 64800 Teile geteilt.
Der Zahlbereich wird dann zu 98.87% ausgenutzt. Die Rechnerei
wird jedoch durch die 736 unbenutzten Digit komplizierter.
Moderator #3864831
Lesenswert?

Possetitjel schrieb:
> Stimmt alles. Hat aber den Schönheitsfehler, dass kleine Winkel
> (z.b. 1°) nicht exakt darstellbar sind.
> Um dem bei 16Bit-Darstellung abzuhelfen, könnte man 20" als
> Einheit wählen;

Warum muss 1° oder ein ganzzahliger Bruchteil davon exakt darstellbar
sein? Die Unterteilung des Vollkreises in 360 Teile ist doch ziemlich
willkürlich festgelegt worden.

Meistens muss sowieso irgendo skaliert werden, um bspw. Drehgeber- oder
Schrittmotorauflösungen oder Getriebeübersetzungen zu berücksichtigen.
Deswegen ist man in der Wahl der internen Winkeldarstellung recht frei,
solange die Auflösung hoch genug ist. So nimmt man praktischerweise
diejenige Darstellung, mit der am leichtesten zu rechnen ist.
Gast #3864951
Lesenswert?

Yalu X. schrieb:

> Possetitjel schrieb:
>> Stimmt alles. Hat aber den Schönheitsfehler, dass kleine Winkel
>> (z.b. 1°) nicht exakt darstellbar sind.
>> Um dem bei 16Bit-Darstellung abzuhelfen, könnte man 20" als
>> Einheit wählen;
>
> Warum muss 1° oder ein ganzzahliger Bruchteil davon exakt
> darstellbar sein?

"Muss" überhaupt nicht.

Das war nur eine eher anekdotische Randbemerkung. - Vor längerer
Zeit gab's hier mal eine Diskussion über Winkeldarstellung und
Winkelfunktionen mit ganzen Zahlen bzw. Festkommazahlen.
Hintergrund war eine Roboter-Anwendung, bei der schnell und
ohne Fließkomma gerechnet werden sollte.

Da mich das interessiert hat, habe ich vor Monaten mal gesucht,
ob sich das klassische Grad-Minute-Sekunde-System irgendwie
kompatibel in übliche Ganzzahlen abbilden lässt. Resultat war
die bereits geschilderte Unterteilung des Vollkreises in
360*60*3 = 64800 Teile, was ideal in 16bit passt.

> Die Unterteilung des Vollkreises in 360 Teile ist doch ziemlich
> willkürlich festgelegt worden.

Zweifellos. - Dennoch ist mir ganz recht, dass am Preisschild
in der Kaufhalle nicht "0x3E7" dransteht, sondern "9.99 Euro",
auch wenn das Zehnersystem letztlich genauso willkürlich ist.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren