Servosteuerung
Verfasst von Timo am 3. Januar 2008 - 7:53.
Wie funktioniert ein Servo?
Da es dazu genug im Internet zu lesen gibt, verlinke ich hier nur eine Seite, die alle notwendigen Informationen hat. http://www.the-starbearer.de/Roboterelektronik/servo/SERVOS.htm Das Servo kann direkt mit dem Signal-Pin an den Mikrocontroller angeschlossen werden und benötigt keine weitere Elektronik dazwischen (wie einen Transistor oder so - bitte Kommentieren, falls jemand damit Probleme hatte, bei mir funktioniert es sehr gut). Allerdings sollte man überlegen, ob man einen größeren Elektrolytkondensator als stabilisation für die Versorgungsspannung benutzt, da der Strom, der fließt, wenn der Servo anfängt zu drehen, doch nicht unerheblich ist (im Vergleich zum Mikrocontroller und LEDs und so).Was macht mein Code?
Er startet zwei Timer. Einer feuert alle 20ms einen Interupt, durch den der Port, an dem das Servo hängt auf "aus" geschaltet wird. Damit ist der PWM-Impuls begonnen und deren Länge wird der zweite Timer bestimmen, der direkt danach aktiviert wird. Dessen Comparewert wird vorher noch berechnet, wobei der Wert immer zwischen 125 und 250 pendelt (1-2ms). Ich gehe hier von einer Taktung des ATmega8 von 1Mhz aus. (Das ist seeehr wichtig, die Timerzeiten / prescaler anzupassen, wenn man mit anderen Taktzahlen arbeitet, da sonst nicht die gewünschten Zeiten eingehalten werden) Wenn der zweite Timer den gewünschten Wert erreicht hat, schaltet er den Port wieder an und setzt seine clock auf "keine", somit wird er nicht weitergezählt und ist aus. Im Endeffekt sieht es so aus, dass das Servo sich gemütlich hin und her drehen wird. Man kann die Geschwindigkeit erhöhen, indem man richtung mit einem größeren Wert initialisiert, sollte aber darauf achten, dass man entweder die Grenzen von 125 und 250 anpasst oder einen Wert nimmt, der durch vielfaches addieren immernoch den Zähler auf die beiden Werte kommen lässt. (also 2 wäre eine ganz schlechte Idee, da 125 + x *2 nie 250 wird)Codeschnipsel:
.include "m8def.inc" .def temp = r16 .def leds = r17 .def weite = r18 .def richtung = r19 .org 0x0000 rjmp main ; Reset Handler .org OC2addr rjmp timer2_compare ; Timer2 .org OC1Aaddr rjmp timer1_compare ; Timer1 ; Zum Plan: ; Ich benutze Timer1, der alle 20ms einen Port einschaltet und einen zweiten Timer startet ; Der zweite Timer wartet x ms und schaltet den Port um und sich aus. ; Okay, hier dei benötigten Register und deren Zweck: (nicht vollständig) ; Timer1 macht den 20ms Part: ; OCR1AH = obere 8 bit der 16 bit vergleichszahl ; OCR1AL = untere ... ; TIMSK = interruptregister für alle timer ; Timer2 macht den 1-2ms Part: ; OCR2 = zahl, zu der hochgezählt werden soll ; TCCR2 = steuerregister main: ldi temp, LOW(RAMEND) ; Stackpointer initialisieren out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ldi temp, 0xFF ; Port B auf Ausgang out DDRB, temp ldi leds, 0x00 ; initialisieren auf aus ; 125 + 250 / 2 = mittelstellung ldi weite, 125 ldi richtung, 1 ; richtungsangabe ; 20ms -Timer ; Vergleichswert ldi temp, high( 19999 ) ; jede 50 mal die sekunde out OCR1AH, temp ldi temp, low( 19999 ) out OCR1AL, temp ldi temp, ( 1 << WGM12 ) | ( 1 << CS10 ) ; CTC + no prescale out TCCR1B, temp ; OCIE1A: Interrupt bei Timer Compare - OCIE2 - ebenfalls ldi temp, (1 << OCIE1A) | (1 << OCIE2) out TIMSK, temp sei loop: rjmp loop timer1_compare: ;Hier wird der PWM-Impuls gestartet ; timerwert verändern add weite, richtung cpi weite, 250 ; ganz am anschlag? breq umstellen cpi weite, 125 ; ganz am anschlag? breq umstellen rjmp weiter umstellen: neg richtung ; 1 -> -1 und -1 -> 1 weiter: out OCR2, weite ; schonmal setzen ; timer auf 0 setzenldi temp, 0x00 out TCNT2, temp ldi temp, ( 1 << WGM21 ) | ( 1 << CS21 ) ; CTC + 8 prescale out TCCR2, temp ; Port anmachen ldi leds, 0xFF out PORTB, leds reti timer2_compare: ; Timer 2 compare handler - PWM-Impuls-Sendung beenden ; port ausmachen ldi leds, 0x00 out PORTB, leds ldi temp, 0b00000000 ; CS00 setzen: anhalten out TCCR2, temp reti

ldi temp, 0x00
out TCNT2, temp
ldi temp, ( 1 << WGM21 ) | ( 1 << CS21 ) ; CTC + 8 prescale
out TCCR2, temp
; Port anmachen
ldi leds, 0xFF
out PORTB, leds
reti
timer2_compare: ; Timer 2 compare handler - PWM-Impuls-Sendung beenden
; port ausmachen
ldi leds, 0x00
out PORTB, leds
ldi temp, 0b00000000 ; CS00 setzen: anhalten
out TCCR2, temp
reti