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
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:
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 |
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
incf
counter,
f bcf INTCON, T0IF
;
End
ISR, restore context and return to the main program |
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 . 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:
;***********************************************************************
W_save
Equ
0x20
;
auch
0xA0 ; Flag bits (FLAGS) ;***********************************************************************
goto Main ;***********************************************************************
InterruptServiceVector
incf
counter,
f bcf INTCON, T0IF
;
End
ISR, restore context and return to the main program ;***********************************************************************
;
interner
Taktgenerator
;
Interrupt
clrf
counter
;
TIMER0
muss eingestellt sein!
;
Interrupt
return ;***********************************************************************
loop0 loop1 loop2 loop4 loop5 sleep end |
Autor: sprut
erstellt 06.06.2003
letzte Änderung: 17.03.2004