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
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.
Hallo Karl Heinz Buchegger, Danke für Deinen Tipp, den subi und sbci - Befehl zu verwenden. Bernhard
@ 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.
@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
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.
Danke Yalu für die sehr wertvollen Hinweise :-) Gruß Bernhard
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.
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.