106.PWMでモーター制御


2001/05/03 【ソフトウエア編TOPに戻る】

ここでは、DCモーターの速度制御をするのに欠かせないPWMについて触れてみたいと思います。これをしないとロボットが思うように動きません。いよいよTekuRobo工作室の本題に入っていきます。(大げさ!)


106−1.PWMとは

PWMとはパルス幅変調(Pulse Width Modulation)方式と呼ばれる手法です。なんのこっちゃ?という感じですが、大したことはありません。モーターの電源を高速で入れたり切ったりすることを繰り返すだけです。なんでそんなことでモーターの速度制御が出来るの?とも思いますが、ちゃんと出来ます。

小学生に、「モーターの速さを変えるにはどうしらいい?」と聞くと、「電池の数を増やす!減らす!」という答えが返ってきそうです。つまり、直列に繋ぐ乾電池の数で、モーターに掛ける電圧を増減させるー!と言うのです。

普通に考えるとこの答えは正解ですが、一定の電源電圧を供給している場合、モーターに掛ける電圧だけを変化させるには、抵抗やレギュレータなどで電圧を下げなければなりません。つまり、余計な電力を消費することによって、モーター電圧を可変させるわけです。これでは効率が悪いし、マイコンからの制御にも向いていません。そこで、PWM方式の登場です。

デューティー非とアナログレベルの関係

先ほど、PWMでは高速でモーター電源の入り切り(ON/OFF)を繰り返す、と説明しました。ON/OFFを繰り返すにもちょっと工夫が必要で、ONにする時間とOFFにする時間の比を変えてあげるのです。この比をデューティー比といいます。上の図の左側では、デューティー比が高いほどONになっている期間(オレンジ色の部分)が長く、デューティー比がゼロではずっとOFFのままである様子を示しています。

モーターにこういうタイミングで電源を与えてあげると、あたかもアナログ的に電源電圧を可変してあげたかのように、速度の制御が可能になります。これがPWMによる制御です。

必要な期間しか電源をONにしないので、不要な電力を消費することもありませんし、パルス幅だけで制御できるため、マイコンには扱いやすい方式です。

ただし注意が必要なのが、パルスを与える周期です。つまり、何秒おきにON/OFFを繰り返すか、を最適に設定してあげないといけません。例えば、周期を10秒に設定したとすると、デューティー比が5の場合、5秒ON/5秒OFFを繰り返すことになります。これでは、何の役にも立ちません。ON/OFFを繰り返すといっても、モーターがスムースに回転し続けなければ意味がありません。モーターにはそれぞれ固有の慣性力があり、回転中に電源をOFFにした場合、慣性力によってどれくらいの期間回転を続けるか、の特性があります。PWM制御を行なう場合、この慣性力が働く期間で周期を設定してあげないとスムースな速度制御が出来ません。大体、数百Hz〜数KHzくらいの周期が最適のようです。具体的には、あとで色々と試して決めます。

【先頭に戻る】


106−2.PWMのテストプログラムでモーターを動かす

AKI-H8/3048F CPUボードでは、ITU0〜4を使って5チャンネル分のPWM信号を得ることが出来ます。今回のテストプログラムでは、ITU0からPWM信号を出力させて、DCモーター駆動回路を経由して実際に、モーターを動かしてみます。

ITU0のPWM出力は、PIOポートAチャンネルのBit2と端子を共用しているため、開発キットのポートAを外部に出力しているコネクタを、DCモーター駆動回路に接続します。

H8-3048/F CPUでは、ITUによって以下のようなタイミングでPWM波形を出力します。

H8波形発生説明

GRBをカウンタクリア要因に設定した場合、カウンタ値がGRAを過ぎてからGRBに達するまでの期間、パルスが出力されます。なので、GRBでパルス周期を設定し、GRAでデューティー比を設定することが出来ます。なお、GRA > GRB の関係となるように値を設定すると、デューティー比が0(ゼロ)、つまりパルス出力されない状態とすることができます。

下のプログラムはポート4のスイッチSW1〜4を押すことによって、それぞれ設定された速度でモーターが回転します。プログラム上では、それぞれのスイッチに以下のデューティー比を設定してあります。

スイッチ デューティー比
SW1 0.1
SW2 0.5
SW3 0.7
SW4 0.9

つまり、SW1が一番遅く回転し、SW4が一番早く回転します。

ソースプログラムは、ここをクリックするとダウンロードできます。(pwmtest1.c)

また、ハードウエアについては、電子回路編 3.AKI-H8開発キットの回路の[13]PORTA 接続コネクタおよび、4.DCモーター駆動回路を参照して下さい。

なお、スタートアップオブジェクトは、今回割込みを利用していないので、startup.marで結構です。(ちなみに割込み対応のstartup2.marでも問題なく動作します)

/****************************************/
/* PWMテスト1         RIKIYA 2001/05/02 */
/*                           pwmtest1.c */
/*                             H8-3048F */
/* ITU0を使ったPWM基本動作テスト        */
/****************************************/

#include <3048f.h>

/* メイン関数 ********************************************/

void main(void){

     ITU.TMDR.BIT.PWM0 = 1;   /* ITU0 PWMモード              */
     ITU0.TCR.BYTE = 0x43;    /* GRBコンペアマッチ clock 1/8 */
     ITU0.GRA = 0xFFFE;       /* GRAを65534に設定            */
     ITU0.GRB = 0xFFFD;       /* GRBを65533に設定            */
     ITU.TSTR.BIT.STR0 = 0;   /* カウント停止状態                */

     PA.DDR = 0xff;           /* portA出力に設定             */
     P4.DDR = 0x00;           /* port4入力に設定 操作用sw1〜4*/
     P4.PCR.BYTE = 0xff;      /* port4プルアップon           */

     PA.DR.BIT.B3 = 0;        /* portA bit3を0固定とする     */
     ITU.TSTR.BIT.STR0 = 1;   /* カウント開始                */

     while(1){

          if(P4.DR.BIT.B4 == 0){       /*sw1の入力検出       */
               ITU0.GRA = 0xE665;      /* GRAを58981に設定   */
          }                            /* デューティー比0.1  */

          else if(P4.DR.BIT.B5 == 0){  /*sw2の入力検出       */
               ITU0.GRA = 0x7FFF;      /* GRAを32767に設定   */
          }                            /* デューティー比0.5  */

          else if(P4.DR.BIT.B6 == 0){  /*sw3の入力検出       */
               ITU0.GRA = 0x4CCC;      /* GRAを19660に設定   */
          }                            /* デューティー比0.7  */

          else if(P4.DR.BIT.B7 == 0){  /*sw4の入力検出       */
               ITU0.GRA = 0x1999;      /* GRAを6553に設定    */
          }                            /* デューティー比0.9  */

          else{                        /*入力が無い時の処理  */
               ITU0.GRA = 0xFFFE;      /* GRAを65534に設定   */
          }                            /* デューティー比0    */
     }
}

 【先頭に戻る】


106−3.テストプログラムpwmtest1.cの説明

このプログラムは、特に関数を分けていません。全てmain関数の中だけで処理しています。

 

■3048f.hのヘッダファイルを読み込む

#include <3048f.h>

 

■ITUタイマーモードの設定

     ITU.TMDR.BIT.PWM0 = 1; /* ITU0 PWMモード */

ITU.TMDRは、ITU5チャンネル分のPWM動作のON/OFFを設定するレジスタです。その他、ロータリエンコーダを使う場合の設定も行ないますが、今回は使用しません。TMDRとはタイマーモードレジスタのことで、以下の意味を持ちます。

7 6 5 4 3 2 1 0
--- MDF FDIR PWM4 PWM3 PWM2 PWM1 PWM0

Bit7は未使用です。

 

MDFおよびFDIRはロータリエンコーダを使用するときに設定します。今回は使用しません。

 

PWM4〜PWM0は、対応するBitを1に設定すると、その対応するITUのTIOCA出力がPWM出力として動作します。今回はPWM0だけをPWMとして動作させるため、Bit0だけを1にします。

なので、 ITU.TMDR.BIT.PWM0=1; とします。

■ITUタイマーコントロールレジスタおよびGRA,GRBの設定

     ITU0.TCR.BYTE = 0x43;   /* GRBコンペアマッチ clock 1/8 */
     ITU0.GRA = 0xFFFE;      /* GRAを65534に設定            */
     ITU0.GRB = 0xFFFD;      /* GRBを65533に設定            */
     ITU.TSTR.BIT.STR0 = 0;  /* カウント停止状態            */

TCR(タイマーコントロールレジスタ)の設定方法については、103.タイマーで正確な時間稼ぎをするのページを参照して下さい。今回は、以下の設定にしています。

7 6 5 4 3 2 1 0
--- CCLR1 CCLR0 CKEG1 CKEG0 TPSC2 TPSC1 TPSC0
0 1 0 0 0 0 1 1

カウンタクリア要因をGRBとする。 CCLR1 = 1, CCLR0 = 0

カウンタはクロックの立ち上がりエッジでカウントする。 CKEG1,2 = 0

カウンタは内部クロックφ/8でカウントする。 TPSC2 = 0, TPSC1,0 = 1

設定値は0100 0011なので、16進数で43Hです。なので、ITU0.TCR.BYTE = 0x43; です。

 

また、GRBをカウンタクリア要因とすると、GRA > GRB に設定した時、PWM出力はデューティー比が0(ゼロ)になり、モーターが停止状態になるため、

     ITU0.GRA = 0xFFFE;       /* GRAを65534に設定  */
     ITU0.GRB = 0xFFFD;       /* GRBを65533に設定  */

という値を初期値として設定しておきます。

     ITU.TSTR.BIT.STR0 = 0;   /* カウント停止状態  */

では、カウンタを停止状態にしてあり、PWM出力を止めています。

■PIOポートの設定

     PA.DDR = 0xff;           /* portA出力に設定             */
     P4.DDR = 0x00;           /* port4入力に設定 操作用sw1〜4*/
     P4.PCR.BYTE = 0xff;      /* port4プルアップon           */

     PA.DR.BIT.B3 = 0;        /* portA bit3を0固定とする     */
     ITU.TSTR.BIT.STR0 = 1;   /* カウント開始                */

ポートAを出力に設定し、ポート4を入力に設定しています。ポートAのBit2はPWM0の出力端子としてパルス動作しますが、DCモーター駆動回路へはBit3とペアで制御信号を与えてあげる必要があり、Bit3は常に0(ゼロ)でないとモーターは動作しないので、PA.DR.BIT.B3 = 0; としてあります。DCモーター駆動用ICの動作表を下記に記します。

VIN1 VIN2 OUT1 OUT2 モード
1 1 L L ブレーキ
0 1 L H 正転
1 0 H L 逆転
0 0 ハイインピーダンス ストップ

今回、VIN1入力にPWMのパルス信号を与え、VIN2は0固定とします。なので、モーター動作は「逆転」のPWM動作となります。この、VIN2を0に固定するのがPA.DR.BIT.B3 = 0;ということになります。(4.DCモーター駆動回路も参照してみて下さい。)

 

設定部の最後にITU.TSTR.BIT.STR0 = 1;としてカウントを開始させ、PWM0のパルス出力をさせています。

 

■スイッチによるモーター駆動動作


while(1){ } で無限ループを作っています。で、ループの中で、各スイッチに対応させたPWM動作の設定を変化させています。

ここでは、ITU0.GRAの値を変化させることによって、PWMのデューティー比を変えています。

               ITU0.GRA = 0xE665;   /* GRAを58981に設定 */ デューティー比 0.1
               ITU0.GRA = 0x7FFF;   /* GRAを32767に設定 */ 
デューティー比 0.5
               ITU0.GRA = 0x4CCC;   /* GRAを19660に設定 */ 
デューティー比 0.7
               ITU0.GRA = 0x1999;   /* GRAを6553に設定  */  
デューティー比 0.9
               ITU0.GRA = 0xFFFE;   /* GRAを65534に設定 */ 
デューティー比 0

 【先頭に戻る】


このように、ITUによってPWM波形を出力させると、GRAの値を変化させてあげるだけで、簡単にモーターの速度制御ができます。今回はVIN1にだけPWM波形を入力し、VIN2は0に固定したため、片方向のみのモーター制御でした。正転/逆転の制御を行なうためには、更に工夫が必要となりますが、今回の原理さえ分かってしまえば簡単に対応できます。

とりあえず今回は、基本動作のご紹介でした。

 

【ソフトウエア編TOPに戻る】


【表紙に戻る】