Allgemeines
Initialisierung
Capturen
Beispiel
Ich beziehe mich
in diesem Text auf die PICs der Familie 16F87x.
Natürlich
kann
der Capture-Mode mit allen PICs verwendet werden,
die
wenigstens ein CCP-Modul besitzen,
aber
bei anderen PICs als den 16F87x können Adressen einzelner Register
auf anderen Adressen liegen oder es werden andere Pins verwendet. So
verwendet
der 16F628 z.B. anstelle von RC2 das Pin
RB3
als Capture-Eingang.
Wer andere PIC-Typen
einsetzen will, achte bitte auch die korrekten Adressen, Bänke und
Pins.
Der Capture-Eingang eignet sich zum genauen Messen des Zeitpunktes, zu dem ein externes Ereignis eintritt. Dazu wird der Timer1 auf das Zählen des Prozessortaktes eingestellt. Ändert sich der Zustand am Eingang RC2, so wird in diesem Augenblick der Zählerstand des Timers1 in das Captureregister kopiert (ge-'capturet'). Als auslösendes Ereignis steht zur Verfügung:
Initialisierung
Das Capture-Modul Nr.1 wird mit dem
Register
CCP1CON (Adresse 17h) gesteuert, das Capture-Modul Nr.2 mit dem
Register
CCP2CON (Adresse 1Dh).
CCP1CON: CAPTURE/COMPARE/PWM-1-CONTROL (ADDRESS 17h):
bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 | |
Name: | - | - | CCPxX | CCPxY | CCPxM3 | CCPxM2 | CCPxM1 |
|
|
|
|
|
|
|
|
|
|
Für den Capture-Mode ist CCPxM3=0
und
CCPxM2=1 zu setzen. Mit den Bits CCPxM1 und CCPxM0 wird
ausgewählt,
welches externe Ereignis das Capturen auslösen soll.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Für eine Capture-Funktion bei jeder steigenden Flanke muss also CCP1CON mit 1 geladen werden:
; CAPTURE MODE mit CCP1 initialisieren
CLRF
CCP1CON ;
CCP1-Modus
aus
BSF
CCP1CON,CCPxM0 ; CCP1-Modus in Capture Mode (L-H, 1:1)
Natürlich muss auch der Timer1 auf Zählen eingestellt werden. Außerdem sollte das zugehörige Pin als Eingang konfiguriert sein, was nach einem Reset ohnehin der Fall ist.
; RC2 auf Eingang stellen
BSF
STATUS,RP0 ; Bank1
BSF
TRISC, 2 ; RC2:
input=1
BCF
STATUS,RP0 ; Bank 0
Jedes Capture-Ereignis setzt das
Interruptflag
CCP1IF
(CCP2IF) im Register PIR1. Soll dadurch ein Interrupt
ausgelöst
werden, so ist ist das zugehörige Enable-Bit zu CCP1IE
(CCP1IE)
im Register PIE1 setzen. Das sollte erst erfolgen,
nachdem
die anderen Einstellungen abgeschlossen sind, und CCP1IF gelöscht
wurde, da jedes Verändern von CCP1CON versehentlich CCP1IF setzen
kann.
Zum Erlauben des Interrupts müssen
noch das Haupt-Interrupt-Flag GIE und das
Peripherie-Interrupt-Flag
PEIE
gesetzt sein.
Das Capturen kann man mit Polling (ständiges abfragen) oder durch einen Interrupt organisieren. Polling ist einfacher zu programmieren, verbraucht aber viel Rechenzeit.
Polling
Bei jedem Capturen wird das Bit CCP1IF
(CCP2IF) im Register PIR1 (Adresse 0Ch) gesetzt. Dieses Bit
kann
man in einer Schleife abfragen. Ist das Bit gesetzt, liest man den
gemessenen
16-Bit-Wert in zwei Hälften aus den Registern CCPR1H
(CCPR2H)
und CCPR1L (CCPR2L) aus. CCP1IF (CCP2IF)
muss
per Software geläscht werden. Die folgende Routine pollt, und
schreibt
ein empfangenes Zeichen nach 'Zeichen':
Capture
btfss
PIR1,CCP1IF
; sind Daten da ?
goto
Capture ; nein,
noch
keine Daten da
movfw
CCPR1H
; High Teil
movwf
CapHigh
; in den Speicher nach 'CapHigh' schreiben
movfw
CCPR1L
; Low Teil
movwf
CapLow
; in den Speicher nach 'CapLow' schreiben
bcf
PIR1,CCP1IF ; Flag löschen
Interrupt
Das CCP-Modul kann beim Capturen einen
Interrupt auslösen. Damit fordert er dazu auf, den gemessenen Wert
abzuholen. Sollen Interrupts genutzt werden, müssen Interrupts
generell
erlaubt werden (GIE=1), Peripherie-Interrupts erlaubt werden
(PEIE=1)
und im speziellen muss der Empfängerinterrupt freigeschaltet
werden (CCP1IE=1 bzw. CCP2IE=1).
;Interrupts vorbereiten
BSF
STATUS,RP0 ; Bank1
BSF
PIE1,CCP1IE ; Enable CCP1
interrupts
BCF
STATUS,RP0 ; Bank 0
clrf
PIR1
;
alle
Interruptflags löschen
clrf
PIR2
BSF
INTCON,GIE ; generell
Interrupts
erlauben
BSF
INTCON,PEIE ; Interrupts von
Peripheriegeräten erlauben
Eine Interruptroutine die die gemessene Zeit in die Register 'CapHigh' und 'CapLoe' kopiert könnte wie folgt aussehen:
org
4
;
Interrupt
beginnt immer bei Adresse 4
int
movwf
w_temp
; status retten
swapf STATUS,w
movwf
status_temp
;Capture-Interrupt?
btfss
PIR1,CCP1IF
goto
intEnde ;
Interrupt
kam von wo anders
movfw
CCPR1H
; High Teil
movwf
CapHigh
; in den Speicher nach 'CapHigh' schreiben
movfw
CCPR1L
; Low Teil
movwf
CapLow
; in den Speicher nach 'CapLow' schreiben
bcf
PIR1,CCP1IF ; Flag löschen
intEnde
;
geretteten
Status wieder zurückschreiben
swapf
status_temp,w
movwf STATUS
swapf w_temp,f
swapf w_temp,w
retfie
Eines meiner Projekte ist ein Drehzahlmesser für Modellflugzeuge mit Zweiblattluftschraube, der sich natürlich auch an andere Anwendungsfälle anpassen lässt. Die Messung erfolgt mit dem Capture-Modul eines PIC16F628.
Autor: sprut
erstellt: 03.07.2001