CCP モジュールには 3 つのモードがあり、それぞれの用途によって使い分けて使用することができます。
CCP モジュールをコンペア・モードで動作させると、タイマ 1 のカウンタ TMR1L、TMR1H が レジスタ CCPRxL、CCPRxH で指定した値と等しくなったときに、何らかのアクションを行います(CCP モジュールが 2 つある場合、x に 1 または 2 が入ります)。
TMR1L, TMR1H (タイマ 1 のカウンタ)
↓
常に比較 → 一致したならアクション発生(アクションは 4 パターンから選択)
↑
CCPRxL, CCPRxH (ユーザが自由に設定する)
どんなアクションを行なうかは、CCPxCON<CCPxM0> ~ <CCPxM3> で指定します。
CCPxCON <CCPxM3(3)> ~ <CCPxM0(0)> |
アクション |
---|---|
1000 | 割り込みが発生と同時に PIRx<CCPxIF> ビットがセットされる。CCPx ピンの出力を H レベルにする。 |
1001 | 割り込みが発生と同時に PIRx<CCPxIF> ビットがセットされる。一致したら CCPx ピンの出力を L レベルにする。 |
1010 | 割り込みが発生と同時に PIRx<CCPxIF> ビットがセットされる。 |
1011 (SpecialEventTrigger) |
割り込みが発生と同時に PIRx<CCPxIF> ビットがセットされる。CCP1 の場合はタイマ 1 をリセットする。CCP2 の場合はタイマ 1 をリセットし、A/D コンバータを起動する。 |
コンペア・モードを有効にするには、タイマ 1 の設定をクロック同期モードにしておく必要があります。 また、CCPx ピンの出力を利用する場合は、TRISC レジスタで出力ピンに設定しておく必要があります(CPP1 ピンを出力にするには TRISC<2> ビットをクリアします)。 日本語のデータシートには、コンペアモードを使用するときは CCPx ピンを必ず出力に設定するように書かれています(2002年現在)が、SpecialEventTrigger などでインターバルタイマを実現する場合などは、CCPx ピンの出力を利用しないので、TRISC レジスタの設定を行なう必要はありません(PIC16F873 で動作確認済み)。
CCP モジュールからの割り込みは、割り込みフラグビット PIR1<TMR1IF(0)> をセットしません。 その代わり、PIRx<CCPxIF> がセットされます。 CCP モジュールによる割り込みが発生すると、タイマ 0 による割り込みの時と同様に 0x04 番地へ強制的にジャンプします。 どの原因により割り込みが発生したかを調べるには、どのフラグがセットされているかを確認する必要があります。 割り込み時に、ソフトウェア側で明示的に PIRx<CCPxIF> フラグをクリアする必要があります。 このフラグをクリアするのを忘れると、割り込みルーチンから retfie した瞬間にまた割り込みが発生してしまうので、永遠に割り込みルーチンをループして実行し続けることになってしまいます。
1011 (SpecialEventTrigger) に設定しておくと、割り込みが発生すると同時にタイマ 1 をリセットしてくれるので、正確なインターバルタイマを作成することができます。 次の例は、10MHz クロックで、10msec ごとに割り込み処理を行っています。
LIST P=PIC16F84
INCLUDE "P16F84.INC"
__CONFIG _HS_OSC & _WDT_OFF
;ウォッチドッグ・タイマ OFF
ORG 0 ;リセット後のエントリポイント
GOTO Start
ORG 4 ;割り込みルーチンのエントリポイント
GOTO Interrupt
;==============================================================================
; エントリポイント
;==============================================================================
Start
;CCP1 のコンペアモード(SpecialEventTrigger)による割り込みの設定
;Setup Timer1 (内部クロックでカウントに設定)
movlw B'00000001'
;プリスケーラ 1:1
;オシレータ停止
;内部クロック
movwf T1CON
;Setup CCP1 (コンペアモードの SpecialEventTrigger に設定)
movlw B'00001011'
movwf CCP1CON
;Setup CCP1 Counter
movlw H'30' ;インターバルによって目標カウンタ値を設定 (次は 10 MHz の場合)
movwf CCPR1H ; 0x30D4 = 12500 Count ( 5msec ごとに割り込みの場合)
movlw H'D4' ; 0x61A8 = 25000 Count (10msec ごとに割り込みの場合)
movwf CCPR1L
;割り込み許可
bsf STATUS, RP0 ;Go to Bank1
bsf PIE1, CCP1IE ;CCP1 割り込みイネーブル
bcf STATUS, RP0 ;Back to Bank0
bsf INTCON, PEIE ;周辺機能割り込みイネーブル (CCP1は周辺機能)
bsf INTCON, GIE ;全体の割り込みイネーブル
;******************************************************************************
; Main Loop
;******************************************************************************
MainLoop
;■■■ ここにメインの処理を書く ■■■
;Nothing to do.
goto MainLoop
;******************************************************************************
; 割り込み時に行なう処理
;******************************************************************************
InterruptProcedure
bcf PIR1, CCP1IF ;CPP1 コンペアモード 割り込みフラグクリア
;■■■ 割り込み時に行ないたい処理をここに自由に記述 ■■■
return
;******************************************************************************
; 割り込みのエントリポイント (レジスタの保存復帰、InterruptProcedure 呼び出し)
;******************************************************************************
Interrupt
movwf w_temp
movf STATUS, w
bcf STATUS, RP0 ;Bank 0
movwf status_temp
call InterruptProcedure ;このルーチンの中で独自の処理を記述する
bcf STATUS, RP0 ;Bank 0
movf status_temp, w
movwf STATUS
swapf w_temp, f
swapf w_temp, w
retfie
;******************************************************************************
; Directive 'End of Program'
;******************************************************************************
END