-         

Ergebnis 1 bis 4 von 4

Thema: Servocontroller mit Mega16

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    12.02.2005
    Beiträge
    38

    Servocontroller mit Mega16

    Anzeige

    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:

    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:
    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.

    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...]

  2. #2
    Benutzer Stammmitglied
    Registriert seit
    29.12.2004
    Beiträge
    84
    Hallo!
    Ich habe mir auch mal einen Servocontroller gebaut (für 8 Servos)
    Ich lasse alle 20ms einen Interrupt auslösen,
    dann gebe ich ein HI-Signal auf alle Servos,
    dann warte ich 1ms, da die Pulslänge zwischen 1 und 2ms liegt (1,5=Mitte)
    die Pulslängen verändere ich auch in einer schleife, so wie du es beschrieben hast,
    ist der Zähler also bei einem bestimmten Wert angelangt, dann wird das Signal wieder auf LO gezogen.
    Die komplette schleife muss so konstruiert sein, dass sie dann genau 1ms
    dauert, ggf. nop's einfügen und erst mal mit einem Servo probieren.
    Es kann passieren, dass du nicht alle Servos mit einer schleife ansteuern kannst. mach einfach 2 hintereinander.
    Gruß. Johannes

  3. #3
    Benutzer Stammmitglied
    Registriert seit
    12.02.2005
    Beiträge
    38
    Genau auf die gleiche Art mache ich das ja auch, nur dass es nicht funktioniert

  4. #4
    Benutzer Stammmitglied
    Registriert seit
    29.12.2004
    Beiträge
    84
    Hier meine Interrupt Routine..

    sbi PORTB,1 ;Pulse einschalten
    sbi PORTB,2
    sbi PORTB,3
    sbi PORTB,4
    sbi PORTB,0
    sbi PORTD,7
    sbi PORTD,6
    sbi PORTD,5


    ldi r23,16
    wms1:
    ldi r22,00
    wms2: ;etwa 1ms warten
    dec r22
    brne wms2
    dec r23
    brne wms1

    ldi r22,$00
    PLoop: ;Diese Schleife sollte auch wieder 1ms dauern

    lds r21,0x0060 ;Position lesen
    cp r22,r21 ;Vergleichen
    brne n1
    cbi PORTB,1 ;Ja, dann entsprechendes Portbit setzen
    n1:
    lds r21,0x0061
    cp r22,r21
    brne n2
    cbi PORTB,2
    n2:
    lds r21,0x0062
    cp r22,r21
    brne n3
    cbi PORTB,3
    n3:
    lds r21,0x0063
    cp r22,r21
    brne n4
    cbi PORTB,4
    n4:


    lds r21,0x0064
    cp r22,r21
    brne n5
    cbi PORTB,0
    n5:
    lds r21,0x0065
    cp r22,r21
    brne n6
    cbi PORTD,7
    n6:
    lds r21,0x0066
    cp r22,r21
    brne n7
    cbi PORTD,6
    n7:
    lds r21,0x0067
    cp r22,r21
    brne n8
    cbi PORTD,5
    n8:
    nop
    nop
    nop
    nop


    inc r22
    brne PLoop

    nop

    reti ;Rücksprung aus Interrupt


    Am besten du Verwendest den Simulator im AVR Studio und prüfst, ob die
    Zeiten auch stimmen, diese Routine ist für 12Mhz geschrieben...

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •