【CCPとは?】
CCP (Compare/Capture/PWM)とは、10ビットの比較器を持った
モジュールで、その比較器の機能により、データ比較やパルス
列の数、パルス幅をコントロールすることが出来ます。
CCPモジュールの詳細は別ページを参照して下さい。
CCS C Compiler では、CCPについても組込み関数が用意されて
おり、これを使うことで簡単にCCP機能を使うことができます。
ここではCCPをPWM(Pulse Width Modulation)つまりパルス幅
変調に使う方法を説明します。
【CCP制御用関数】
まずCCPをコントロールする関数には下記があります。僅かに
3つの関数だけで実現することが出来ます。
CCPモジュールが2個あるのでいずれの関数も1と2の2種類が
あります。
パルス幅変調を制御するためには、周期とデューティを決める
2個のパラメータが必要です。
(1) 周期
周期はタイマ2の period で指定します。CCP1とCCP2共用です。
このperiodは8ビット(正確には10ビットの上位8ビット)です。
(2) デューティ
デューティは、専用関数で指定します。long int型で10ビットの有効
データで指定できます。
《CCP制御用関数》
関数
機能内容
SETUP_CCP1(mode)
SETUP_CCP2(mode)CCPの動作モードを初期設定します。
CCPのカウンターは、CCP_1、CCP_2でアクセスできます。
modeには下記の値を指定します。
0 CCP_OFF
(CCPモジュールをリセット)
(以下キャプチャ用)
4 CCP_CAPTURE_FE
5 CCP_CAPTURE_RE
6 CCP_CAPTURE_DIV_4
7 CCP_CAPTURE_DIV_16
(以下コンペア用)
8 CCP_COMPARE_SET_ON_MATCH
9 CCP_COMPARE_CLR_ON_MATCH
A CCP_COMPARE_INT
B CCP_COMPARE_RESET_TIMER
(以下PWM用)
C CCP_PWM
(以下8ビットモードでの下位セット)
1C CCP_PWM_PLUS_1
2C CCP_PWM_PLUS_2
3C CCP_PWM_PLUS_3SET_PWM1_DUTY(value)
SET_PWM2_DUTY(value)デューティ値をデューティカウンタ
に設定します。
valueのデータ型によって8ビットモードと
10ビットの高解像度モードを自動切替し
ています。
int型 → 8ビットモード
long int型 → 10ビットモードSETUP_TIMER_2(mode,
period,postscale)タイマ2の設定でperiodを設定することでパルスの周期を設定する。
modeは下記値を取る
プリスケール値設定とスタート制御
0 T2_DISABLED
4 T2_DIV_BY_1
5 T2_DIV_BY_4
6 T2_DIV_BY_16
periodは8ビット値
postscaleはPWM制御では使わない
【PWMの周期の決定方法】
PWMの周期の設定にはいくつかの事前検討が必要です。
基本前提として、10ビット精度のPWMを実現させるための設定
とします。
PICのクロック周波数とプリスケール値によって最高周波数が異なり
ますが、10ビットの最高分解能を得る為には下記設定のいずれかと
なります。どれを使うかは最高周波数の選択のみとなります。
クロック
プリスケール
timer2 mode最高周波数
分解能
period値
10MHz
T2_DIV_BY_1
9.77KHz
10ビット
0xFF
10MHZ
T2_DIV_BY_4
2.44KHz
10ビット
0xFF
20MHZ
T2_DIV_BY_1
19.53KHz
10ビット
0xFF
20MHz
T2_DIV_BY_4
4.88KHz
10ビット
0xFF
20MHz
T2_DIV_BY_16
1.22KHz
10ビット
0xFF
ちょっと難しくなりますが、period値をFFより小さくすることで、最高
周波数以下の適当な周波数のパルス出力とすることが出来ますが、
period値の8ビットが、そのままデューティ値の上位8ビットと連動
するため、デューティの分解能も下がることになってしまいます。
従って最高分解能とするためにはperiod値をFFとする必要があり
ます。この辺の詳細は「CCPの使い方」のページを参照して下さい。
【PWMの制御方法】
PWMで負荷を制御する時には、普通は周期を固定して、デューティ
で可変制御します。
従ってプログラムのパターンは、2個のCCPを使うとすれば下記の
ようになります。
初期設定(20MHzで最高周波数とする)
SETUP_CCP1(CCP_PWM);
SETUP_CCP2(CCP_PWM);
SETUP_TIMER_2(T2_DIV_BY_1,0xFF,0);
-----
制御(任意の制御の中で)
SET_PWM1_DUTY(value);
-----
SET_PWM2_DUTY(value);
下記は実際のプログラム例ですが、この例では下記回路図の
構成でモータの回転数を制御しようとしています。
つまり、MOSトランジスタで構成したHブリッジでモータの回転
方向を制御し、かつパルス幅制御で回転数を制御します。
正回転の時には、Q1をONとしてCCP1でQ4をパルス制御します。
逆回転の時には、Q2をONとしてCCP2でQ3をパルス制御します。
これを実現するプログラムが下記リストとなります。
【プログラム例1】(8ビット分解能での使い方)
下記プログラムの機能は、まずスタートさせると
Start PWM Control! Direction=
と聞いてきますので、ここで「n」か「r」を入力して回転方向を指定します。
するとモータを一旦停止してから
nの時には、
Normal Direction Duty(hex)=
と聞かれますので、ここで16進数2桁で数値を入力してリターンをすれば
入力した数値に比例した速度でモータが正回転します。
この16進数はデューティの10ビットの上位8ビットとなります。
0x00の時停止し、0xFFの時最高速度となります。
rの時には
Reverse Direction Duty(hex)=
とやはり聞かれますので、同じ様に16進数2桁数値を入力すれば逆方向
に回転します。
rでもnでもない時は Error! となります。
そのあとは、また最初に戻って Start PWM Control! Direction= と
なって繰り返します。
《プログラム例》 下記リストには漢字スペースを含むのでそのままでは使えません
////////////////////////////////////////////////////
// This program is a sample of CCP PWM mode.
// This controls one DC motor by two PWMs.
// The H bridge is constructed with below pins.
// Normal direction : CCP1 and RC3 high
// Reverse direction : CCP2 and RC4 high
// Break mode : RC3 and RC4 to high
// Normal stop : all low
// CCP frequency is 9.77KHz at 10MHz clock.
///////////////////////////////////////////////////
#include <16c73.h>
#use delay(CLOCK=10000000)
#use rs232(BAUD=9600,XMIT=PIN_C6, RCV=PIN_C7)
#include <input.c> //CCS special function
main() {
int dirct,duty;
set_tris_c(0x80); //set port C
output_low(PIN_C3); //stop all
output_low(PIN_C4);
setup_ccp1(CCP_PWM); //setup CCP
setup_ccp2(CCP_PWM);
setup_timer_2(T2_DIV_BY_1,0xFF,1);
//////////// Drive motor with variable speed
do {
printf("\r\nStart PWM Control! Direction= ");
dirct=getc(); //回転方向を指定nかr
putc(dirct); //echo out
output_low(PIN_C3); //一旦停止させる
output_low(PIN_C4);
set_pwm1_duty(0);
set_pwm2_duty(0);
switch(dirct){
case 'n': //正回転の時
printf("\r\nNormal Direction Duty(hex)= ");
duty=gethex(); //デューティ値を16進数で
set_pwm1_duty(duty); //Hブリッジ制御
output_high(PIN_C3); //start drive
break;
case 'r': //逆回転の時
printf("\r\nReverse Direction Duty(hex)= ");
duty=gethex();
set_pwm2_duty(duty);
output_high(PIN_C4); //Hブリッジ制御
break;
default: //エラーの時
printf(" Error?\r\n");
break;
}
}while(1);
}
《解説》
#include <input.c>
CCS社から提供されている数値入力の関数群のインクルード指定です。
setup_ccp*(CCP_PWM);
CCPの初期設定でPWMモードを指定します。CCP1、CCP2それぞれを
設定します。
setup_timer_2(T2_DIV_BY_1,0xFF,1);
タイマ2で周期周波数を設定します。プリスケーラ無しで周期最大のFF
を設定します。
set_pwm*_duty(duty);
デューティ比をキーボードから入力した任意の値にセットします。
ここでは10ビットのデューティの上位8ビットのみセットします。
CCPのデューティは10ビットの分解能がありますから、これを最大に活か
した使い方の例です。
機能は、まずプログラムをスタートさせると、Startメッセージが出力されま
す。その後、「+」を入力すると次第にデューティ値が増加し、モータの回転
が次第に速くなります。 途中で「−」を入力すると回転数が下がります。
《プログラム例》 下記リストには漢字スペースを含むのでそのままでは使えません
////////////////////////////////////////////////////
// This program is a sample of CCP PWM mode.
// This controls one DC motor by two PWMs.
// The H bridge is constructed with below pins.
// Normal direction : CCP1 and RC3 high
// Reverse direction : CCP2 and RC4 high
// Break mode : RC3 and RC4 to high
// Normal stop : all low
// CCP frequency is 9.77KHz at 10MHz clock.
// Function
// Input key + or -, then speed up/down of motor.
///////////////////////////////////////////////////
#include <16c73.h>
#use delay(CLOCK=10000000)
#use rs232(BAUD=9600,XMIT=PIN_C6, RCV=PIN_C7)
main() {
long int duty;
set_tris_c(0x80); //set port C
output_low(PIN_C3); //stop all
output_low(PIN_C4);
output_low(PIN_C1);
setup_ccp1(CCP_PWM); //setup CCP
setup_timer_2(T2_DIV_BY_1,0xFF,1);
set_pwm1_duty(0); //initialize
//////////// Drive motor with variable speed
printf("\r\nStart PWM Control! input + or -");
duty=0; //initialize speed
do {
output_low(PIN_C4);
output_high(PIN_C3); //start drive
switch(getc()) { //Input character
case '+':
if(++duty >1023)
duty=1023;
printf("%4LX\r\n",duty); //print speed
set_pwm1_duty(duty); //H bridge control
break;
case '-':
if(--duty == 0)
duty= 1;
printf("%4LX\r\n",duty); //print speed
set_pwm1_duty(duty);
break;
default:
printf("Error?\r\n");
break;
}
}while(1);
}
《解説》
long int duty;
デューティの変数として16ビット長の符号無し整数値を指定します。
これは必ずこの型である必要があります。
set_tris_c(0x80);
ポートCを最上位だけ入力であとは出力の設定にします。
output_low(PIN_C1);
CCP2側は使わないので標準出力ポートとなっていますからLowに
しておきます。
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1,0xFF,1);
set_pwm1_duty(0);
CCP1のモードを設定しています。最高速の9.77KHzの設定になります。
switch(getc()) {
キーボードからの入力を待ち、+、−、その他でcase分けをして処理
しています。
set_pwm1_duty(duty);
その時点のデューティ値をセットします。このデューティ値は10ビット
ですから、最大1023(0x3FF)が最大値となります。