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); // 更新間隔 } }