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カウンタへの入力クロックは25MHzである。PWM階段数は
PWM_MAXで与えられ,1000である。PWM周波数は25kHzとなっている。(PWM周期は1/25msec)
|
図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 <3048fone.h>
#include "h8_3048fone.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=SCI1_getInt("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 <3048fone.h>
#include "h8_3048fone.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カウンタへの入力クロックは25MHzである。PWM階段数は
PWM_MAXで与えられ,1000である。PWM周波数は25kHzとなっている。(PWM周期は1/25msec)
|
図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 <3048fone.h>
#include "h8_3048fone.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=SCI1_getInt("value=");
outPWM(pwmvalue);
}
}
|