PIC-Lernbeispiel: Power-Sequencer


zurück zu Lernbeispiele , PIC-Prozessoren , Elektronik , Homepage


5 Leitungen werden im 2-Sekunden-Abstand nacheinander eingeschaltet

Ein Bekannter suchte eine einfache Lösung, um in seinem PowerGamer-PC, beim Einschalten die einzelnen Komponenten (Wasserkühlung, Lüfter, PC, Lautsprecherverstärker) nacheinander einzuschalten. Normalerweise kann man das durch eine Reihe von Verzögerungsschaltungen (mit RC-Gliedern) oder mit einem langsam getakteten Schieberegister lösen. Die einfachste Lösung ist aber ein kleiner PIC.
Mir ist völlig klar, das dabei 90% der Recourcen des PIC verschwendet werden, das spielt bei einem Preis von unter 3,- € aber keine Rolle.

Außerdem eignet sich das Ganze gut als Lernbeispiel für den 8-pin-PIC12F629.


Schaltung
 
Schaltbild Um möglichst viele Portpins als Schaltausgänge nutzen zu können, verwende ich den internen 4-MHz-Oszillator des PIC.

In der richtigen Schaltung sind alle benutzten I/O-Pins mit Treibertransistoren versehen, die Relais ansteuern.

Zum Testen und Lernen genügt es, die I/O-Pins mit LEDs zu verbinden, die über 1 kOhm Widerstände mit Masse verbunden sind. Damit zeigen die LEDs die Ausgangspegel des Ports an.

Es eignet sich z.B. die 12F6xx-Testplatine .


Der PIC12F629/675
Die niedlichen 12F6xx mit ihren 8 Pins weisen einige Besonderheiten auf.


Programmablauf
Um der Reihe nach die Pins GPIO0, 1, 2, 4 und 5 einzuschalten, muss man:

  1. Alle Bits des GPIO auf "0" setzen (alles ist aus)
  2. Port GPIO in Ausgabe-Mode schalten
  3. den internen 4-MHz-Oszillator kalibrieren
  4. Timer0 auf 125 Interrupts pro Sekunde einstellen, in einer Schleife jeweils 256 Interrupts abwarten
  5. nächtes IO-Pin einschalten
  6. Schritt 4 und 5 wiederholen, bis alle Pins an sind
  7. PIC in den Sleep-Modus setzen

interner Taktgenerator
Um möglichst viele Anschlusspins als I/O-Pins nutzen zu können, und um den Hardwareaufwand zu minimieren, benutze ich den internen 4-MHz-Taktgenerator des PIC12F6xx. Die Frequenz des Oszillators unterliegt exemplarabhängigen Schwankungen. Der Hersteller misst diese aber aus, und ermittelt einen Kalibrierwert (OSCAL). der in das Register OSCAL geschrieben werden muss, um den Oszillator auf 4 MHz abzustimmen. Dieser Kalibrierwert liegt als RETLW-Befehl auf der Adresse 0x3FF.
 
        ; interner Taktgenerator
        bsf     STATUS, RP0             ; Bank 1
        call    0x3FF
        movwf   OSCCAL                  ; 4-MHz-Kalibrierung
        bcf     STATUS, RP0             ; Bank 0

Nun weicht der interne Oszillator um weniger als 1% von den vorgegebenen 4 MHz ab. Für die Anwendung als Power-Sequenzer wäre ein so genauer Takt eigentlich nicht nötig.


Power on Timer
In der Regel aktiviere ich den Power-up-Timer der PICs. Der 'weckt' den PIC erst ca. 72ms nach dem Zuschalten der Betriebsspannung. Da ich in diesem besonderen Fall aber unmittelbar nach dem Einschalten die Kontrolle über die Treiberstufen haben möchte (die in der echten Anwendungs-Schaltung anstelle der LEDs angeschlossen sind) habe ich den Power-up-Timer deaktiviert.
 
; Configuration festlegen:
; kein Power up Timer, kein Watchdog, int-Oscillator, kein Brown out
        __CONFIG        _MCLRE_OFF & _PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _BODEN_OFF

Bei einem Nachbau hatte das zur Folge, dass der PIC nicht sicher startete. Ursache war ein prellender Betriebsspannungsschalter, der ein ordnungsgemäßes Power-On-Reset des PIC vereitelte. Um das zu vermeiden kann man die Betriebsspannung am PIC mit einem kleinen ELKO sieben, oder den Power-up-Timer doch aktivieren.
 
; Configuration festlegen:
; Power up Timer, kein Watchdog, int-Oscillator, kein Brown out
        __CONFIG        _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _BODEN_OFF


Timer0
Der Timer0 soll die Zeitbasis liefern. Dazu wird er mit dem Zyklustakt (1/4 des 4-MHz-PIC-Taktes) über einen 32:1 Vorteiler gespeist. Dadurch beträgt sein Eingangstakt 31,25kHz (1 MHz / 32). Da der Timer0 nur 8-Bit breit ist, läuft er immer nach 256 Eingangstakten über, und setzt das T0IF-Bit im INTCON-Register. Das passiert also 122 Mal pro Sekunde (32,125 kHz / 256 = 122).
 
;**********************************************************
; Initialisierung des Timer0
        ; TIMER0 muss eingestellt sein! 
        ; 32:1 bei 4 MHz -> 31 kHz
        ; Überlauf nach ca 8 ms
        ; 256 int in s Sekunden
        bsf     STATUS, RP0             ; Bank 1
        bcf     OPTION_REG, T0CS        ; interner Takt/4
        bcf     OPTION_REG, PSA         ; Vorteiler am Timer0
        bsf     OPTION_REG, PS2
        bcf     OPTION_REG, PS1
        bcf     OPTION_REG, PS0         ; Vorteiler 32:1
        bcf     STATUS, RP0             ; Bank 0

        ; Interrupt
        bcf     INTCON, T0IF            ; Int-Flag löschen
        bsf     INTCON, T0IE            ; Timer0-Int ein
        bsf     INTCON, GIE             ; Int aktiviert
 

Die I/O-Pins sollen im Abstand von ca. 2 Sekunden aktiviert werden. Ich benutze dazu eine Interruptroutine, die vom Timer0 122 mal pro Sekunde aufgerufen wird. Diese Routine erhöht den Wert eines 8-Bit-Registers (Counter) jeweils um 1.
 
;***********************************************************************
        org     0x04

InterruptServiceVector
        movwf   W_save                  ; save W
        swapf   STATUS,W
        bcf     STATUS, RP0             ; Bank 0
        movwf   Status_save

        incf    counter, f
        btfsc   STATUS, Z
        bsf     weiter

        bcf     INTCON, T0IF

        ; End ISR, restore context and return to the main program
        swapf   Status_save, w
        movwf   STATUS
        swapf   W_save,f                ; restore W without corrupting STATUS
        swapf   W_save,w
        retfie
 

Immer wenn dieses 8-Bit Register (Counter) überläuft (also immer nach 256 Zyklen) wird ein bestimmtes Bit ('weiter') gesetzt. Das passiert alle 2 Sekunden (256 / 122 Hz = 2,09 s)

Das Hauptprogramm fragt das 'weiter'-Bit ständig ab. Immer wenn es gesetzt ist, schaltet es ein weiteres Output-Pin ein, und löscht das 'weiter'-Bit wieder.
Wenn alle Output-Pins aktiv sind, geht der PIC in den Schlafmodus.
 
loop0
        btfss   weiter
        goto    loop0
        bcf     weiter
        bsf     GPIO,0          ; erste Leitung 

loop1
        btfss   weiter
        goto    loop1
        bcf     weiter
        bsf     GPIO,1          ; nächste Leitung

.
.
.

        sleep


Programmlisting

Das Assembler-Programm ist auch in nachfolgender Tabelle zu sehen.
 
        list p=12f629
;***********************************************************************
;*      Pinbelegung
;*      ---------------------------------- 
;*      GP:     0 > out 0
;*              1 > out 1
;*              2 > out 2
;*              3 > out 3
;*              4 > out 4
;*              5 > out 5
;* 
;***********************************************************************
;
;sprut (zero) Bredendiek 06/2003
;
; Power-Sequencer mit 12F629
;       die Pins GP0..GP5 werden mit 2 Sekunden verzögerung der Reihe 
;       auf High gelegt
;
; Prozessor 12F629 
;
; Prozessor-Takt 4 MHz intern
;
;
;***********************************************************************
; Includedatei für den 12F629 einbinden

        #include <P12f629.INC>

        ERRORLEVEL      -302            ;SUPPRESS BANK SELECTION MESSAGES

; Configuration festlegen:
; kein Power up Timer, kein Watchdog, int-Oscillator, kein Brown out
        __CONFIG        _MCLRE_OFF & _PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _BODEN_OFF
 

;***********************************************************************
; 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)
BYTE            equ     0x24            ; via PS-2 empfangenes Byte
counter         equ     0x25            ; Misc counter
 

; Flag bits (FLAGS)
#define weiter          Flags, 0        ; nächste Leitung einschalten
 

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

        goto    Main

;***********************************************************************
        org     0x04

InterruptServiceVector
        movwf   W_save                  ; save W
        swapf   STATUS,W
        bcf     STATUS, RP0             ; Bank 0
        movwf   Status_save

        incf    counter, f
        btfsc   STATUS, Z
        bsf     weiter

        bcf     INTCON, T0IF

        ; End ISR, restore context and return to the main program
        swapf   Status_save, w
        movwf   STATUS
        swapf   W_save,f                ; restore W without corrupting STATUS
        swapf   W_save,w
        retfie
 
 

;***********************************************************************
; 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
        clrf    TRISIO                  ; alle outnput
        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

        ; TIMER0 muss eingestellt sein! 
        ; 32:1 bei 4 MHz -> 31 kHz
        ; Überlauf nach ca 8 ms
        ; 256 int in s Sekunden
        bsf     STATUS, RP0             ; Bank 1
        bcf     OPTION_REG, T0CS        ; interner Takt/4
        bcf     OPTION_REG, PSA         ; Vorteiler am Timer0
        bsf     OPTION_REG, PS2
        bcf     OPTION_REG, PS1
        bcf     OPTION_REG, PS0         ; Vorteiler 32:1
        bcf     STATUS, RP0             ; Bank 0

        ; Interrupt
        bcf     INTCON, T0IF
        bsf     INTCON, T0IE
        bsf     INTCON, GIE             ; Int aktiviert

        return
 
 

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

loop0
        btfss   weiter
        goto    loop0
        bcf     weiter
        bsf     GPIO,0

loop1
        btfss   weiter
        goto    loop1
        bcf     weiter
        bsf     GPIO,1

loop2
        btfss   weiter
        goto    loop2
        bcf     weiter
        bsf     GPIO,2

loop4
        btfss   weiter
        goto    loop4
        bcf     weiter
        bsf     GPIO,4

loop5
        btfss   weiter
        goto    loop5
        bcf     weiter
        bsf     GPIO,5

        sleep

        end


zurück zu Lernbeispiele , PIC-Prozessoren , Elektronik , Homepage

Autor: sprut
erstellt 06.06.2003
letzte Änderung: 17.03.2004