Forum: Projekte & Code SINUS - COSINUS / KOSINUS - BEISPIEL (Assembler) ATmega8


von Bernhard S. (bernhard)


Angehängte Dateien:

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

von Karl H. (kbuchegg)


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.

von Bernhard S. (bernhard)


Lesenswert?

Hallo Karl Heinz Buchegger,

Danke für Deinen Tipp, den subi und sbci - Befehl zu verwenden.

Bernhard

von pencho (Gast)


Lesenswert?

@ Karl Heinz Buchegger
Laut Wikipedia http://de.wikipedia.org/wiki/Atmel_AVR ist diser Befehl
entwernt worden um Chipfläche zu sparen und so "Addition mit direktem
16-Bit-Parameter" zu realisieren.

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

@alle

Ein Beispiel für z.B. einen ATmega1284p / ATmega1284.

Winkel:          0...360 GRD, in 0,1 GRD-Schritten
Wertebereich: -127...+127

Vorteil: wenig Prozessor-Takte

Nachteil: sehr speicherintensiv


Bernhard

von Yalu X. (yalu) (Moderator)


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.

von Bernhard S. (bernhard)


Lesenswert?

Danke Yalu für die sehr wertvollen Hinweise :-)

Gruß Bernhard

von Franz (Gast)


Lesenswert?

Interessant wäre es, diesen Algortithmus in Assembler umzusetzen:
Beitrag "Re: minimalistische Berechnung einer Sinusschwingung"
um zu sehen, wie schnell er auf einem AVR läuft.

von Possetitjel (Gast)


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.

von Yalu X. (yalu) (Moderator)


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.

von Possetitjel (Gast)


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.

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.