CCPのPWMでの使い方


【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_3
SET_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ビットのみセットします。



【プログラム例2】(10ビット高分解能での使い方)

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)が最大値となります。



       目次ページへ