見出し画像

【#3】 Arduinoで40年前の赤道儀にモータードライブを作った話(その3 プログラム編)

他の方のコードを使わせてもらうと言っても・・・

(その1)でも書きましたが、先人が大変素晴らしいコードを公開してくれているので、これを使わせて貰うのですが、やはり中身を理解していないと使えないのです。

特に「北の国から電子工作(仮)」さんはArduino Uno、私はArduino MicroでL6470ボードとの接続も色々と異なりますので、結局コードの中身も拝見して理解に努めました。

まずピン接続が(その1)でも紹介した通り異なりますので、その辺りを修正します。

あと「北の国から電子工作(仮)」さんはあまりStep Clockモードは使っていない様子ですので、この辺りも設定が必要です。

Step Clockモード

そもそもStep Clockモードとはなんぞやという事ですけど、L6470をこのモードに設定した後、Step Clockピンにパルスを送ると信号の立ち上がりでステッピングモータの1ステップ分を動かすというモードになります。L6470のデータシートを読むと以下の記載があります。

6.7.5 Step-clock mode
In Step-clock mode the motor motion is defined by the step-clock signal applied to the STCK pin. At each step-clock rising edge, the motor is moved one micro step in the programmed direction and the absolute position is consequently updated.

(その1)で私はL6470のStep Clock(STCK)ピンにArduino Microの9番ピンを接続しました、更にL6470の#CS(チップセレクト(又はSS スレーブセレクト))ピンにはArduino Microの13番ピンを接続しましたので、Arduinoのスケッチの冒頭は以下のように修正しました。

#include <SPI.h>
// ピン定義。
/* コメントアウト
#define PIN_SPI_MOSI 11
#define PIN_SPI_MISO 12
#define PIN_SPI_SCK 13
*/
#define PIN_SPI_SS 13
#define stepClockPin 9

void setup()の中身(前半 SPI通信設定)

void setup()の前半ではL6470とのSPI通信の設定を行います。

void setup()
{
 delay(1000);
 pinMode(PIN_SPI_SS, OUTPUT);
 pinMode(stepClockPin, OUTPUT);
 SPI.begin();
 SPI.setDataMode(SPI_MODE3);
 SPI.setBitOrder(MSBFIRST);
 Serial.begin(9600);

特にL6470とSPI通信をする時は#CS(or SS)ピンをHIGHにしておく必要があります。Step Clock信号も立ち上がりを検知するので初期値はLOWで良いと思います。

  digitalWrite(PIN_SPI_SS, HIGH);
  digitalWrite(stepClockPin, LOW);

あとは頂いたコードの関数を呼び出して、L6470のリセットとステップクロックモードへの設定まで行います。

ステップクロックのmicrostepは1/128にすることにしました。L6470のデータシートには以下のようにmicrostepの設定一覧表が掲載されています。これより、レジスターには2進数で"111"、16進数で"07"を設定します。

画像2

よって、void setup()の前半と、L6470_setup()は以下の通りにします。

// void setup() 前半
L6470_resetdevice(); //L6470リセット
  L6470_setup();  //L6470を設定  
  L6470_resetdevice(); //L6470リセット
  L6470_stepclock(0);  //L6470をステップクロックモードに設定

// L6470のセットアップコマンド
void L6470_setup(){
    L6470_setparam_stepmood(0x07); // micro setp = 1/128
}

void setup()の中身(後半 Timer割り込み設定)

赤道儀のモータードライブは正確に地球の自転に合わせてモータを動かしていく必要がありますので、Arduinoに搭載されている16MHzの水晶発振器(クォーツ)を使ったTimer割り込みを利用します。

Arduinoの回路図を見るとちゃんと16MHz, XTAL(クリスタル)の記載がありますね。

画像1

このTimer割り込み、最初はその存在も知りませんでした。『delay()関数を使うと誤差が蓄積して正確な制御ができない』という記事もあったりしてどうしたら解決できるか探していたところ、新たな先人の素晴らしい記事を発見しました。

ArduinoのTimerの複雑な仕組みを非常に丁寧に解説して下さっています。長文でしたがじっくり読んで理解しました。

Timerの使い方をざっくり要約

ArduinoのTimerには、カウンターが8bit(Max256)のTimer0, Timer2と、カウンターが16bit(Max65536) Timer1の3種類があります。カウンターとは水晶発振器からのパルスの数を数えるもので、その最大数に違いがあるということです。

当然大は小を兼ねるので16bitカウンターが便利です。しかもTimer0, Timer2はdelay()関数などの組み込み関数で使われるそうなので、ここではTimer1を使うことにします。

しかし、16MHzの水晶発振器ですからそのままでは16bitのカウンターでも65,536÷16,000,000=0.004096秒でカウンターが一杯になってしまいます。これではタイマーとして使い勝手が悪いですよね。

そのため水晶発振器からのパルスを8回受け取ったら1回カウンターを回す、というようにカウンターが回るのを遅らせる分周(prescaler)という機能があります。この分周の回数は、1, 8, 64, 256, 1024のうちから選べますのでこれだとかなり用途の幅が広がります。

従って、分周によって16bitカウンターのタイマーは以下のように機能します。

・分周1 最大 0.004096秒 1カウント=0.06μs
・分周8 最大 0.0327秒 1カウント=0.5μs
・分周64 最大 0.252秒 1カウント=4μs
・分周256 最大 1.09秒 1カウント=16μs
・分周1024 最大 4.19秒 1カウント=64μs

Timer1の設定

前回の記事で0.00350603秒おきに1ステップ動かすと決めたので分周は1でOKということになります。

Timer1で分周1に設定して、0.00350603秒÷ 1/16,000,000=56,096カウントおきにタイマー割り込みを発生させてStep Clock Pin にパルス信号を出せば良いことになります。

タイマー割り込みは65,535になった時に発生する仕組みです。Timer割り込みの間隔を変えるにはカウンターの初期値を変更すれば良いのです。

初期値を65,535-56,096=9,439 にしてタイマーを開始すれば良いことになります。

よって、void setup()の後半のタイマー設定は以下の通りにしました。

 TCCR1A = 0; // 初期化
 TCCR1B = 0; // 初期化
 TCNT1 = 9439// カウンターの初期値を設定
 TCCR1B |= (1 << CS10); // CS10 -> 1  分周 = 1 に設定
 TIMSK1 |= (1 << TOIE1); //TOIE -> 1 タイマー割り込みを許可

割り込みルーチンの記述

割り込みが発生したらタイマーの初期値を再度設定し、Step Clock Pinにパルスを送ります。これは比較的簡単で、次のように記述しました。

ISR(TIMER1_OVF_vect) {
 TCNT1 = 9439; // カウンター初期値設定
 digitalWrite(stepClockPin, HIGH); // stepClockPinをHIGHにして
 delay(1);
 digitalWrite(stepClockPin, LOW); // 1ms待ってstepClockPinをLOWにする
}

これで準備は完了です。長くなりましたので次回でコードの全体を眺めてみます。


この記事が気に入ったらサポートをしてみませんか?