ステッパーモーター / ゆっくり加速、ゆっくり減速

pp.334-335
脱調しないよう、加速、巡航、減速の3ステージで構成された台形駆動をしてみる。ここでは単純に、静止→加速→巡航→減速→静止という動作を試す。下のコードは1ステップごとに加減速をしているので、速度はステップ数に対しては線形変化するが時間に対しては線形変化しない。
f:id:ti-nspire:20191123075215p:plain:h250

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "mylib.h"

#define START_DELAY  255
#define CRUISE_DELAY 10
#define ACCELERATION 2

volatile const uint8_t Phases[] = { // 励磁シーケンスを定義しておく。フルステップ。
    (1 << PB0) | (1 << PB2),
    (1 << PB0) | (1 << PB3),
    (1 << PB1) | (1 << PB3),
    (1 << PB1) | (1 << PB2),
};
volatile const uint8_t MaxIndex = sizeof(Phases)/sizeof(uint8_t) - 1;

volatile uint8_t  whichPhase  = MaxIndex; // どの励磁状態にあるのかを覚えておく変数。
volatile int8_t   direction;              // 回転方向。1 or -1。
volatile uint16_t stepCounter;            // 何ステップ進んだのかを数える変数。

ISR(TIMER0_COMPA_vect){                               // コンペアマッチするたびに、
    whichPhase = (whichPhase + direction) & MaxIndex; // 次の励磁状態へ進んで、
    PORTB = Phases[whichPhase];                       // 実際に励磁して、
    stepCounter++;                                    // ステップカウンターを1増やす。
}

void initTimer0(){
    TCCR0A |= (1 << WGM01); // ウェーブフォームモード: Clear Timer on Compare Match (CTC)モード。
    setPrescaler0(1024);    // 分周比: 1024。8 MHz/1024 = 7.8125 kHzをカウントする。
    sei();
}

// 普通に回す。
void takeSteps(int16_t howManySteps, uint8_t matchVal){                 // 普通の回転指令が来たら、
    if(howManySteps > 0){direction =  1;                              } // 回転方向を特定して、
    else                {direction = -1; howManySteps = -howManySteps;}

    stepCounter = 0;                       // ステップカウンターをリセットして、
    OCR0A = matchVal;                      // コンペア値をセットして、
    TIMSK0 |= (1 << OCIE0A);               // コンペアマッチ割り込みを有効化して、(※OCIEはOutput Compare Match Interrupt Enable)
    while(!(stepCounter == howManySteps)); // 指定したステップ数だけ回し終えるまでISR()を実行し続けて、
    TIMSK0 &= ~(1 << OCIE0A);              // 指定したステップ数だけ回し終えたらコンペアマッチ割り込みを無効化する。
}

// 台形駆動で回す。
void trapezoidMove(int16_t howManySteps){                               // 台形回転指令が来たら、
    if(howManySteps > 0){direction =  1;                              } // 回転方向を特定する。
    else                {direction = -1; howManySteps = -howManySteps;}

    uint8_t  matchVal     = START_DELAY;
    uint16_t _stepCounter = 0;
    
    uint16_t rampSteps   = (START_DELAY - CRUISE_DELAY) / ACCELERATION; // 加速ステージ(または減速ステージ)のステップ数を計算する。
    int16_t  cruiseSteps = howManySteps - (rampSteps << 1);             // 巡航ステージのステップ数を計算する。

    // 巡航ステージのある場合:
    if(cruiseSteps > 0){
        
        //加速ステージ
        while(_stepCounter < rampSteps){    // 加速ステージを抜けるまで、
            takeSteps(direction, matchVal); // 1ステップ回すたびに、
            matchVal -= ACCELERATION;       // コンペア値を減らして加速してゆき、
            _stepCounter++;                 // そのたびにステップカウンターをインクリメントする。
        }

        // 巡航ステージ
        matchVal = CRUISE_DELAY;                      // 加速ステージを抜けたのでコンペア値を巡航時のコンペア値にして、
        takeSteps(direction * cruiseSteps, matchVal); // 巡航ステージに割り当てられたステップ数だけ回し、
        _stepCounter += cruiseSteps;                  // そのステップ数だけステップカウンターを増やす。

        // 減速ステージ
        while(_stepCounter <= howManySteps){ // 指定したステップ数を回しきるまで、
            takeSteps(direction, matchVal);  // 1ステップ回すたびに、
            matchVal += ACCELERATION;        // コンペア値を増やして減速してゆき、
            _stepCounter++;                  // そのたびにステップカウンターをインクリメントする。
        }
    }

    // 巡航ステージのない場合:
    else{
      
        // 加速ステージ:
        while(_stepCounter < (howManySteps >> 1)){ // 指定したステップ数の半分を超えるまで、
            takeSteps(direction, matchVal);        // 加速して、
            matchVal -= ACCELERATION;
            _stepCounter++;
        }
        // 減速ステージ
        while(_stepCounter <= howManySteps){ // 指定したステップ数を全部回しきるまで、
            takeSteps(direction, matchVal);  // 減速する。
            matchVal += ACCELERATION;
            _stepCounter++;
        }
    }
}

int main(){
  
    initTimer0();
    DDRB = 0x0F; // (1 << PB0) | (1 << PB1) | (1 << PB2) | (1 << PB3)

    while(1){
        // 台形駆動
        trapezoidMove( 800); _delay_ms(500);
        trapezoidMove(-800); _delay_ms(500);

        // 巡航ステージに達しない台形駆動
        trapezoidMove( 200); _delay_ms(500);
        trapezoidMove(-200); _delay_ms(500);

        // 普通に回す。
        takeSteps( 400, 50); _delay_ms(500);
        takeSteps(-400, 50); _delay_ms(500);
    }

    return 0;
}

テキストはマイクロステッピングにも少しだけ触れているがChapter 15: Advanced Motorsはここまでにしておく。