Schaltung
Dieses Lernbeispiel ist eine exakte Kopie des 18F8720-Lauflichts,
umgesetzt mit dem 18F242. Wer das 18F8720-Lauflicht schon durchgenommen
hat, findet hier nichts Neues.
Da der 18F424 kein PortD hat, verwende ich das PortB. Alle acht Pins des Port B werden mit Leuchtdioden versehen, die über 1 kOhm Widerständen mit Masse verbunden sind. Damit zeigen die LEDs die Ausgangspegel des Port B an. Es eignet sich dafür die 28-Pin-Testplatine. |
Programmablauf
Um am Port B ein Lauflicht zu erzeugen muss man:
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 PortB befinden sich im
Register
TRISB. Um PortB als Ausgang nutzen zu können, müssen also
alle
8 Bit des TRISB-Registers auf 0 gesetzt werden.
clrf
TRISB
;
PortB
alle output clrf PORTB ; alle LEDs ausschalten |
Um am Port B ein Lauflicht zu erzeugen muss man an diesem Port einen Spannungspegel ausgeben. Jedes Pin kann entweder 0V oder 5V ausgeben. Im obrigen Stromlaufplan sieht man, das die LEDs über einen Widerstand an den Pins des PORTB und mit dem anderen Anschluss mit Masse verbunden sind. Gibt ein Pin 0V aus, dann leuchtet die LED nicht. Gibt das Pin aber 5V aus, dann fließt ein Strom durch den Widerstand und die LED nach Masse, wodurch die LED leuchtet. Die von den 8 Pins des PortB ausgegebenen Spannungspegel stellt man ein, indem man die zugehörigen 8 Bits des Registers PORTB setzt (1) oder löscht (0). Eine 1 bewirkt 5V am zugehörigen Pin, eine 0 bewirkt 0V.
Im der letzten Zeile des obigen Listings werden mit einem clrf-Befehl
alle
Bits
des PORTB auf 0 gesetzt, anfangs sind also alle LEDs aus.
Will
man die LED am Pin RB0 einschalten, so muss man das Bit0 von PORTB
auf 1 setzen:
; 1. LED einschalten
bsf PORTB,0 ; LED an RB0 einschalten |
Um ein Lauflicht zu erzeugen, verschiebt man diese 1 nun innerhalb
des
Registers PORTB mit Hilfe des Rotierbefehls rlncf.
Dadurch wandert die 1 in PORTB jedesmal um eine Stelle nach links,
und es leuchtet jedesmal eine andere LED auf:
00000001
00000010
00000100
...
01000000
10000000
00000001
...
; Lauflicht
Loop |
Das Verschieben erfolgt in einer Endlosschleife, die durch eine Warteroutine (Wait) soweit abgebremst wird, dass ein Durchlauf der Schleife ca. 1/4 Sekunde dauert. Ist nach 7 Schleifendurchläufen die 1 links aus dem Register PORTB heraus geschoben worden, erscheint sie wieder im Bit 0 des PORTB-Registers.
Configuration
Wenn man dem Brennprogramm P18 keine Config-Einstellungen vorschreibt,
dann verwendet es die Microchip-Standardeinstellungen, und die sind
nicht
gerade praxistauglich. folgende Probleme kommen da auf einen zu:
;Configuration bits CONFIG OSC = HS ; HS 20 MHz CONFIG PWRT = ON ; power up timer on CONFIG BOR = OFF ; brown out detect off CONFIG WDT = OFF ; watchdog off CONFIG LVP = OFF ; lvp off |
Warteschleife
Immer wieder erreichen mich eMails, in denen nach Warteschleifen
gefragt
wird.Oft benötigt man in einem Programm eine Wartezeit, die sich
mit
Software-Warteschleifen einfach realisieren lässt. Sicher
wäre
die Nutzung des Hardware-Timers 'professioneller', es wäre aber
auch
das typische Schießen mit Kanonen auf Spatzen.
Ich realisiere die meisten 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 z.B. 250 mal.
Im nachfolgenden Fenster ist eine 1-ms-Routine zu sehen. Sie heißt 'Wai' und ist für einen PIC-Takt von 20 MHz ausgelegt.
Fast alle Befehle eines PIC dauern einen Zyklus lang, wobei ein
Zyklus
4 externen PIC-Takten entspricht. Ein 20-MHz-PIC schafft also 5
Millionen
Befehle pro Sekunde, da in einer Sekunde 5 Millionen Zyklen bzw. 20
Millionen
externe Takte stattfinden. Ein Zyklus ist hier 0,2 Mikrosekunde (0,2
µs)
lang.
Ein Programm, das 1 Millisekunde verzögern soll, muss also
5000 Zyklen lang sein. Ein einfaches Beispiel wäre eine einfache
Folge
von 5000 NOP-Befehlen. Eleganter ist es aber, eine kurze Schleife
vielfach
durchlaufen zu lassen.
Wenn man eine Schleife aufbaut, die 20 Zyklen (also auch 4 µs)
lang ist, und diese Schleife 249 mal durchläuft, dann dauert das
4980
Zyklen - das sind 0,996 ms. Da fehlen noch 4 µs zur vollen
Millisekunde,
aber auch der Sprung zur Warteroutine und zurück wird einige
Mikrosekunden
dauern, so das eine 996-µs-Warteschleife in der Praxis 1 ms
verzögert.
;**********************************************************
; Warteschleife 1 ms für einen 20-MHz-PIC-Takt Wai Wai2 nop
|
Die 20 Zyklen lange Warteschleife besteht aus 17 NOP-Befehlen, einem
DCFSZ-Befehl und einem GOTO-Befehl. Der DCFSZ-Befehl dient gleichzeitig
der Zählung der Schleifen. Nach 249 Schleifen wird der GOTO-Befehl
übersprungen, und die 1-ms-Warteroutine verlassen.
Diese 1-ms-Kernroutine ist taktfrequenzabhängig. Wird der PIC
mit einem höheren oder niedrigeren Takt versorgt, muss die
1-ms-Routine
mehr oder weniger Befehle/Schleifen enthalten. Nachfolgende Tabelle
gibt
eine Orientierung:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Dementsprechend ist also der in loops2 zu ladende Wert für die Schleifenanzahl zu verändern, und eventuell auch ein zusätzlicher NOP-Befehl einzufügen.
Da in der Praxis normalerweise längere Verzögerungen als 1
ms benötigt werden, ist die 1ms-Warteschleife in eine weitere
Schleife
eingebettet, die in folgendem Fenster ergänzt wurde:
;**********************************************************
; Warteschleife 250 ms Wait250 movlw D'250' ; 250 ms Pause movwf loops Wai Wai2 nop
|
Bevor die eigentliche 1-ms-Routine gestartet wird, wird die Zelle 'loops' mit einer Zahl zwischen 1 und 255 geladen. So oft wird die 1-ms-Schleife dann durchlaufen. In diesem Beispiel wird 'loops' mit 250 beschrieben, folglich wird die gesamte Warteroutine 'Wait250' insgesamt 250 ms = 1/4 s dauern.
Ein Aufruf der Routine mit ' CALL Wait250' führt also zu einer Wartezeit von 250 ms, danach läuft das Programm weiter.
Will man 10 ms oder 100 ms verzögern, lädt man loops mit
dem
Wert 10 bzw. 100, und springt dann zu Wai:
;**********************************************************
; Warteschleife 10 ms Wait10 movlw D'10' ; 10 ms Pause movwf loops goto Wai ;**********************************************************
;**********************************************************
Wai Wai2 nop
|
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 03/2006 ; ; Lauflicht am Port B ; ; Taktquelle: 20 MHz ; ;****************************************************************************** ; ; Pinbelegung ; ---------------------------------- ; PORTB: 0 LED ; 1 LED ; 2 LED ; 3 LED ; 4 LED ; 5 LED ; 6 LED ; 7 LED ; ;******************************************************************************
LIST
P=18F242 ;der Typ
des Prozessors ;******************************************************************************
CBLOCK
0x000 ;******************************************************************************
ORG
0x0000 ;******************************************************************************
Main: ; 1. LED einschalten
; Lauflicht ;******************************************************************************
Wait Wai ;******************************************************************************
END |