PIC-Lernbeispiel: Wechselblinklicht

mit PIC18F66J60

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


Ein Blinklicht mit 2 LEDs am Port D.
als Beispiel für einen 3,3V-PIC benutze ich den PIC18F66J60 im 64-poligen TQFP-Gehäuse.

Was ist ein 3,3V-PIC?
So bezeichne ich alle PICs, die mit einer Spannung bis maximal 3,6V betrieben werden dürfen. Das sind die folgenden Familien:
Alle anderen PIC-Familien lassen sich mit bis zu 5,5V- betreiben, ich nenne Sie 5V-PICs.
Bei allen 5V-PICs läuft der gesamte Chip mit einer einheitlichen Betriebsspannung. Bei den 3,3V-PICs hat der Prozessorkern dagegen seine eigene Stromversorgung mit einer Spannung von maximal 2,5V. Diese Extraspannung lässt sich an einem speziellen Pin (Vddcore) einspeisen, sie kann aber auch von einem Spannungsregler auf dem Chip aus Vdd erzeugt werden, was deutlich einfacher ist. Um den internen Spannungsregler zu aktivieren, muss das ENVREG-Pin mit Vdd verbunden werden, und zwischen dem Pin Vddcore/Vcsp und Vss ein kleiner Elko eingesetzt werden.

Schaltung
 
Stromlaufplan

Zwei Pins des Port D werden mit Leuchtdioden versehen, die über 330-Ohm Widerständen mit Masse verbunden sind. Damit zeigen die LEDs die Ausgangspegel der Pins RD0 und RD1 an.

An der Schaltung fällt auf, dass keine Taktquelle zu sehen ist. Ich benutze den internen 31kHz-Generator des PIC18F66J60.

Ein weiterer wichtiger Aspekt bei den 3,3V-PICs ist die Stromversorgung. Zunächst einmal besitzt ein großer PIC eine stattliche Anzahl an Vdd- und Vss-Pins, ich habe alle angeschlossen.
Dann muss noch die abgesenkte Betriebsspannung für den Prozessorkern erzeugt werden, der keine 3,3V verträgt. Ich verwende den internen 2,5V-Regulator des PIC,den ich mit Vdd am ENVREG-Pin aktiviert habe. Der Kondensator C1 dient der Stabilisierung/Siebung der 2,5V am Regulatorausgang.

Die Gesamtschaltung darf mit maximal 3,6V gespeist werden. Die mindestens nötige Betriebsspannung ist 2,7V, da ansonsten der Spannungsregler für den Prozessorkern keine ausreichende Spannung mehr abgibt.


Programmablauf
Um am Port D ein Wechselblinklicht zu erzeugen muss man:

  1. Port D in Ausgabe-Mode schalten
  2. Alle Bits bis auf das LSB auf "0" setzen, das LSB aber auf "1" (LED1 ist an)
  3. eine feste Zeit in einer Warteschleife warte
  4. Alle Bits des Port D eine Position nach rechts schieben. Nun ist LED2 an..
  5. eine feste Zeit in einer Warteschleife warte
  6. Alle Bits des Port D eine Position nach links schieben. Nun ist LED1 an...
  7. ab Schritt 3 wird alles wiederholt

Mit einem Port LEDs ansteuern
(hier ist eine detaillierte Beschreibung der I/O-Pins)
Port-Pins sind entweder als Eingänge oder als Ausgänge nutzbar. Nach dem Einschalten des PIC (oder einem Reset) sind alle Port-Pins als Eingänge konfiguriert. Um sie als Ausgänge nutzbar zu machen, muss man sie zunächst auf die Ausgangsfunktion umschalten. Dazu muss man bestimmte Steuerbits setzen bzw. löschen. Jedes Port-Pin hat so ein Steuerbit. Ist es auf '1' gesetzt, dann funktioniert das Pin als Eingang, ist es aber auf '0' gesetzt, so ist es ein Ausgang.

Die 8 Steuerbits für die 8 Pins des PortD befinden sich im Register TRISD. Um PortD als Ausgang nutzen zu können, müssen also alle 8 Bit des TRISD-Registers auf 0 gesetzt werden.
 
        clrf    TRISD           ; PortD alle output
        clrf    PORTD           ; alle LEDs ausschalten

Um am Port D ein Wechselblinklicht zu erzeugen muss man an diesem Port einen Spannungspegel ausgeben. Jedes Pin kann entrweder 0V oder 3,3V (Vdd) ausgeben. Im obigen Stromlaufplan sieht man, dass die LEDs über einen Widerstand an den Pins des PORTD  und mit dem anderen Anschluss mit Masse verbunden sind. Gibt ein Pin 0V aus, dann leuchtet die LED nicht. Gibt das Pin aber 3,3V aus, dann fließt ein Strom durch den Widerstand und die LED nach Masse, wodurch die LED leuchtet. Die von den Pins des PortD ausgegebenen Spannungspegel stellt man ein, indem man die zugehörigen 8 Bits des Registers PORTD setzt (1) oder löscht (0). Eine 1 bewirkt 3,3V am zugehörigen Pin, eine 0 bewirkt 0V.

Im der letzten Zeile des obigen Listings werden mit einem clrf-Befehl alle Bits des PORTD auf 0 gesetzt, anfangs sind also alle LEDs aus. Will man die LED am Pin RD0 einschalten, so muss man das Bit0 von PORTD auf 1 setzen:
 
; 1. LED einschalten 

        bsf     PORTD,0         ; LED an RD0 einschalten

Um ein Wechselblinklicht zu erzeugen, verschiebt man diese 1 nun innerhalb des Registers PORTD mit Hilfe der Rotierbefehle rlncf und rrncf abwechselnd hin und her.
Dadurch wandert die 1 in PORTD ständig zwischen RD0 und RD1 hin und her, und es leuchten die LEDs D1 und D2 wechselseitig auf:

00000001
00000010
00000001
00000010
...
...
 
; Lauflicht
Loop
    call    Wait          ; Wartezeit
    rlncf   PORTD,f       ; laufen zur 2.LED
    call    Wait          ; Wartezeit
    rrncf   PORTD,f       ; laufen zur 1.LED
    goto    Loop   

Das Verschieben erfolgt in einer Endlosschleife, die durch eine Warteroutine (Wait) soweit abgebremst wird, dass ein Durchlauf der Schleife ca. 2 x 1/4 Sekunde dauert. 


Configuration
Wenn man dem Brennprogramm US-Burn keine Config-Einstellungen vorschreibt, dann verwendet es die Microchip-Standardeinstellungen, und die sind nicht gerade praxistauglich. Deshalb sollte man gleich im HEX-File eine andere Config einbauen. Das sieht dann so aus:  

;******************************************************************************
;Configuration bits
    CONFIG    FOSC2  = OFF    ; intrc 31 kHz
    CONFIG    WDT    = OFF    ; watchdog off
    CONFIG    DEBUG  = OFF
    CONFIG    XINST  = OFF
    CONFIG    CP0    = OFF
    CONFIG    ETHLED = OFF


Wichtig ist vor allem, dass man den Watchdog abschaltet (WDT = OFF) und den internen 31kHz-Oszillator als Takt auswählt (FOSC2 = OFF).


Warteschleife

Ich realisiere die Verzögerungen im Programm mit Hilfe einer 1-Millisekunden-Warteschleife. Das ist also eine Unterprogramm, das genau 1 ms lang läuft, und dann zum rufenden Programm zurückkehrt. Mit Hilfe einer Schleife rufe ich dieses 1-ms-Warteprogramm vielfach auf - für 1/4 Sekunde rufe ich es 250 mal.

Im nachfolgenden Fenster ist eine 1-ms-Routine zu sehen. Sie heißt 'Wai' und ist für einen PIC-Takt von 31 kHz ausgelegt.

Fast alle Befehle eines PIC dauern einen Zyklus lang, wobei ein Zyklus 4 externen PIC-Takten entspricht. Ein 31-kHz-PIC schafft also 7750 Befehle pro Sekunde, da in einer Sekunde 7750 Zyklen bzw. 31000 externe Takte stattfinden. Ein Zyklus ist hier 129 Mikrosekunde (129 µs) lang.
Ein Programm, das 1 Millisekunde verzögern soll, muss also 7,75 Zyklen lang sein. Meine Wai-Schleife ist mit 8 Zyklen etwas zu lang, aber für ein einfaches LED-Blinklicht ist der Fehler vertretbar.

Wie oft die 1ms-lange Wai-Schleife durchlaufen wird, das hängt von der Variablen loops ab. Für eine 250ms-Wartezeit springe ich die Marke Wait an. Hier wird loops mit 250 geladen, und dann zu Wai weiter gegangen. Dadurch wird Wai genau 250 mal durchlaufen, wodurch sich 250ms Verzögerung ergibt.

;******************************************************************************
; Warteschleife 250 ms
; 31 kHZ Takt
; 8 Zyklen pro loop = 1ms

Wait
    movlw    D'250'        ; 250 ms Pause
    movwf    loops    

Wai                        ; Zeitkonstante für 1ms (8 Takte)
    nop
    nop
    nop    
    nop              
    decfsz  loops, F       ; 250 ms vorbei?
    goto    Wai            ; nein, noch nicht
    retlw   0              ; das Warten hat ein Ende


        .



Programmlisting

Das Assembler-Programm ist auch in nachfolgender Tabelle zu sehen. Den überflüssigen Kommentar habe ich grau gefärbt, damit man sich auf den eigentlichen Code konzentrieren kann.
 
;******************************************************************************
; sprut (zero) Bredendiek 02/2006
;
; Wechselblinklicht am Port D,  RD0 & RD1
;
; Taktquelle: 31 kHz intern
;
;******************************************************************************
;
; Pinbelegung
;    ----------------------------------    
;    PORTD:    0 LED 1       
;              1 LED 2        
;
;******************************************************************************

    LIST P=18F66J60            ;der Typ des Prozessors
    #include <P18F66j60.INC>    ;processor-spezifische Variablendefinitionen

;******************************************************************************
;Configuration bits
    CONFIG    FOSC2  = OFF    ; intrc 31 kHz
    CONFIG    WDT    = OFF    ; watchdog off
    CONFIG    DEBUG  = OFF
    CONFIG    XINST  = OFF
    CONFIG    CP0    = OFF
    CONFIG    ETHLED = OFF


;******************************************************************************
;Variable definitions

    CBLOCK    0x000
    loops        
    ENDC

;******************************************************************************
;Reset vector
; hier beginnt der Prozessor beim Reset

    ORG    0x0000
    goto    Main           ;go to start of main code

;******************************************************************************
;Start of main program

Main:
; Port D kmnfigurieren
; alle Pins sind output
    clrf    TRISD
    clrf    PORTD         ; alle LEDs ausschalten

; 1. LED einschalten
    bsf    PORTD,0        ; LED an RD0 einschalten

; Lauflicht
Loop
    call    Wait          ; Wartezeit
    rlncf    PORTD,f      ; laufen zur 2.LED
    call    Wait          ; Wartezeit
    rrncf    PORTD,f      ; laufen zur 1.LED
    goto    Loop    

;******************************************************************************
; Warteschleife 250 ms
; 31 kHZ Takt
; 8 Zyklen pro loop = 1ms

Wait
    movlw    D'250'        ; 250 ms Pause
    movwf    loops    

Wai                        ; Zeitkonstante für 1ms (8 Takte)
    nop
    nop
    nop    
    nop             
    decfsz  loops, F       ; 250 ms vorbei?
    goto    Wai            ; nein, noch nicht
    retlw   0              ; das Warten hat ein Ende

;******************************************************************************
;End of program

    END



zurück zu 18F-Lernbeispiele , PIC-Prozessoren , Elektronik , Homepage
Autor: sprut
erstellt: 24.09.2007
letzte Änderung 24.09.2007