PIC18F14K50の基本動作から応用プログラムまでを学びます。

ホーム
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
    
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
CCP コンペア

18F26J50には、ECCP (Enhanced Capture/Compare/PWM)が2セット組み込まれています。なお、2つのECCPは同じ構造をしているため、両方に該当する場合はECCPxと表記しています。関連レジスターも同様に「x」には、1または2の番号が入ります。ECCPのCompareモードは、タイマー1またはタイマー3を常時モニターしています。どちらのタイマーを使用するかは、表に示すように TCLKCON、<1:0>で指定します。タイマーがCCPRxH / CCPRxLで定められたカウントに達すると、以下の5種類のいずれかの動作を行います。

ECCPのCompareモードは、タイマー1またはタイマー3を常時モニターしています。どちらのタイマーを使用するかは、表に示すように TCLKCON、<1:0>で指定します。タイマーがCCPRxH / CCPRxLで定められたカウントに達すると、以下の5種類のいずれかの動作を行います。

TCLKCON < T3CCP2:T3CCP1 >
1:0 0:1 0:0
ECCP1 Timer3 Timer1 Timer3
ECCP2 Timer3 Timer3 Timer1

Special Eventを利用すると連携するタイマーカウンターを16ビットまでの任意の分周カウンターにすることができます。なお、CCP1(RC5)をCCPの出力に使用する場合には、TRISCのビットを"0"出力に設定する必要があります。 この機能を活用することで、精度の高いクロックを分周し時計や、周波数カウンターの基準時間を定期的に発生させることが可能です。注意点として、Special Event が発生しタイマーをゼロにリセットするので、CCPR1H / CCPR1Lにプリセットする値は(必要分周数ー1)となります。

*注意*
出力ピンのCCPxはPeripheral Pin Select (PPS)機能で任意のRPnピンに指定することができます。CCPx出力に使用する場合には、該当のTRISCのビットを"0"出力に設定し、ANCONxビットも”1”デジタルにする必要があります

関連するレジスター一覧を下表に示します。

レジスタ bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
RCON IPEN CM RI TO PD POR BOR
INTCON GIEH GIEL TMR0IE INT0IE RBIE TMR0IF INT0IF RBIF
PIR1 ADIF RC1IF TX1IF SSP1IF CCP1IF TMR2IF TMR1IF
PIE1 ADIE RC1IE TX1IE SSP1IE CCP1IE TMR2IE TMR1IE
IPR1 ADIP RC1IP TX1IP SSPIP CCP1IP TMR2IP TMR1IP
PIR2 OSCFIF CM2IF CM1IF USBIF BCL1IF HLVDIF TMR3IF CCP2IF
PIE2 OSCFIE CM2IE CM1IE USBIE BCL1IE HLVDIE TMR3IE CCP2IE
IPR2 OSCFIP CM2IP CM1IP USBIP BCL1IP HLVDIP TMR3IP CCP2IP
CCPxCON PxM < 1 - 0 > DCxB < 1 - 0 > CCPxM < 3 - 0 >
TCLKCON     T1RUN       T3CCP2 T3CCP1
ODCON1 ECCP2OD ECCP1OD
CCPRxL CCP Register x, Low Byte
CCPRxH CCP Register x, High Byte
レジスタ BIT 説明 1 0
RCON 7 IPEN 2レベルのインタラプト優先度 使用
INTCON 7 GIEH 高優先度インタラプトを使用許可 許可
6 GIEL 低優先度インタラプトを使用許可 許可
PIR1 1 CCP1IF CCP1 発生フラグ 発生  
PIE1 1 CCP1IE CCP1 インタラプトを使用許可 許可
IPR1 1 CCP1IP CCP1 インタラプト優先度
PIR2 0 CCP2IF CCP2 発生フラグ 発生  
PIE2 0 CCP2IE CCP2 インタラプトを使用許可 許可
IPR2 0 CCP2IP CCP2 インタラプト優先度
CCPxCON 3 CCPxM3 0000 =モジュール全体をOFF (初期値)
0010 =CCPxをトグル, 1000 =CCPxLOW, 1001 =CCPxをLOW
1010 =CCPxは変化せず、CCPxIFセット
1011 =Special Event を発生
2 CCPxM2
1 CCPxM1
0 CCPxM0
TCLKCON 1 T3CCP2 10 =CCP1,CCP2 両方ともタイマー3を使用する
01 =CCP1はタイマー1、CCP2はタイマー3を使用する
00 =CCP1はタイマー3、CCP2はタイマー1を使用する(初期値)
0 T3CCP1
ODCON1 1 ECCP2OD CCP1出力のオープンドレイン機能 有効 無効
0 ECCP1OD CCP2出力のオープンドレイン機能 有効 無効

プログラム例

タイマー1でシステムクロックをカウントし、CCPRxH / CCPRxLで定められたカウントに達すると、Special Eventを発生させるプログラムを作成しました。Special Eventの発生でタイマー1をリセットし同時にンタラプトを発生させ出力を反転(LEDを点滅)させています。比較する値を可変するためにVRの値をAD変換し、CCPRxH にセットしています。

<回路図>

<プログラム>

//  File name: CCP Comp
//  Description:
//  VRの値で出力する周波数が変化する  約 240Hz-1Hz
//  Timer1で内部クロックをカウントし、CCP1で比較する
//    AN0のAD変換値と一致で割込みが発生する
//    高優先割込み処理ルーチンで、LED0を反転し点滅させる。
//  Timer3で内部クロックをカウントし、CCP2で比較する
//    AN1のAD変換値と一致で割込みが発生する
//    低優先割込み処理ルーチンで、LED2を反転し点滅させる。
//  Notes: 4MHz内部クロック
//        LED0 RB0 LED2 RB2
//        LED1 RB1 LED3 RB3
//        Pot0 AN0(RA0)
//        Pot1 AN1(RA1)
//    Language: MPLAB xc8
//    Target: PIC18F26J50

#include <xc.h>
#define _XTAL_FREQ 4000000      // delay_ms(x) のための定義

#define   LED0   LATBbits.LATB0
#define   LED1   LATBbits.LATB1
#define   LED2   LATBbits.LATB2
#define   LED3   LATBbits.LATB3
//
     #pragma config WDTEN = OFF, PLLDIV = 2, STVREN = ON, XINST = OFF
     #pragma config CPUDIV = OSC1, CP0 = OFF
     #pragma config OSC = INTOSC, T1DIG = OFF
     #pragma config LPT1OSC = OFF, FCMEN = OFF, IESO = OFF
     #pragma config WDTPS = 32768
     #pragma config DSWDTOSC = INTOSCREF, RTCOSC = T1OSCREF
     #pragma config DSBOREN = OFF, DSWDTEN = OFF, DSWDTPS = 8192
     #pragma config IOL1WAY = OFF, MSSP7B_EN = MSK7
     #pragma config WPFP = PAGE_1, WPEND = PAGE_0, WPCFG = OFF
     #pragma config WPDIS = OFF

//----------------------高優先割込み------------------------
void interrupt Hi_Isr(void){
    if(PIR1bits.CCP1IF){            // CCP1からの割込みを確認
        PIR1bits.CCP1IF = 0;        // 割込みフラッグをクリア
            LED0 = !LED0;           // LED0を反転
            LED1 = !LED0;           // LED1を反転
    }
}
//-----------------低優先割込みの処理------------------------
void interrupt low_priority Lo_Isr(void){
    if(PIR2bits.CCP2IF){            //CCP2からの割込みを確認
        PIR2bits.CCP2IF = 0;        // 割込みフラッグをクリア
            LED2 = !LED2;           // LED2を反転
            LED3 = !LED2;           // LED3を反転
    }
}
//----------------------メインプログラム-------------------------
void main(void){
    OSCCON = 0b01100010;       // 内部クロック4Mhz
    LATB = 0;                  // PortCのすべてのビットを「0」
    TRISB = 0b11110000;        // LEDのポートを出力に設定
// ---------------- CCPの使用するタイマーを設定 ---------------
    TCLKCON = 0x01;            // CCP1はT1と、CCP2はT3と連携
// ---------------- CCP1の 設定 ------------------------
    CCP1CON = 0b00001011;      // スペシャルイベント
    CCPR1H = 0x0F;             // 繰返し周期の暫定設定
    CCPR1L = 0xFF;             //
    IPR1bits.CCP1IP = 1;       // 高優先割り込み
    PIE1bits.CCP1IE = 1;       // 割り込みを使用する。
    PIR1bits.CCP1IF = 0;
    T1CON = 0b00110001;        // T1は Fosc/4をPSで1/8してカウント
// ---------------- CCP2の 設定 ------------------------
    CCP2CON = 0b00001011;      // スペシャルイベント
    CCPR2H = 0xFF;             // 繰返し周期の暫定設定
    CCPR2L = 0xFF;             //
    IPR2bits.CCP2IP = 0;       // 低優先割り込み
    PIE2bits.CCP2IE = 1;       // 割り込みを使用する。
    PIR2bits.CCP2IF = 0;
    T3CON = 0b00110001;        // T3は Fosc/4をPSで1/8してカウント
// ---------------- ADC初期化 ------------------------
    ADCON1 = 0b00101100;        // 左詰 クロックFosc/4 12_TAD
    ADCON0 = 0b00000001;        // Vdd-Vss AN0(RA0) ADC_ON

    ANCON0 = 0b00011100;        // CH0,1をアナログ入力にする
    ANCON1 = 0b00011111;
// ---------------- 割込みの有効化 ------------------------
    RCONbits.IPEN=1;           // 2段階の割込みに設定
    INTCONbits.GIEH=1;         // 高優先割込みを許可
    INTCONbits.GIEL=1;         // 低優先割込みを許可
    while(1){
        ADCON0 = 0b00000001;    // AN0に接続
        ADCON0bits.GO = 1;      // AD変換開始
        while(ADCON0bits.GO);   // AD変換終了待ち
        CCPR1H = ADRESH;        // AD変換結果をCCP1繰返周期に

        ADCON0 = 0b00000101;    // AN1に接続
        ADCON0bits.GO = 1;      // AD変換開始
        while(ADCON0bits.GO);   // AD変換終了待ち
        CCPR2H = ADRESH;        // AD変換結果をCC2P繰返周期に
        __delay_ms(100);        // 更新間隔
    }
}