本チュートリアルではDCモーター出力を使用したステッパモーターの制御方法を説明する。

ステッパモーターについて

ステッパモーターは日常使用のデバイスに広く用いられている。例えば、プリンター等の正確な動作を要する機器が挙げられる。

原理

Stepperステッパモーターは磁気式材料のロータ及び複数のコイルで構成されている。左図はステッパモーターの略図である。コイルは
位相(フェーズ)とも呼ばれる。これは二相モータである。ここで、任意の方向で流れる電流を正極とする。この場合、ローターはコイルの磁気方向に適応するように回転し停止する。それから、位相0の電圧を止め位相1に送ると、ローターは位相1による発生磁場と並ぶように1/4回転する。更に、位相1の電圧を止め位相0に負電流を送ると、磁石は再び1/4回転する。

 

 

Tamagawa使用するステッパモーターは、1回転当たり200ステップのモータである。3Vなので、小型ロボットの開発に容易に使用できる。

モーター制御についてのチュートリアルで、DCモーターの前後回転の方法を解説した。この特徴を使用し、DCモーター出力で両相を動作させてみよう。ステッパモーターの欠点は、制御回路が2つ必要なことである。ここでは、ステッパモーター制御のため2つのDCモーター出力を使用する。

 

 

 

コイルの給電順

上記説明より、コイルの給電順が予測できる

  Phase 1 Phase 2
Step 1 + 0
Step 2 0 +
Step 3 - 0
Step 4 0 -

任意にフェーズ1をモーター1の出力に、フェーズ2をモーター2の出力に接続する。

同様に、フェーズ1の正方向をP1.5=1、P1.4=0とする。同様に、フェーズ2では、正方向はP1.3=1、P1.2=0とする。

配列は以下の通りとなる

  P1.2 P1.3 P1.4 P1.5
Step 1 0 0 0 1
Step 2 0 1 0 0
Step 3 0 0 1 0
Step 4 1 0 0 0

プログラミング手順

基本的には、以下のシーケンスをポート1に送る:0x20、0x08、0x10、0x04
または、逆方向に進ませる場合、逆のシーケンスを送る(0x04、0x10、0x08、0x20)。これは、const配列により容易に実行可能である:
const char PowSeq[4] = {0x20, 0x08, 0x10, 0x04};
次に、0から3へ周期的に指数を増やし(0→1→2→3→0→1→...)、その指数が指している値をポートに送る。これによりステッパーモーターが回転する。

スピード制御

DCモーターの速度を制御する場合、信号のデューティー比を変えた。ここでは、周波数自体を変える必要がある。従って、タイマーのCCRx でなくCCR0 を変更する。

プログラム

当プログラムの新たな点は、2つの異なった割込みルーチンがあることだ。1つはアナログ/デジタル割込み用で、もう1つはモーターピンを適切なレベルに設定するのに使用される。これは自動的には行われないので、割込み付きタイマーを使用する必要がある。(つまり、PWMのみでの自動化は不可能) 

一つの割り込み処理中に他の割込みが発生しないように割り込み停止(_DINT(Disable Interrupts))を使用する。割込み再開(_EINT(Enable Interrupts))により次の割込みまで待機する。

以下のようなソースコードになる

--------------------

void interruptADC(void) {
    _DINT();    // Disable interrupts
    // ADC specific code goes here
    _EINT();    // Enable interrupts
}

void interruptStepper(void) {
    _DINT();    // Disable interrupts
    // Stepper specific code goes here
    _EINT();    // Enable interrupts
}

--------------------

両タイマーは割込み(TxxCCTL0|=CCIE;)と共に設定される。これは単純なマルチタスクソフトウェアでループを動作させる必要はない。

下は、4本のワイヤの状態を示す画面コピーである。

4Phasesトレース1と2は第1コイルを、3と4は第2コイルを示す。

この場合、デューティー比は常に(ほぼ)25%である。4つの信号はタイムシフトし、各時点で1つのコイルのみが給電される。

 

 

 

 

コメント:

  • モータ停止は、全フェーズをオフにすることにより可能である。その場合、ブレーキがかからない欠点がある。省電力にはなるが、その欠点は軸が負荷率により容易に動いてしまうことだ。最後に止まったフェーズを給電すると軸がより強力にブロックされる代わりに消費電力が高くなる。
  • ステッパーモータはハーフステップ動作も可能である。上記の原理での説明通り、モータは1回転当たり4ステップがある。同時に2フェーズを給電すると、磁場は45度となり、2つのステップの中間に留まる。同様に、電流制御により1/4ステップで動作可能となる。

ソースコード

--------------------

#include <msp430F5659.h>
#include "F5659Utils.h"

void EnableStepperTimer(void);
void EnableADCTimer(void);
void EnableADC();
void SetStepperSpeed(int16 speed);
uint16 ReadADCVal(void);

const uint8 Phase[4] = {0x20, 0x08, 0x10, 0x04};
static int8 CurrentPhase = 0;
static int8 Direction = 1;

int main(void) {
    WDTCTL = WDTPW + WDTHOLD;                //    Stop WDT
    SetCoreVoltage(VCORE19);                 //    Set the core to 1.9V
    SetFLL(24);                              //    Set SMCLK to 24 MHz
    EnableStepperTimer();
    SetStepperSpeed(10);
    EnableADCTimer();
    EnableADC();
    __bis_SR_register(LPM0_bits + GIE);      //    Enter LPM0, enable interrupts
}

void SetStepperSpeed(int16 speed) {
    uint32 val;                    //    Use a 32-bit value so that it does not overflow
    if(speed > 0) Direction = 1;
    else if(speed < 0) {
        Direction = -1;
        speed = -speed;
    }
    else Direction = 0;
    val = 32768;
    if(speed > 0) val /= speed;
    else val = 32767;
    if(val <= 32) val = 32;
    TA0CCR0 = val;
}

void EnableStepperTimer(void) {
    TA0CCTL0 = CCIE;                         //    CCR0 interrupt enabled
    TA0CCR0 = 32;                            //    Check ADC every 15.6 ms (64 Hz)
    TA0CTL = TASSEL_1 + MC_1 + TACLR;        //    SMCLK, upmode, clear TAR
    P1DIR |= 0x3C;
    P1OUT = 0;
}

void EnableADCTimer(void) {
    TA1CCTL0 = CCIE;                         //    CCR0 interrupt enabled
    TA1CCR0 = 511;                           //    Check ADC every 15.6 ms (64 Hz)
    TA1CTL = TASSEL_1 + MC_1 + TACLR;        //    SMCLK, upmode, clear TAR
    P2DIR = 0x01;
}

void EnableADC() {
    ADC12CTL0 = ADC12ON+ADC12SHT0_2;         //    Turn on ADC12, set sampling time
    ADC12CTL1 = ADC12SHP;                    //    Use sampling timer
    ADC12CTL0 |= ADC12ENC;                   //    Enable conversions
}

uint16 ReadADCVal(void) {
    uint16 retval;                           //    Value for debugging purpose
    ADC12CTL0 |= ADC12SC;                    //    Start conversion-software trigger
    while (!(ADC12IFG & BIT0));              //    Wait for the ADC
    retval = ADC12MEM0;                      //    Set breakpoint here to verify value
    return retval;
}

// Timer0 A0 interrupt service routine. This is the stepper motor interrupt
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void) {
    _DINT();
    CurrentPhase += Direction;
    if(CurrentPhase >= 4) CurrentPhase = 0;  //    Roll back to 0 in case of forward move
    if(CurrentPhase < 0) CurrentPhase = 3;   //    Roll back to 3 in case of backward move
    P1OUT = Phase[CurrentPhase];
    _EINT();
}

// Timer1 A0 interrupt service routine. This is te ADC interrupt
#pragma vector=TIMER1_A0_VECTOR
__interrupt void TIMER1_A0_ISR(void) {
    _DINT();
    int16    adcval;
    adcval = ReadADCVal();
    adcval >>= 1;
    adcval -= 1024;
    SetStepperSpeed(adcval);
    _EINT();
}

--------------------