PIC24FのPWM生成方法
(可変抵抗のツマミを回してLEDの点滅速度を可変します)
〔PICの動かせ方入門に戻る〕
PIC24FJ64GB002でPWMを行うやり方についてメモして置きます。
(PIC24FJ64GA002は機能が古い為にレジスタの使い方等が若干異なります)
PIC24FJ64GB002でPWMを生成させるには出力コンペアモジュールを利用する事になります。
ここでは、
MPLAB X V4.10 と MPLAB(R) XC16 C Compiler Version 1.30コンパイラ を使用しての記事です。
出力コンペア(PWM)のPIC24F用日本語リファレンスマニュアルはこちらを参照下さい。
出力コンペアモジュールは5個(OC1/2/3/4/5)有るので5個のPWM出力が出来ます。
出力コンペアモジュール出力端子の"OC1/2/3/4/5"は、PPS機能でピンを割り付けないと使えません。
RP0-RP11/RP13-RP15のどこでも自由に割り付け可能
今回は、OC1/OC2の2モジュールを利用したので下記の様に割り付けました。
#include <xc.h>
#include <PPS.h> // Pin Re-Mapping peripheral library
#pragma config IOL1WAY = OFF // 周辺機器のピン割り付けは何度でも変更出来る様に許可
PPSUnLock ;
iPPSOutput(OUT_PIN_PPS_RP8,OUT_FN_PPS_OC2) ; // RB8(OC2)
iPPSOutput(OUT_PIN_PPS_RP7,OUT_FN_PPS_OC1) ; // RB7(OC1)
PPSLock ;
※ "#include <PPS.h>"のライブラリを使う場合はこちらを参照し、インストールを行います。
出力コンペアのモード
(1)単一比較一致モード
タイマのカウント値がOCxRと一致した時にOCx出力ピンから出力するモード。
出力パターンは以下の3パターンが有ります。
・LowからHighに出力する
・HighからLowに出力する
・出力を反転する
(2)二重比較一致モード
タイマのカウント値がOCxRと一致した時にOCx出力ピンをHighにし、OCxRSと一致した時に
Lowに駆動します。
出力パルスパターンは以下の2パターンが有ります。
・ワンパルスの出力
・連続パルスの出力
(3)単純PWMモード
このページではこのモードのみ以下で実験しています。
又、エッジ整列PWMモードとセンター整列PWMモード(24FJ64GA002には無し)が有ります。
尚、センター整列PWMモードが有ればモータアプリケーション等で利用出来るでしょう。
※ フォルト動作を有効にすれば、フォルトピン(OCFA/OCFB)の動作によりPWM出力を
一時停止出来ます。
(4)カスケードモード
通常は16ビットタイマですが、OC1/OC2とOC3/OC4と2モジュールをカスケードする事により
32ビットタイマとして動作させるモードです。(24FJ64GA002には無し)
クロックのタイムベース
出力コンペアのタイムベースは、Timer1〜Timer5と周辺クロック(FCY=Fosc/2)のいずれかを使います。
Timerを使うメリットは、プリスケーラが利用出来る事でしょう。
タイムベースの1カウント時間は?
(1秒/FCY)X プリスケーラ設定値
・Fosc=32MHz(FCY:16MHz)でプリスケーラ=1:1での1カウント時間は
(1 / 16MHz) * 1 = 0.0625(62.5ns) → これが最少単位の1カウントの時間です。
因みに、プリスケーラは1:1/1:8/1:64/1:256が利用出来る。
タイムベースが周辺クロック(FCY)使用する場合はプリスケーラ1:1で計算する。
1000HzのPWMを生成するには?
1000000us/1000Hz=1000us(1ms)が1KHzの1サイクル時間なのでぇ、
1000000ns/62.5ns=16000だから16000カウントさせれば1msになる。
なのでPRx=16000-1でセットする。
もしタイムベースが周辺クロックならOCxRS=16000-1でセットする。
《実験回路とサンプルプログラム》
左が実験回路で、電源は3.3Vです。
半固定抵抗はAN0(RA0:2番ピン)に接続しています。
RB7(16番ピン)にOC1を割り付けてPWM出力を行うので、
LEDを繋いでいます。
又、サンプルプログラムによっては、
RB8(17番ピン)にOC2を割り付けています。
↓ここからサンプルプログラムソースファイルをダウンロードして下さい。
PWM.zip
プログラムソースをダウンロードしたら解凍して下さい。
MPLAB Xにてプロジェクトを作成し、解凍ファイルをプロジェクトディレクトリにコピーして
プロジェクトに取込んで下さい。
次にコンパイルとPIC書き込みを実行して下さい。
ダウンロードファイルを解凍すると下記の様なファイル構成です。
PWM_FCY.c・・・・・・・・・・・・・・・出力コンペア機能のエッジ整列PWMモードサンプルプログラム1
PWM_TIMER2.c・・・・・・・・・・・出力コンペア機能のエッジ整列PWMモードサンプルプログラム2
PWM_Complement.c・・・・・・出力コンペア機能のエッジ整列PWMモードサンプルプログラム3
PWM_Center.c・・・・・・・・・・・・出力コンペア機能のセンター整列PWMモードサンプルプログラム4
このいずれかの1ファイルのみでコンパイルします。
尚、CPUのクロックは32MHzを想定しています。
《周辺クロック(FCY)での使用例》
ここで使用するサンプルプログラムは、"PWM_FCY.c"を使います。
出力コンペアのモードは、”エッジ整列PWMモード”でOC1から出力を行います。
このモードではコンペアのクロックに、”周辺クロック(FCY)”を利用します。
又、このモードはタイマを使わないので OC1RS に1周期の設定を行います。
#define F_CYCLE 15999 // OC1RSのサイクル(1周期)
// OC1機能をエッジ整列PWMモードで初期化
OC1CON1 = 0b0001110000000110 ; // FCY使用、エッジ整列PWMモード
OC1CON2 = 0b0000000000011111 ; // 16bit、同期イベントはOC1(OC1RS))
OC1R = 0 ; // デュティ比は0%で初期化
OC1RS = F_CYCLE ; // 16000(0x3E80)=1ms(1000Hz)が1周期
OC1R にデュティ比を設定しますが、値は"F_CYCLE"が1周期なので0〜F_CYCLE(100%)です。
なので、可変抵抗値(0-1023)をスケール変換して OC1R にセットしています。
可変抵抗を回すとLEDの明るさが変わるでしょう。
《タイマ2での使用例》
ここで使用するサンプルプログラムは、"PWM_TIMER2.c"を使います。
出力コンペアのモードは、”エッジ整列PWMモード”でOC1から出力を行います。
このモードではコンペアのクロックに、”タイマ2”を利用します。
タイマ2を使うので1周期の設定は PR2 で行います。
#define F_CYCLE 15999 // Timer2のサイクル(1周期)
// OC1機能をエッジ整列PWMモードで初期化
OC1CON1 = 0b0000000000000110 ; // Timer2使用、エッジ整列PWMモード
OC1CON2 = 0b0000000000001100 ; // 16bit、同期イベントはTimer2
OC1R = 0 ; // デュティ比は0%で初期化
// タイマー2の設定
T2CON = 0b0000000000000000 ; // プリスケーラカウント値 1:1、内部クロック(FCY)で使用、16ビット動作
TMR2 = 0 ; // タイマー2のカウンターを初期化する
PR2 = F_CYCLE ; // 16000(0x3E80)=1ms(1000Hz)が1周期
T2CONbits.TON = 1 ; // タイマー2開始
OC1R にデュティ比を設定しますが、値は"F_CYCLE"が1周期なので0〜F_CYCLE(100%)です。
なので、可変抵抗値(0-1023)をスケール変換して OC1R にセットしています。
可変抵抗を回すとLEDの明るさが変わるでしょう。
《相補出力PWM》
ここで使用するサンプルプログラムは、"PWM_Complement.c"を使います。
出力コンペアのモードは、”エッジ整列PWMモード”でOC1とOC2から出力を行います。
又、相補出力PWMなのでOC2出力を反転させます。
このモードではコンペアのクロックに、”タイマ2”を利用します。
タイマ2を使うので1周期の設定は PR2 で行います。
複数の出力コンペアを同期させる場合は必ず同じクロックベースを使いましょう。
#define F_CYCLE 15999 // Timer2のサイクル(1周期)
// OC1機能をエッジ整列PWMモードで初期化
OC1CON1 = 0b0000000000000110 ; // Timer2使用、エッジ整列PWMモード
OC1CON2 = 0b0000000000001100 ; // 16bit、同期イベントはTimer2
OC1R = F_CYCLE/2 ; // デュティ比は50%で初期化
// OC2機能をエッジ整列PWMモードで初期化
OC2CON1 = 0b0000000000000110 ; // Timer2使用、エッジ整列PWMモード
OC2CON2 = 0b0001000000001100 ; // 16bit、同期イベントはTimer2、出力は反転
OC2R = F_CYCLE/2 ; // デュティ比は50%で初期化
// タイマー2の設定
T2CON = 0b0000000000000000 ; // プリスケーラカウント値 1:1、内部クロック(FCY)で使用、16ビット動作
TMR2 = 0 ; // タイマー2のカウンターを初期化する
PR2 = F_CYCLE ; // 16000(0x3E80)=1ms(1000Hz)が1周期
T2CONbits.TON = 1 ; // タイマー2開始
OC1RとOC2Rにデュティ比を設定しますが、50%固定デュティ比なのでF_CYCLE/2としています。
尚、OC1(RB7)/OC2(RB8)の出力ピンには、このサンプルでは何も接続していません。
《センター整列PWMモード》
ここで使用するサンプルプログラムは、"PWM_Center.c"を使います。
出力コンペアのモードは、”センター整列PWMモード”でOC1とOC2から出力を行います。
又、OC2側出力にはデッドバンド出力を施してみました。
このモードではコンペアのクロックに、”タイマ2”を利用します。
タイマ2を使うので1周期の設定は PR2 で行います。
#define F_CYCLE 15999 // Timer2のサイクル(1周期)
// OC1機能をセンター整列PWMモードで初期化
OC1CON1 = 0b0000000000000111 ; // Timer2使用、センター整列PWMモード
OC1CON2 = 0b0000000000001100 ; // 16bit、同期イベントはTimer2
OC1R = 5000 ; // TMR2=OC1Rで出力HIGH、50%のデュティ比
OC1RS = 13000 ; // TMR2=OC1RSで出力LOW、50%のデュティ比
// OC2機能をセンター整列PWMモードで初期化
OC2CON1 = 0b0000000000000111 ; // Timer2使用、センター整列PWMモード
OC2CON2 = 0b0000000000001100 ; // 16bit、同期イベントはTimer2
OC2R = 5000 + 500 ; // TMR2=OC2Rで出力HIGH、30us立ち上げを遅くしている
OC2RS = 13000 - 500 ; // TMR2=OC2RSで出力LOW、30us立ち下げを早くしている
// タイマー2の設定
T2CON = 0b0000000000000000 ; // プリスケーラカウント値 1:1、内部クロック(FCY)で使用、16ビット動作
TMR2 = 0 ; // タイマー2のカウンターを初期化する
PR2 = F_CYCLE ; // 16000(0x3E80)=1ms(1000Hz)が1周期
T2CONbits.TON = 1 ; // タイマー2開始
センター整列PWMモードでは、1周期内のどこでパルスを作成するのかを決めます、
即ち、OCxRでパルスのHighする位置を指定し、OCxRSでパルスのLowする位置を決めます。
0 15999 0
|←―(PR2)―→|←―(PR2)―→|
┌――┐ ┌――┐
―――┘ └―――┘ └――――
↑ ↑ ↑ ↑
OCxR OCxRS OCxR OCxRS
(5000) (13000)
とセットすれば50%のデュティ比が生成出来るでしょう。
でぇ、OC2にデッドバンドを作成する為に、
OC2R = 5000 + 500 ; と立ち上がりを遅くさせています。
さらに、
OC2RS = 13000 - 500 ; と立ち下げを早くしています。
"500"で30us程のデッドバンドが出来ます。
尚、OC1(RB7)/OC2(RB8)の出力ピンには、このサンプルでは何も接続していません。
【きむ茶工房ガレージハウス】
Copyright (C) 2006-2019 Shigehiro Kimura All Rights Reserved.