ステッパーモーター / タイマーを直接使って回転速度を制御する

pp.329-332
前回は、励磁から励磁までの時間を_delay_us()函数で設定したが、今度はテキストどおりにタイマーのコンペアマッチで設定する。

8 MHzを1024分周した7.8125 kHzをカウントするので1ティックは128 usec。したがってコンペア値0のときは128 usec (= 128 usec * 1)で1ステップ回転し、コンペア値255のときは32.768 msec (= 128 usec * 256)で1ステップ回転する。
https://cdn-ak.f.st-hatena.com/images/fotolife/t/ti-nspire/20191123/20191123075215.png

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

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);           // 指定したステップ数だけ回し終えたらコンペアマッチ割り込みを無効化する。
}

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

    while(1){
        // takeSteps(何ステップ回すか, コンペア値)
        takeSteps( 400,  50); _delay_ms(500);
        takeSteps(-400, 100); _delay_ms(500);
    }

    return 0;
}