Modell-RC-Servo-Inverter


 PIC-Projekte , zurück , PIC-Prozessoren , Elektronik , Homepage

Analoge Modellbauservos werden mit Impulsen angesteuert. Die Impulslänge bestimmt dabei die Sollstellung der Servoachse. Die Pulse sind zwischen 1 ms und 2 ms lang, und werden etwa 50 mal pro Sekunde wiederholt. Eine Impulslänge von 1,5 ms entspricht der Servomittelstellung.

In einem bestimmten Schiffsmodell war es nötig, den Servo andersherum einzubauen, als ursprünglich geplant. Dadurch drehte der Servo jetzt genau in die falsche Richtung. Dieses Problem lässt sich mit einem Servo-Inverter beheben, der in die Leitung zwischen Modell-Funkempfänger und Servo eingeschliffen wird. Der Inverter verändert die Impulsweite so, dass bei minimalem Eingangsimpuls (vom Empfänger) ein maximaler Ausgangsimpuls (zum Servo) erzeugt wird, und umgekehrt.

(Normalerweise kann man so ein Problem auch durch die Umprogrammierung der Fernsteuerung beheben, dass war aber aus anderen Gründen nicht erwünscht.)




Schaltung

Schaltung
Ein PIC12F629 mit 8-Pins ist ausreichend.
Der Einfachheit halber wird der interne 4-MHz-Oszillator des PIC verwendet.

Als Eingangspin für den Puls verwende ich GPIO2 (Pin 5) und als Ausgang GPIO5 (Pin 2). Das Pin GPIO0 (Pin 7) dient dem Anschluss einer Korrekturtaste (nach Vss) zur Nullpunkteinstellung.

Das ist auch schon die ganze Schaltung.

Hinweis
Das Pin GPIO1 (Pin 6) ist ein weiterer Tastereingang zu Testzwecken. Wird es mit Vss verbunden, dann gibt der PIC Ausgansgpulse der festen Länge 1,5 ms aus, egal wie lang die Eingangspulse sind. Da GPIO1 normalerweise nicht benötigt wird, ist es nicht zu beschalten.




Berechnung

Der PIC überwacht kontinuierlich den Eingang. Wird ein positiver Puls erkannt, dann wird dessen Länge (in 10-us-Schritten) gemessen. Ist der Puls kürzer als 0,5 ms (Messwert 50) oder länger als 2,55 ms (Messwert 255), dann wird der Puls ignoriert, da er offensichtlich fehlerhaft ist. Für Pulse "sinnvoller" Länge wird die inverser Pulsbreite berechnet, und der inverse Puls ausgegeben.
Die Berechnung ist eigentlich simpel:  Ausgangspulsbreite = 3ms - Eingangspulsbreite

Die gesamten Messungen und Berechnungen erfolgen aber in 10-us-Schritten. Damit entsprechen 3 ms intern dem Zahlenwert 300 (dezimal). Das ist aber größer als der maximale 8-Bit-Zahlenwert von 255. Die Berechnung lautet also:
Ausgangspulsbreite = 300 - Eingangspulsbreite
Ausgangspulsbreite = 256+44 - Eingangspulsbreite
Ausgangspulsbreite = 44 - Eingangspulsbreite

Ich kann also den Eingangspulsmesswert einfach von 44 subtrahieren, und erhalte auch das richtige Ergebnis für den Ausgangspuls, ein Nebeneffekt der 8-Bit-Arithmetik.

Der Wert 44 ist nicht fest im Code verankert, sondern im EEPROM des PIC abgespeichert. Beim Einschalten des PIC wird er hier ausgelesen. Damit ergibt sich hier eine Justiermöglichkeit für die Pulslänge.
Wird der Taster am Pin 7 gedrückt, so dient das als Anweisung an den PIC, mit der aktuellen Eingangspulslänge einen Ausgangspuls von 1,5 ms (Mittelstellung)  zu erzeugen. Dazu wird nun einfach der Ausgangsrechenwert (normalerweise 44) so verändert, dass sich mit dem aktuellen Eingangspulsbreite eine Ausgangspulsbreite von 1,5 ms ergibt. Der modifizierte Wert wird anstelle der originalen "44" im EEPROM abgespeichert, und zukünftig verwendet.



mögliche Verbesserungen

Die Lösung wurde so einfach wie möglich gehalten. Dadurch ist die Auflösung auf 8 Bit begrenzt. Für eine verbesserte Auflösung von z.B. 10 Bit wäre ein grundsätzlich anderer Ansatz der Pulslängenmessung (z.B. mit der Capture-Hardware) oder ein höherer PIC-Takt nötig. Beides wäre zwar realisierbar, erfordert dann aber einen anderen PIC-Typ.



Programmcode


        list p=12f629
;***********************************************************************
;*      Pinbelegung
;*      ----------------------------------     
;*      GP:     0 < KorrekturTaste
;*              1 < 1,5 ms Taste
;*              2 < Puls-Eingang
;*              3 -
;*              4 > out 4
;*              5 > Puls-Ausgang
;*     
;***********************************************************************
;
;sprut (zero) Bredendiek 12/2010
;
; Servo-Inverter mit 12F629
;
; Prozessor 12F629
;
; Prozessor-Takt 4 MHz intern
; Zyklus = 1 us
;
;  es werden Pulse von 0,5 ms bis zu 2,5 ms akzeptiert  (500 .. 2500 Zyklen)
; outPulse  = 3 ms - inPuls
;
;
;***********************************************************************
; Includedatei für den 12F629 einbinden

        #include <P12f629.INC>

        ERRORLEVEL      -302            ;SUPPRESS BANK SELECTION MESSAGES

; Configuration festlegen:
; Power on Timer, kein Watchdog, int-Oscillator, Brown out 2,1V
        __CONFIG        _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _BODEN_ON


;***********************************************************************
; Variablen festlegen  20h ... 5Fh

W_save          Equ     0x20            ; auch 0xA0
Status_save     equ     0x21            ; registers for saving context
PCLATH_save     equ     0x22
Flags           equ     0x23            ; flag bits (see definitions below)
counter         equ     0x24            ; Misc counter
PinL            equ     0x25
PoutL           equ     0x26
Nullpunkt       equ     0x27


; Flag bits (FLAGS)
#define InPulse         GPIO, 2
#define OutPulse        GPIO, 5
#define KorrekturTaste  GPIO, 0
#define MittenTaste     GPIO, 1

;***********************************************************************
;voreingestellte Daten für den EEPROM ab der Zelle 00h
        org     H'2100'                 ; Adresse des EEPROM für den Brenner
        de      D'44'                   ; 44 -> (0)

;***********************************************************************
        org     0x00

        goto    Main

;***********************************************************************
; Initialisierung
;
;***********************************************************************
Init
        ; IO-Pins
        bcf     STATUS, RP0             ; Bank 0
        clrf    GPIO                    ; aus!
        movlw   0x07
        movwf   CMCON                   ; alle Pins digital (nicht Comp)
        bsf     STATUS, RP0             ; Bank 1
; nur 12F675
;       CLRF    ANSEL                   ; GP0,1,2,4 von ADC auf digital
        movlw   B'11011111'
        movwf   TRISIO
        bcf     OPTION_REG,7            ; GPPU
        movlw   0xFF
        movwf   WPU                     ; pull up ein
        bcf     STATUS, RP0             ; Bank0

        ; interner Taktgenerator
        bsf     STATUS, RP0             ; Bank 1
        call    0x3FF
        movwf   OSCCAL                  ; 4-MHz-Kalibrierung
        bcf     STATUS, RP0             ; Bank 0

        ; Interrupt
        bcf     INTCON, GIE             ; Int deaktiviert

        clrf    counter
        clrf    Flags

        movlw   0
        call    EEread
        movwf   Nullpunkt

        return



;***********************************************************************
;Main
;
;***********************************************************************
Main
        call    Init                    ; PIC initialisieren


LoopStart

        ; auf Pulse warten  ___XXXXX___
        clrf    PinL
WaitForPulse
        btfss   InPulse
        goto    WaitForPulse
        ; puls da, nun laenge messen in 10us increments
WFP1
        nop
        nop
        nop
        nop
        incf    PinL, f
        BTFSC   STATUS, Z
        GOTO    LoopStart               ; viel zu lang >2,56 ms        
WFP2
        btfsc   InPulse
        goto    WFP1

        ; Plausibilitetstest 0,5 ... 2,5 ms
        movlw   D'50'
        subwf   PinL, w                 ; PinL - 50  so sollte nun C kommen
        BTFSS   STATUS, C
        GOTO    LoopStart               ; viel zu kurz < 0,5 ms

Taste1
        ; Korrekturtaste ??
        btfsc   KorrekturTaste
        goto    Taste2
        ; ok, das soll nun also 1,5 ms sein
        ; dafuer muss nun Nullpunkt angepasst werden
        movlw   D'150'
        addwf   PinL, w
        movwf   Nullpunkt
        call    EEwrite
        goto    Berechne

Taste2
        btfsc   MittenTaste
        goto    Berechne
        movlw   D'150'
        movwf   PoutL
        goto    PA


Berechne
        ; Pulse berechnen
        ; outPulse  = 3 ms - inPuls
        ; PoutL = 300 - PinL
        ; PoutL = 256 +44 - PinL
        ; PoutL = 44 - PinL

        movfw   PinL
        subwf   Nullpunkt, w
        movwf   PoutL
       

PA
        ; Pulse ausgeben
        bsf     OutPulse
PA1    
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        decfsz  PoutL, f
        goto    PA1
        bcf     OutPulse


        goto    LoopStart



;***********************************************************************
        ; (w) -> w
EEread
        bsf     STATUS, RP0
        ;movlw  Adresse
        movwf   EEADR
        bsf     EECON1, RD
        movf    EEDATA, w
        bcf     STATUS, RP0
        return

;***********************************************************************

        ; w -> (0)
EEwrite
        BSF     STATUS, RP0             ; EEADR und EEDATA liegen in der Bank 1

        MOVWF   EEDATA                  ; Wert aus w wollen wir schreiben
        MOVLW   0x00             
        MOVWF   EEADR                   ; Die Zelle 0 soll beschrieben werden


        BSF     EECON1, WREN            ; nun ist Schreiben erlaubt
        BCF     INTCON, GIE             ; verbieten aller Interrupts

        ; Die folgenden 5 Zeilen müssen genau so im Code stehen!!!
        MOVLW   0x55        
        MOVWF   EECON2                  ; schreibe 55h nach EECON2
        MOVLW   0xAA   
        MOVWF   EECON2                  ; schreibe AAh nach EECON2
        BSF     EECON1, WR              ; starte den Schreibzyklus

        ;BSF    INTCON, GIE             ; Interrupts wieder erlauben
        bcf     STATUS, RP0
        return

;***********************************************************************

        end
;***********************************************************************



zurück , PIC-Prozessoren , Elektronik , Homepage
Autor: sprut
erstellt: 05.12.2010
letzte Änderung: 10.08.2011