Schaltung
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 z.B. die 16F84-Testplatine
oder
|
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.
TRISB befindet sich in der Bank1, deshalb muss vor dem Zugriff
auf TRISB in diese Bank umgeschaltet werden, danach schaltet man
in die Bank 0 zurück. Die Bankumschaltung erfolgt durch setzen/löschen
des Bits RP0 im Register STATUS.
bsf
STATUS, RP0 ; auf Bank
1 umschalten
movlw B'00000000' ; PortB alle output movwf TRISB bcf STATUS, RP0 ; auf Bank 0 schalten clrf PORTB ; alle LEDs ausschalten |
Um am Port B ein Lauflicht zu erzeugen muss man an diesem Port einen Spannungspegel ausgeben. Jedes Pin kann entrweder 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 obrigen 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 mu 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 rlf.
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
00000000
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 herausgeschoben worden, erschein sie einen rlf-Befehl später wieder im Bit 0 des PORTB-Registers. (wird durch das C-Flag hindurch geschoben.)
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ät. 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 4 MHz ausgelegt.
Fast alle Befehle eines PIC dauern einen Zyklus lang, wobei ein
Zyklus
4 externen PIC-Takten entspricht. Ein 4-MHz-PIC schafft also 1
Millionen
Befehle pro Sekunde, da in einer Sekunde 1 Millionen Zyklen bzw. 4
Millionen
externe Takte stattfinden. Ein Zyklus ist hier 1 Mikrosekunde (1
µs)
lang.
Ein Programm, das 1 Millisekunde verzögern soll, mu also
1000 Zyklen lang sein. Ein einfaches Beispiel wäre eine einfache
Folge
von 1000 NOP-Befehlen. Eleganter ist es aber, eine kurze Schleife
vielfach
durchlaufen zu lassen.
Wenn man eine Schleife aufbaut, die 9 Zyklen (also auch 9 µs)
lang ist, und diese Schleife 110 mal durchläuft, dann dauert das
990
Zyklen - das sind 0,99 ms. Da fehlen noch 10 µs zur vollen
Millisekunde,
aber auch der Sprung zur Warteroutine und zurück wird einige
Mikrosekunden
dauern, so das eine 990-µs-Warteschleife in der Praxis 1 ms
verzögert.
;**********************************************************
; Warteschleife 1 ms für einen 4MHz-PIC-Takt Wai
Wai2 nop
|
Die 9 Zyklen lange Warteschleife besteht aus 6 NOP-Befehlen, einem
DCFSZ-Befehl
und einem GOTO-Befehl. Der DCFSZ-Befehl dient gleichzeitig der
Zählung
der Schleifen. Nach 110 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, mu 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
|
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
|
Tip zum PIC16F62x
Wer dem moderneren 16F627 oder 16F628 anstelle des 16F84 einsetzen
möchte,
der achte bitte darauf, da beim Brennen 'LV-programming enable'
nicht
aktiviert ist. Ansonsten funktioniert RB4 nicht!
Man darf also nicht die Configuration aus dem HEX-File benutzen,
sondern
mu die Configuration im Brennprogramm manuell einstellen. Dabei
sollte auch ein eventuell aktiviertes Codeprotecton abgeschaltet
werden.
Programmlisting
Das Assembler-Programm ist auch in nachfolgender Tabelle zu sehen. Den überflüssigen Kommentar am Anfang habe ich grau gefärbt, damit man sich auf den eigentlichen Code konzentrieren kann.
list
p=16f84
;************************************************************** ;* ;* Pinbelegung ;* ---------------------------------- ;* PORTA: 0 ;* 1 ;* 2 ;* 3 ;* 4 ;* PORTB: 0 LED ;* 1 LED ;* 2 LED ;* 3 LED ;* 4 LED ;* 5 LED ;* 6 LED ;* 7 LED ;* ;************************************************************** ; ; sprut (zero) Bredendiek 05/2000 (mod. am 16.01.2002) ; ; Lauflicht am Port B ; ; Taktquelle: 4MHz ; ;************************************************************** ; Includedatei für den 16F84 einbinden ; #include <P16f84.INC> ; ; Configuration festlegen ; ; bis 4 MHz: Power on Timer, kein Watchdog, XT-Oscillator __CONFIG _PWRTE_ON & _WDT_OFF & _XT_OSC ; ; ab 4 MHz: Power on Timer, kein Watchdog, HS-Oscillator ; __CONFIG _PWRTE_ON & _WDT_OFF & _HS_OSC ; ;************************************************************** ; Variablennamen vergeben loops
Equ
0x22
; Zähler für Warteschleife
;**************************************************************
Init
; 1. LED einschalten bsf PORTB,0 ; LED an RB0 einschalten ; Lauflicht Loop
;**********************************************************
Wait
Wai
end |