18F26J50には、ECCP (Enhanced Capture/Compare/PWM)が2セット組み込まれています。なお、2つのECCPは同じ構造をしているため、両方に該当する場合はECCPxと表記しています。関連レジスターも同様に「x」には、1または2の番号が入ります。 ECCP (Enhanced Capture/Compare/PWM)のPWM(Pulse Width Modulation) モードは、分解能10ビットのPWM 信号をタイマー2、または、タイマー4と連携して発生させることができます。PWM 出力モードには、4 種類がありますが、ここでは、 シングルPWMの説明です。
PWMの動作をCCP1とタイマー2の連携で説明しますが、他のCCPやタイマーでも動作自体は同じです。関連するレジスタの名称を読み変えてください。
PWMの繰り返し周期は、タイマーのPR2の設定値で決定し、デューティーサイクルはCCPR1LにDC1B <1:0>の2ビットをあわせた10ビットの値で決まります。タイマー(TMR2)とPR2の値が一致するとTMR2をリセットします。同時に、PWM出力を”1”にセットし、CCPR1LとDC1B <1:0>の値を、CCPR1Lと内部2ビットレジスタにコピーします。この値が、TMR2の値と一致するとPWM出力を”0”にリセットします。つまり、PR2の設定値の半分の値をCCPR1LとDC1B <1:0>にセットすればデューティー50%の波形が出力されます。
PWM出力は、PSTR1CONの該当ビットを「1」にすることで、1~4ピンまで増やすことが可能で、さらにそれらの極性を、CCP1M <3:0>で指定することも出来ます。TCLKCONでタイマー2を使用するか、タイマー4を使用するかを指定します。
*注意*
PWM 信号を出力するピンは、Peripheral Pin Select (PPS)機能で任意のRPnピンに指定することができます。CCPx出力に使用する場合には、該当のTRISCのビットを"0"出力に設定し、ANCONxビットも”1”デジタルにする必要があります。
RPOR0 = 14; // CCP1/P1A を RP0(RA0,AN0)に設定する TRISA.bitsTRISA0 = 0; // RA0 を出力に設定する ANCON0bits.PCFG0 = 1; // RA0,AN0 をデジタルに設定する
上図ではTimer2を使用していますがTimer4を選択することもできます。
CCP出力 | PPS 表記番号 |
---|---|
CCP1/P1A | 14 |
P1B | 15 |
P1C | 16 |
P1D | 17 |
CCP2/P2A | 18 |
P2B | 19 |
P2C | 20 |
P2D | 21 |
代表的なクロック周波数と、PWM繰り返し周波数の関係を表に示します。
4 Mhz | 48 Mhz | |||||||
---|---|---|---|---|---|---|---|---|
プリスケラ値 | 1:16 | 1:4 | 1:4 | 1:1 | 1:16 | 1:4 | 1:4 | 1:1 |
PR2 | 0xFF | 0xFF | 0xF9 | 0xFF | 0xFF | 0xFF | 0xF9 | 0xFF |
PWM周波数 | 244Hz | 976Hz | 1KHz | 3.9KHz | 2.9KHz | 11.7KHz | 12KHz | 46.9KHz |
高低2レベルの優先度を使用するCCP に関連するレジスターを一覧で説明します。
レジスタ | 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 > | |||||
CCPRxL | Duty Cycle Register の上位8ビット | |||||||
CCPRxH | CCPRxLのスレーブ Register | |||||||
PSTRxCON | CMPL1 | CMPL0 | STRSYNC | STRD | STRC | STRB | STRA | |
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 | ||||
CCPxCON | 7 | PxM1 | 00 = シングル出力(規定値)、01 = フルブリッジ順方向出 10 = ハーフブリッジ出力、 11 = フルブリッジ逆方向出 |
||
6 | PxM0 | ||||
5 | DCxB1 | PWM デューティ サイクル値の下位 ビット | 1 | 0 | |
4 | DCxB0 | PWM デューティ サイクル値の最下位 ビット | 1 | 0 | |
3 | CCPxM3 | 0000 =CCPxモジュール全体をOFF(規定値) 1100 = PxA-PxCを正論理出力 1111 = PxA-PxCを負論理出力 1101 = PxA,PxCを正論理、PxB,PxDを負論理 1110 = PxA,PxCを負論理、PxB,PxDを正論理 |
|||
2 | CCPxM2 | ||||
1 | CCPxM1 | ||||
0 | CCPxM0 | ||||
PSTRxCON | 4 | STRSYNC | 出力をPWM周期に同期 | する | しない |
3 | STRD | PxD PinにPWM波形を出力 | する | しない | |
2 | STRC | PxC PinにPWM波形を出力 | する | しない | |
1 | STRB | PxB PinにPWM波形を出力 | する | しない | |
0 | STRA | PxA PinにPWM波形を出力 | する | しない | |
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出力のオープンドレイン機能 | 有効 | 無効 |
CCP1とCCP2を使いPWM波形を発生させるプログラムを作成しました。繰り返し周波数は、3.9KHzで固定ですが、デューティーサイクルをVRで可変できます。
<プログラム>
// File name: CCP PWM // Description: // VRの値で出力するデューティサイクルが変化する // CCP1とTimer2で、AN0のAD変換値から波形を発生させ // RP3(RB0)のLED0を駆動する。 // CCP2とTimer4で、AN1のAD変換値から波形を発生させ // RP4(RB1)のLED1を駆動する。 // Notes: 4MHz内部クロック // LED0 RC0 RPOR3 = 14; ECCP1 Timer2 CCP1/P1A // LED1 RC1 RPOR4 = 18; ECCP2 Timer4 CCP2/P2A // Pot0 AN0(RA0) // Pot1 AN1(RA1) // Language: MPLAB xc8 // Target: PIC18F26J50 #include <xc.h> #define _XTAL_FREQ 4000000 // delay_ms(x) のための定義 #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 main(void){ OSCCON = 0b01100010; // 内部クロック4Mhz LATB = 0; // PortCのすべてのビットを「0」 TRISB = 0b11110000; // LEDのポートを出力に設定 // ----- CCPの使用するタイマーを設定 ------------------------------- TCLKCON = 0x01; // CCP1はT2と、CCP2はT4と連携 // ----- CCP1の 設定 -------------------------------------------- RPOR3 = 14; // CCP1/P1AをRP3(RB0)に指定 CCP1CON = 0b00001100; // シングルPWM 正論理出力 PSTR1CON = 0b00000001; // PWM出力がP1A ピン T2CON = 0b00000100; // PreS 1/1 PostS 1/1 PR2 = 0xFF; // 繰返し周波数3.9KHz // ----- CCP2の 設定 -------------------------------------------- RPOR4 = 18; // CCP2/P2AをRP4(RB1)に指定 CCP2CON = 0b00001100; // ↑ PSTR2CON = 0b00000001; // ↑ T4CON = 0b00000100; // ↑ PR4 = 0xFF; // CCP1/T2と同一の設定内容 // ----- ADC初期化 ------------------------------------------------ ADCON1 = 0b00101100; // 左詰 クロックFosc/4 12_TAD ADCON0 = 0b00000001; // Vdd-Vss AN0(RA0) ADC_ON ANCON0 = 0b00011100; // AN0,AN1をアナログ入力にする ANCON1 = 0b00011111; while(1){ ADCON0 = 0b00000001; // AN0に接続 ADCON0bits.GO = 1; // AD変換開始 while(ADCON0bits.GO); // AD変換終了待ち CCPR1L = ADRESH; // AD変換結果をCCP1デューティに ADCON0 = 0b00000101; // AN1に接続 ADCON0bits.GO = 1; // AD変換開始 while(ADCON0bits.GO); // AD変換終了待ち CCPR2L = ADRESH; // AD変換結果をCC2Pデューティに __delay_ms(100); // 更新間隔 } }