H8CPUのPWM信号でモータ駆動の
サンプルプログラム
Copyright(C)
13May2002
coskx
【1】 はじめに
この文書はAKI-H8にて,PWM方式によるモータの利用のサンプルプログラムを提示するものである。
PWMはパルス幅変調(Pulse
Width
Modulation)のことである。
モータの駆動時において,高速にスイッチのON-OFFを繰り返し,ONになっている時間とOFFになっている時間の比を変更することによって,見かけ上,モータにかける電圧を変更する駆動方法である。
次の図1はPWM信号の例である。周期的なON-OFFの信号で,その周期はPWM周期と呼ばれる。また(ONになっている時間)÷(PWM周期)のことはデューティ比と呼ばれる。
|
図1 PWM信号の例 |
PWM信号の作り方は大きく分けて2つある。
(1)H8/3048のITUのPWM発生機能を用いる
この方法では(入力クロック周期))×(PWM段階数)=(PWM周期)になるため,短い1msec以下のPWM周期を実現できる。
1つのH8/3048のITUの個数により,制御できるモータ数が限られる。
(2)1つのITUによるタイマー割り込みを用い,ソフトウェアにより,PWM信号を作る
この方法では(割り込み周期)×(PWM段階数)=(PWM周期)になるため,PWM周期が10msec程度以上になる
2ビットの出力で,1つのモータが制御できるため,1つのH8/3048で多くのモータを制御できる
【2】 AKI-H8とのモータドライバ
TA8429Hと接続
(ITU
Channel3のPWM機能を利用)
外付け回路が必要だが,PWM周波数を高くできる
H8CPUはITUでPWM(Pulse Width
Modulation)信号を発生することができる。このPWM信号と方向信号2ビットを用いてDCモータ駆動用のプログラムを作成することができる。ITUチャンネル3を用いることにすると,PWM信号はTIOCA3より出力される。また方向信号はポート4のビット0,1から出力するものとする。PWM信号と方向信号はアンド回路を経てモータドライバIC(東芝TA8429)に与えられ,DCモータを駆動するものとする。(図2.1,図2.2参照)
プログラムでは,RS232Cに接続されたパソコンのターミナルソフト(例えばハイパーターミナル)を用い,キーボードからPWM値を設定するものとし,設定値は-1000から1000までの値(負の値は逆転を意味する)を用いる。これ以外の値だったら,モータを停止するものとする。
プログラムでは,システムクロックφをそのまま用いているので,ITUカウンタへの入力クロックは16MHzである。PWM階段数はPWM_MAXで与えられ,1000である。PWM周波数は16kHzとなっている。(PWM周期は1/16msec)
|
図2.1 ITUチャンネル3を用いたモータのPWM駆動回路例 |
|
図2.2 モータドライバIC 東芝TA8429 |
モータへのPWM出力 |
/********************************************************** モータへのPWM出力 ITU
Channel3 を用いたPWM信号発生 TIOCA3(PWM波形出力信号) はPB-0(PortB-bit0) Conecter
CN1-16 P4-bit0 正転信号 Conecter CN1-32 P4-bit1 逆転信号 Conecter
CN1-31 **********************************************************/ #include
<3048f.h> #include "h8_3048.h" #define PWM_MAX
1000
void initPWM3(int
gra_value) /*ITU
channel3*/ {
/*初期化(方向を設定)*/
P4DDR|=0x03;
/*(????????) | (00000011) 下位2ビットを出力に*/
P4.DDR=P4DDR;
P4.DR.BYTE=0x0; /*初期値 b0=cw,b1=ccw
正論理*/
ITU3.TCR.BIT.TPSC=0; /*内部クロックφでカウント*/
ITU3.TCR.BIT.CKEG=0; /*立ち上がりエッジでカウント*/
ITU3.TCR.BIT.CCLR=1;
/*GRAのコンペアマッチ/インプットキャプチャでTCNTをクリア*/
ITU3.GRA=gra_value-1; /*GRAの値(GRB=GRAのときPWMが100%)をPWM_MAXに設定*/
ITU3.GRB=0;
/*GRBの値を0に設定(=PWM0%)パルス幅を変えるときはこの値を変更する*/
ITU.TMDR.BIT.PWM3=1;
/*ITUのPWMに使うchをPWMモードに設定*/ ITU3.TIOR.BIT.IOB=0;
/*TIOCBにPWM信号を出力しないように設定*/
ITU.TSTR.BIT.STR3=1;
/*カウントスタート(PWM信号が出力される)*/ }
void outPWM3(int value) /* value :
-gra_value...gra_value */ /*ITU channel3*/ {
if (0<value) {
P4.DR.BIT.B0=1;
P4.DR.BIT.B1=0;
value--; if
(ITU3.GRA==value) value++;
ITU3.GRB=value; } else if (value<0)
{
P4.DR.BIT.B0=0;
P4.DR.BIT.B1=1;
value=-value-1; if
(ITU3.GRA==value) value++;
ITU3.GRB=value; } else
{
P4.DR.BIT.B0=0;
P4.DR.BIT.B1=0;
ITU3.GRB=0; } }
main() { int
x;
initSCI1();
/*シリアルポート初期化*/
initPWM3(PWM_MAX); /*PWM出力初期化(ITU
channel3使用)*/ while(1)
{ x=getIntSCI1("PWM value
=");
SCI1_printf("\n%d\n",x); if
(-1000<=x&&x<=1000)
outPWM3(x); else
outPWM3(0);
} } |
【3】 AKI-H8とのモータドライバ TA8429Hと接続
(割り込みを用いたソフトウェアPWM機能を利用)
駆動するモータの数を多くできるが,PWM周波数は低い
H8CPUのITUを用いてPWM(Pulse Width
Modulation)信号を発生することができるが,最大で5チャンネルしか利用できない。割り込みを利用するとソフトウェアで方向信号を兼ねたPWM信号を発生することが出来る。この方向信号を兼ねたPWM信号2ビットを用いてDCモータ駆動用のプログラムを作成することができる。方向信号を兼ねたPWM信号2ビットはポート1のビット0,1から出力するものとする。方向信号を兼ねたPWM信号2ビットはモータドライバIC(東芝TA8429)に与えられ,DCモータを駆動するものとする。(図3.1参照)
プログラムでは,デューティ比は-10/10,-9/10,-8/10,....,-1/10,0/10,1/10,.....,9/10,10/10を使えることになっているがこのうち,プッシュスイッチに-10/10,-5/10,5/10,10/10を割り当てて駆動する。
RS232Cに接続されたパソコンのターミナルソフト(例えばハイパーターミナル)を用いると,プッシュスイッチのON-OFF状態,モータへの指令値が表示される。
プログラムでは,割り込み周期が1msec。PWM階段数は10である。PWM周波数は100Hzとなっている。(PWM周期は10msec)
|
図3.1 割り込みとポート1第0,1ビットを用いたモータのPWM駆動回路例 |
モータドライバのテスト |
/********************************************************** プログラムの説明 モータドライバのテスト タイマ割り込み利用のソフトウェアPWM PushSW N0.0:
ch1 slow CCW PushSW N0.1: ch1 fast CCW PushSW N0.2: ch1 slow
CW PushSW N0.3: ch1 fast
CW **********************************************************/ #include
<3048f.h> #include "h8_3048.h" #define clearTimer1Flag()
(ITU1.TSR.BIT.IMFA=0)
volatile int motor1;
/*0-10の値,速度に対応*/ const int period=10; /*周期10msec*/ const int
fast=10; const int slow=5;
void
initMyMotor(void) { P1DDR |= 0xff;
/*第0ビットを出力設定だが,全ビットを出力設定*/ P1.DDR =
P1DDR; P1.DR.BYTE = 0;
/*第0ビットに0を出力設定だが,全ビットを0*/ }
main() {
int PushSwStatus,PushSwStatusb=-1;
motor1=0; initMyMotor();
initPushSW(); init8BitSW();
initLed(); initSCI1();
initTimer1Int(1000); /*時間割り込み1msec ITUch1のみ使用*/
E_INT();
/*CPU割り込み許可*/ startTimer1();
/*時間割り込みタイマスタート*/
while(1){ if
(checkPushSW(0)==1) { /* slow
CCW */
motor1=slow; } else if
(checkPushSW(1)==1) { /* fast CCW
*/
motor1=fast; } else if
(checkPushSW(2)==1) { /* slow
CW */
motor1=-slow; } else if
(checkPushSW(3)==1) { /* fast CW
*/
motor1=-fast; } else
{
motor1=0;
}
PushSwStatus=getPushSW()&0xf0;
if (PushSwStatus!=PushSwStatusb)
{
SCI1_printf("PushSW:%B
motor=%d\n",PushSwStatus,motor1);
PushSwStatusb=PushSwStatus;
} } }
#pragma asm
.SECTION MYVEC, DATA,
LOCATE=H'000070
.ORG H'000070
;IMIA1 .DATA.L
_TimerIntFunc .SECTION
P,CODE,ALIGN=2 ;これを忘れてはいけない #pragma endasm
#pragma interrupt (TimerIntFunc) void TimerIntFunc()
/*タイマ割り込みルーチン*/ { static int
tick=0; int motor;
clearTimer1Flag(); /*タイマステータスフラグのクリア 忘れないこと*/
motor=motor1; if (motor<0)
{
motor=-motor; if
(tick<motor)
{
P1.DR.BIT.B0=0;
turnOffLed(0);
P1.DR.BIT.B1=1;
turnOnLed(1); } else
{
P1.DR.BIT.B0=0;
turnOffLed(0);
P1.DR.BIT.B1=0;
turnOffLed(1);
} } else
{ if (tick<motor)
{
P1.DR.BIT.B0=1;
turnOnLed(0);
P1.DR.BIT.B1=0;
turnOffLed(1); } else
{
P1.DR.BIT.B0=0;
turnOffLed(0);
P1.DR.BIT.B1=0;
turnOffLed(1);
} }
tick++; if (tick==period)
tick=0; }
/*実行時のターミナルソフトの表示 PushSW:00010000 motor=
0 PushSW:00000000 motor= 5 PushSW:00000000 motor=
10 PushSW:00100000 motor= 0 PushSW:00000000
motor=-5 PushSW:10000000 motor=-10 PushSW:00000000 motor=
0 */ |
【4】 AKI-H8とのモータドライバ TA8429Hと接続
(ITU3,ITU4を使用して,直接モータドライバを駆動する)
ITUを2つ使ってしまうが,PWM周波数を高くできる
【2】の手法を使って,モータドライバへの出力を2つ作る。ここで,2つのITUを用いるため,ヂューティ比切り替えタイミングによっては,予期せぬ出力が非常に短いとはいえ,発生してしまうので,できるだけ避ける工夫が必要である。
ITUチャンネル3,4を用いることにすると,PWM信号はTIOCA3,TIOCA4より出力される。(図4.1参照)
プログラムでは,RS232Cに接続されたパソコンのターミナルソフト(例えばハイパーターミナル)を用い,キーボードからPWM値を設定するものとし,設定値は-1000から1000までの値(負の値は逆転を意味する)を用いる。これ以外の値だったら,モータを停止するものとする。
プログラムでは,システムクロックφをそのまま用いているので,ITUカウンタへの入力クロックは16MHzである。PWM階段数はPWM_MAXで与えられ,1000である。PWM周波数は16kHzとなっている。(PWM周期は1/16msec)
|
図2.1 ITUチャンネル3,4を用いたモータのPWM駆動回路例 |
モータドライバのテスト |
/********************************************************** モータへのPWM出力 ITU
Channel3,4 を用いたPWM信号発生
正逆転信号を2つのITUで作るぜいたくなシステム TIOCA3(PWM波形出力信号) はPB-0(PortB-bit0) Conecter
CN1-16 TIOCA4(PWM波形出力信号) はPB-3(PortB-bit2) Conecter
CN1-18 **********************************************************/ #include
<3048f.h> #include "h8_3048.h"
/*検査用PWM出力*/ /*出力端子 2
ITOCA3/PB0 CN1-16*/ /*出力端子 4
ITOCA4/PB0 CN1-18*/
/*ITU channel3,4
でPWM出力*/ /*clockindex 0:φ 1:φ/2 2:φ/4 3:φ/8 */ void
initPWM3and4(unsigned short int pwmmax, int
clockindex) { ITU3.TCR.BIT.TPSC=clockindex;
/*内部クロックφでカウント*/ ITU3.TCR.BIT.CKEG=0;
/*立ち上がりエッジでカウント*/ ITU3.TCR.BIT.CCLR=1;
/*GRAのコンペアマッチでTCNTをクリア*/
ITU3.GRA=pwmmax-1;
/*GRAの値(GRB=GRAのときPWMが100%)をPWM_MAXに設定*/
ITU3.GRB=0;
/*GRBの値を0に設定(=PWM0%)パルス幅はこの値に依存*/
/*ITU.TMDR.BIT.PWM3=1;
/*ITUのPWMに使うchをPWMモードに設定*/
ITU3.TIOR.BIT.IOB=0;
/*TIOCB3にPWM信号を出力しないように設定*/
ITU4.TCR.BIT.TPSC=clockindex; /*内部クロックφでカウント*/
ITU4.TCR.BIT.CKEG=0; /*立ち上がりエッジでカウント*/
ITU4.TCR.BIT.CCLR=1; /*GRAのコンペアマッチでTCNTをクリア*/
ITU4.GRA=pwmmax-1;
/*GRAの値(GRB=GRAのときPWMが100%)をPWM_MAXに設定*/
ITU4.GRB=0;
/*GRBの値を0に設定(=PWM0%)パルス幅はこの値に依存*/
/*ITU.TMDR.BIT.PWM4=1;
/*ITUのPWMに使うchをPWMモードに設定*/
ITU4.TIOR.BIT.IOB=0;
/*TIOCB4にPWM信号を出力しないように設定*/
ITU.TSTR.BIT.STR3=1; /*カウントスタート*/
ITU.TSTR.BIT.STR4=1; /*カウントスタート*/
PBDDR|=5;
PB.DDR=PBDDR; PB.DR.BIT.B0=0;
PB.DR.BIT.B2=0; }
/*PWM出力*/ void outPWM(int
value) { if (0<value)
{ ITU.TMDR.BIT.PWM4=0;
/*ITU4のPWMモード解除*/
value--; if
(ITU3.GRA==value) value++;
ITU.TMDR.BIT.PWM3=1;
/*ITU3をPWMモードに設定*/
ITU3.GRB=value; } else if (value<0)
{ ITU.TMDR.BIT.PWM3=0;
/*ITU3のPWMモード解除*/
value=-value-1; if
(ITU4.GRA==value) value++;
ITU.TMDR.BIT.PWM4=1;
/*ITU4をPWMモードに設定*/
ITU4.GRB=value; } else
{ ITU.TMDR.BIT.PWM3=0;
/*ITU3のPWMモード解除*/
ITU.TMDR.BIT.PWM4=0; /*ITU4のPWMモード解除*/
} }
main() { int
pwmvalue; initSCI1();
initPWM3and4(1000,0); /*clock:φ*/ while(1)
{
pwmvalue=getIntSCI1("value=");
outPWM(pwmvalue); } } |