こんにちは、ENGかぴです。
PIC16F1827のPWM機能を持っているため振動波形を模擬してブザーを鳴らしたりデューティー比を調整したりすることで電圧を調整しながらモーターを動かしたりすることができます。MCCでPWMを実装し動作確認を行いました。
PIC16F1827で動作確認したことについてリンクをまとめています。
PICマイコン(PIC16F1827)で実現できる機能と解説リンクまとめ
PWMを実装する
PWMとはpulse width modulationの略でありパルス幅変調です。 一定のキャリア周波数に対する波形のデューティ比(HighとLowの比率)によって電圧を調整することができます。
PWM制御によってトランジスタなどの素子がON/OFFを繰り返すことからOFF時には電流が流れないことから消費電流を抑えることができます。
PIC16F1827の設定はMCCを使っています。MCCの使い方については下記記事にまとめています。
MPLAB Code Configurator(MCC)の追加と使い方
PIC16F1827ではPWM機能としてCCP及びECCPが実装されています。PWM機能はタイマ機能と連動しているためPWM及びTMRの双方の設定が必要です。
System Moduleの設定
最初に共通事項であるSystem Moduleの設定を行います。MPLAB X IDEを起動しMCCのアイコンをクリックしてMCCを有効にします。
内部クロックを使用するためINTOSCを選択しています。クロック周波数は任意でもよいですが4MHz_HFを選択しています。クロックを高速にするほど消費電流が増えてしまいます。他にも設定項目はありますがクロックの設定のみとしています。
CCP3(PWM)及びTMR2の設定
TMR2をDevice Resources内のPeripherals欄のTMR2を選択して追加します。
PWMはタイマと連動しておりPWMに指定できるタイマはTMR2・TMR4・TMR6です。PWMはCCP3(CCP4)の機能に含まれています。 Resources内のPeripherals欄のCCP3を選択して追加します。
Select TimerではTMR2を使用するためTimer2を選択します。TMR2の設定が終わっている場合はPWM Parametersの欄にPWMの情報が表示されます。Duty Cycleにデューティー比を入力します。
CCPR Valueはタイマのプリスケーラやクロックの条件から10ビットのタイマベースを作る仕様に基づくものです。この値を基にPWM Resolutionのビット値に換算された値がレジスタ値に設定されます。
例ではデューティーを50%に設定したときのCCPR Value(データシートの式よりCCPRxLを求める)は249になりますが、10ビットでの計算値となるため8ビット値に換算した値が値がレジスタ値となります。
10ビットの値を8ビット値に換算するため2回右にシフト(4で割る)した値である0x3EがCCPR3Lに設定されます。Registersでレジスタ値の詳細を確認すると一致することが分かります。
ECCP1(EPWM)及びTMR4の設定
Resources内のPeripherals欄のTMR4を選択して追加します。
TMR4はECCP1と連動して使用します。TMR4の割り込みを有効にして20ms毎にデューティー比を変更できるようにします。後述のAD変換の値を使用してデューティー比を変更します。 Resources内のPeripherals欄のECCP1を選択して追加します。
PMWの拡張機能としてEnhanced PWM機能があります。ブリッジ回路などでインバータ起動する際に使用する用途でPWMの出力を最大4ピンで制御する機能です。
Timer SelectにTimer4を選択します。PWM Duty Cycleは初期値として50%にしています。CCPR ValueはCCP3と同じ考え方です。Enhance PWM modeは2ピンで制御を行うためhalfbridgeを選択しています。
P1AとP1Bはお互いに反対の波形を生成しますがタイミングに遅延を持たせるためPWM parametersのPWM Delay countsに0xA(10)を入力して遅延を持たせています。
void IntTmr4(void){
uint16_t value;
value = dutyValue >> 1;
//PWMのデューティー100%でも500となるため
//CCPR Value相当に変換
if( value > DUTY_MAX){
value = DUTY_MAX;
}
value = value >> 2; //8ビット値に換算
CCPR1L = (uint8_t)value;
}
IntTmr4()関数はTMR4割り込みが複数回(20ms)経過したときに処理されるコールバック関数です。AD変換で取得した値をCCPR Value相当に変換した後で8ビット値に換算しています。換算の条件はTMR4のプリスケーラやクロックの条件によって変ります。
8ビット値に換算してCCPR1Lレジスタに値を書き込むとデューティー比が変更できます。
ADCとFVR及びTMR0の設定
AD変換の値からEPWMのデューティーを変更するためADCとFVRを実装します。 Resources内のPeripherals欄のADCを選択して追加します。
AD変換値を右寄せで取得するためにResult Alignmentをrightに設定します。AD変換の基準電圧にFVRを使用するためPositive ReferenceをFVRに設定します。AD変換完了時にAD変換値を取得するため割り込みを使用します。
FVRを使ってAD変換の基準電圧を生成するためResources内のPeripherals欄のFVRを選択して追加します。
AD変換の基準電圧として使用するためFVR_buffer1 Gainに4xを設定します。
TMR0を使ってADC変換のタイミングを生成します。 Resources内のPeripherals欄のTMR0を選択して追加します。
TMR0を1msでオーバーフローするようにして10回経過したときコールバックによってADC変換のタイミングを生成します。
#define TIME_ADC_WAIT 10
/* タイマ管理関数(コールバック関数) */
void mainTimer(void){
if( timAdc > TIME_UP ){
--timAdc;
}
}
/* メイン処理 */
void mainApp(void){
if( timAdc == TIME_UP){
timAdc = TIME_ADC_WAIT;
ADC_SelectChannel(channel_AN0); //AN0を選択
ADC_StartConversion(); //AD変換開始
}
}
mainTimer()が10ms毎にコールバックされてタイマtimAdcを更新します。TIME_ADC_WAITを10にしているため100ms毎にAD変換を開始します。
動作確認
PIC16F1827のPWM出力にLED・ブザー・DCモータを接続して動作を確認しました。PWM機能の動作の確認としてBZ1のブザーを鳴らします。CCP3とTMR2と連動させキャリア周波数を500us、デューティー比を50%のPWM波形を出力します。
EPWMの動作を確認のためLED1の明るさの調整とDCモーターをPWM制御によって操作します。ECCP1のEPWM機能を使用しP1AとP1BのピンからPWM波形が出力します。
P1AとP1Bは波形のONとOFFが反対の動きとなるためVR1を調整しLED1が明るくなるとP1Bのデューティー比が低下するためトランジスタを介して接続しているモータの回転が遅くなります。逆にLED1が暗くなるようにVR1を調整するとP1Bのデューティー比が高くなりモーターの回転が速くなります。
AD変換ピンとしてAN0を設けていますが可変抵抗(VR1)で電圧することでECCP1(EPWM)のデューティー比が変更できるようにします。
MCCのピン設定は以下の通りです。
ソースコード全体
以下のソースコードはコンパイルして動作確認をしております。コメントなど細かな部分で間違っていたりやライブラリの更新などにより動作しなくなったりする可能性があります。参考としてお使いいただければと思います。
#include "mcc_generated_files/mcc.h"
#define TIME_OFF -1 //タイマーを使用しない場合
#define TIME_UP 0 //タイムアップ
#define TIME_ADC_WAIT 10
#define DUTY_MAX 448
/* 変数宣言*/
int16_t timAdc;
uint16_t dutyValue;
/* プロトタイプ宣言*/
void AdcItr(void);
void mainApp(void);
void mainTimer(void);
void IntTmr4(void);
/* Main application */
void main(void)
{
SYSTEM_Initialize();
TMR0_SetInterruptHandler(mainTimer);
TMR4_SetInterruptHandler(IntTmr4);
ADC_SetInterruptHandler(AdcItr); //割り込み時AdcIrt関数をコールバックする
INTERRUPT_GlobalInterruptEnable();
INTERRUPT_PeripheralInterruptEnable();
ADC_SelectChannel(channel_AN0);
ADC_StartConversion();
timAdc = TIME_ADC_WAIT;
while (1)
{
mainApp();
}
}
/* メイン処理 */
void mainApp(void){
if( timAdc == TIME_UP){
timAdc = TIME_ADC_WAIT;
ADC_SelectChannel(channel_AN0); //AN0を選択
ADC_StartConversion(); //AD変換開始
}
}
/* タイマ管理関数(コールバック関数) */
void mainTimer(void){
if( timAdc > TIME_UP ){
--timAdc;
}
}
void IntTmr4(void){
uint16_t value;
value = dutyValue >> 1;
//PWMのデューティー100%でも500となるため
//CCPR Value相当に変換
if( value > DUTY_MAX){
value = DUTY_MAX;
}
value = value >> 2; //8ビット値に換算
CCPR1L = (uint8_t)value;
}
/* AD変換割り込み処理 */
void AdcItr(void){
dutyValue = ADC_GetConversionResult(); //AD変換値を格納
}
/* End of File */
本ソースコードはMPLAB X IDEにMCCのプラグインをインストールしていることが前提となります。MCCをインストールする方法は下記記事を参考にしてください。
MPLAB Code Configurator(MCC)の追加と使い方
関連リンク
PICマイコンを使ってマイコンのレジスタの設定やMPLAB X IDEのプラグインであるMCCを使用して動作確認したことについてまとめています。
PICマイコン(PIC12F675)で実現できる機能と解説リンクまとめ
PICマイコン(PIC16F1827)で実現できる機能と解説リンクまとめ
最後まで、読んでいただきありがとうございました。
ブザーが鳴り続けていると耳障り(幻聴の原因)になのでボタンを押したらブザーを止める等工夫が必要だと感じました。