まくまくいろいろノート
CCP (Compare/Capture/PWM) モジュール ─ PIC めもめも
2002-08-01

CCP モジュールのモード

CCP モジュールには 3 つのモードがあり、それぞれの用途によって使い分けて使用することができます。

コンペア・モード
タイマ 1 のカウントがある値になったときに、何らかのアクションを行います。タイマ 1 の設定をクロック同期モードにしておく必要があります。タイマ 1 を正確なインターバルタイマとして利用できるようになります。
キャプチャー・モード
CCP1 (あるいは CCP2) ピンからの入力を元にして、タイマ 1 のカウントを CCPR1H、CCPR1L レジスタ(あるいは CCPR2H、CCPR2L レジスタ)にコピーします。
パルス幅変調モード (PWM: Pulse Width Modulation)
周期的なパルスを発生させ外部機器を操作します。Duty の指定によりパルス幅を調整できます。

コンペア・モードの 4 つのアクション

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 モジュールからの割り込み

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
2002-08-01