PIC18F14K50で内蔵PWMモジュールを使用する実験の記録である。まず、デバイス単体にてPWMモジュールを動作させ所望の出力波形を得ることができた。また、PCよりUSBによる仮想シリアル通信でデバイスへDuty変更の指示を送信し、それに応じてDutyの変更をすることができた。
USB対応マイコンPIC18F14K50にはPWMモジュールがあるためPCよりUSBでPWMの設定を送信することができれば、応用の幅が広がる。そこで、今回はPIC18F14K50を用いて、PCからPWMモジュールの制御を行ってみる。
使用する実験装置は、おなじみの『PICで動かすUSB』評価基板とする。そして今回の目標はPCよりUSBによる仮想シリアルでPWMモジュールの制御内容を送信し、それを受けてデバイスが応答すればよい。したがって、ハードウェアの構成としてはPCと実験基板をUSBケーブルで接続し、PWM出力として用いるRC5ポートの波形が観測できればよい。そしてプログラムの大まかな流れとしては以下のとおり。それぞれについてプログラム作成を行う。
- PWMモジュールを動かすための各種設定をする
- PCからのシリアルを受信する
- 受信したシリアルの内容を解読し、それに応じてPWMモジュールの制御を行う
PWMモジュールを動かすためには、関連するレジスタを適当に設定する必要がある。そのレジスタはどのようなモードで使用するかで変わってくるが、今回は以下に示すモードで動作させることにする。ちなみに、他のモードとしてhalf bridge modeやfull bridge modeがあるがそれらはモータの制御などで使用するようだ。
- モード:single output mode
- 出力:PA1すなわちRC5ポートのみ
- 位相:active high
まず、PWM波形を出力するポートの設定をする。今回はRC5を使用するので、
TRISCbits.TRISC5 = 0;
次に、PWMモジュールのクロックソースとして内蔵タイマのTimer2モジュールの設定をする。Timer2モジュールで設定すべきレジスタはT2CONとPR2である。T2CONではモジュールをON、プリスケーラは16分周とした。PR2はTimer2の周期を設定できるが、初期値が0xFFで最長の周期となるのでそのままとした。したがって、PWMクロックは命令サイクルクロックの1/16つまり、12MHz/16=750kHzである。
T2CON = 0x07;
次に、本題のPWMモジュールの設定である。PWMモジュールには関連するレジスタがたくさんあるが今回の使用条件ではCCP1CONとPSTRCONとECCP1ASを設定する。CCP1CONは動作モードの設定、PSTRCONはsingle output modeで動作させるときの条件を指定する。ECCP1ASは周辺回路を保護するAuto-shutdown modeという機能の設定をするレジスタであるが今回は使用しない。
CCP1CON = 0x0C; //single output modeを使用
PSTRCON = 0x11; //P1Aを使用
ECCP1AS = 0x00; //auto shut-down modeを使用しない
さらに、PWMのDutyを決めるため、CCPR1Lレジスタに値を入力する。今回は後述するPCからの指示によるDutyの変更があるのでとりあえずDutyは75%とする。したがって以下の記述となる。
CCPR1L = 0xBF;
これは、すでに以前仮想シリアルのサンプルを実験したときにはじめから記述されている。該当部分は関数ProcessIOの以下の部分である。これは変更の必要はまったくない。
if (RS232_Out_Data_Rdy == 0) // only check for new USB buffer if the old RS232 buffer is
{ // empty. This will cause additional USB packets to be NAK'd
LastRS232Out = getsUSBUSART(RS232_Out_Data,64); //until the buffer is free.
if(LastRS232Out > 0)
{
RS232_Out_Data_Rdy = 1; // signal buffer full
RS232cp = 0; // Reset the current position
}
}
受信したシリアルの内容を解読するのであるが、これにはUSBシリアル変換のサンプルを改造しUSBで受け取ったシリアルを接続デバイスへ送信することを止め、その代わりに解読とPWM制御のコードを記述する。今回はPCから'1'または'0'が送られてくることとしそれぞれDutyを25%、50%に変更することにした。
if(RS232_Out_Data_Rdy && mTxRdyUSART())
{
//putcUSART(RS232_Out_Data[RS232cp]);
if(RS232_Out_Data[RS232cp] == '1')
{
CCPR1L = 0x3F; //Duty=25%
}
else if(RS232_Out_Data[RS232cp] == '0')
{
CCPR1L = 0x7F; //Duty=50%
}
++RS232cp;
if (RS232cp == LastRS232Out)
RS232_Out_Data_Rdy = 0;
}
以上のプログラムを組み込み動作させてみた結果は以下の図3.1、3.2、3.3である。まず、図3.1ではデバイス起動直後のPWM出力波形で初期値として設定したDuty75%で動作している。また、PWMの周期は2.93kHzでこれはTimer2で生成したPWMクロック750kHzの256周期分となっていて確かにTimer2で設定したとおりの速度で動作していることがわかる。
次に、図3.2はPCより'1'を送った場合である。ONの時間は約でありDutyは約25%で設定どおりである。さらに、図3.3についてもPCより'0'を送った結果、ONの時間は約でありDutyは約50%で設定どおりとなったことがわかる。
今回の確認で、PCからUSBを経由してデバイスを制御できるようになった。今回PC側でコマンド送信を行ったソフトはTeraTermだったがもし独自のソフトでシリアルを送信できるようにすればまた応用の幅が広がる。今後の少し楽しみが増えた感じである。
図3.1 デバイス起動後のPWM出力波形
図3.2 PCより'1'を送信した場合のPWM出力波形
図3.3 PCより'0'を送信した場合のPWM出力波形
PIC18F14K50で内蔵PWMモジュールを動作させ、PCよりUSBによる仮想シリアル通信でPWMモジュールを制御することができた。今後は、PWMモジュールだけでなくさまざまな制御を行いたい。また、PC側についてもより簡単に制御可能なようGUI等を作成してみたい。