Salut,
momentan bin ich dabei, fuer ein Hexapod-Projekt einen Controller fuer 16 Servos mit einem Mega16 zu entwickeln. Programm steht soweit, C-Anteil funktioniert auch bereits; nur der Assemblerteil macht Schwierigkeiten. Hier erst einmal der Kerncode, vorzustellen in einem .S-File mit Funktionsdefinitionen und Registersicherung, abgelegt in einer Timer-ISR:
Hoffe, das ist so einigermassen verstaendlich. Kerngedanke ist, dass ein Zaehler von 255 runtergeht und 16 sequentiell im SRAM abgelegte Servopositionen mit ihm verglichen werden; stimmt ein Wert ueberein, wird der Servo aktiviert. Je hoeher der Wert ist, desto frueher wird also der Servo zugeschaltet, wobei alle zur gleichen Zeit wieder abschalten (nach der ISR). Naeheres im Codekommentar.Code:; clear masks - we do not want to write anything yet clr amask clr bmask clr cmask ser counter ; count down from 255 sec ; c is to be rotated into cmask clt ; t is final break condition - cleared ldi ZH,4 ; RAM pointer is at 1024, address of first servo value ; duration of loop: 32512 cycles - 1.6128 ms of variable pulse width cycle: clr ZL ; point Z to first servo ; loop to set lower 8 Servos reg1: rol cmask ; rotate mask to indicate position of current servo in PORTA brcs end1 ; after 9 rotations: all Servos checked, exit loop ld servo,z+ ; copy value of current servo from RAM and move Z to next value cp servo,counter brne reg1 ; if servo is not to be set at current cycle: loop or amask,cmask ; else add current servo to output mask as high rjmp reg1 ; and loop end1: out _SFR_IO_ADDR(PORTA),amask ; output mask set in loop gets transferred to PORTA ; loop to set upper 8 Servos - equivalent to lower 8 reg2: rol cmask brcs end2 ld servo,z+ cp servo,counter brne reg2 or bmask,cmask rjmp reg2 end2: out _SFR_IO_ADDR(PORTD),bmask ; output mask set in loop to PORTD brts end ; if final exit condition met: jump to end dec counter ; count comparision value for Servos down brne cycle ; if not zero: next cycle set ; if zero: set exit condition rjmp cycle ; and repeat one last time end:
Es geht mir nun darum, den erzeugten Puls zwischen 0 und 1,6128 ms zu regeln (errechnet aus Zyklenzahl); momentan gibts aber 2 Probleme:
1. Liegt ein anderer Wert als 255 an der Registeraddresse, so wird sozusagen eine Reihe unterbrochen, die
2. kumulativ fuer jeden hintereinander auf 255 liegenden Servo eine exponentiell mit der Position steigende Zeit addiert.
Die Pulslaenge kann also nur durch o. g. Anzahl reguliert werden, nicht durch den Wert im SRAM; zudem ist sie fuer alle Servos gleich.
Ich habe keine Ahnung, wo der Fehler liegen koennte - kann mir da vielleicht jemand weiterhelfen?
Gruss und Dank,
David
PS: Falls jemand eine Optimierungsmoeglichkeit entdeckt - ich bin aufgrund der zeitkritischen Aufgabe um jeden Zyklus dankbar! Je weniger Zeit _noetig_ ist, desto besser laesst sich die Sache auf den Servo anpassen (nop)!
[Edit: Kleineren Fehler in der Schleife beseitigt, aendert nichts, Makulatur...]







Zitieren

Lesezeichen