unsichtbar
 

Servosteuerung

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 setzen Smiling
		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