2012年9月17日月曜日

ストリナのSPIステッピングモータドライバ

 今回の小物は ストロベリーリナックスさんのSPI接続ステッピングモータドライバ です。以外にも?自分はステッピングモータを使ったことがありませんでした。モータというとDCモータばかりです。いつもガラクタを作るのに使うのはタミヤの工作用ギアボックスなんかに入っている小さいやつですし、パワーが欲しい場合はタミヤの遊星ギヤ付きモーターとか。以前仕事で使ったMAXONのエンコーダ付きモータは大きさ(細さ)に比してトルクが大きくて素晴らしいですが、値段とか入手性を考えると日曜電子工作にはちょっと・・・ね。あとは、ぐるぐる回らなくていいなら、ラジコンのサーボですよね。オープン(センサでフィードバックしない)前提で位置制御できるのは楽ちんです。
 で、ステッピングモータも基本オープンで(脱調しなければ)何ステップ動かしたから、ここを向いているはずだということができて、しかもグルグル回せる(ラジコンサーボみたいに180度くらいを往復ではなくて)ので、車輪型ロボットの足回りに使ってみたいなと思っていたんですが、DCモータと違い、電気通せば回る(DCモータもそんなんじゃだめだろ?)っていうもんでもないので、使ったことがありませんでした。今回はそんなわけで、とりあえずステッピングモータを単純に回すところまで挑戦です。ここのところI2Cもののセンサが続きましたが、じつはSPIは使ったことがありませんでした。しかし、Arduinoなら、ちょいちょいとつないで、ライブラリを使えばOKです。(いや、素晴らしい。Arduinoあるいはライブラリを用意してくれた人たちに感謝しなくちゃね。)



 パラメータとかスピードの設定によっては脱調して回らなくなって、電流ばっかり流れてモータが熱くなったりするので気をつけましょう。(→ 自分)


#include <Arduino.h>

#include <SPI.h>

// ピン定義。
#define PIN_SPI_MOSI 11
#define PIN_SPI_MISO 12
#define PIN_SPI_SCK 13
#define PIN_SPI_SS 10

#define PIN_L6470_SS PIN_SPI_SS

// 関数プロトタイプ。
void L6470_write(unsigned char data);
void L6470_init(void);
void L6470_run(long speed);

// グローバル変数。
long speed = 10000;

void setup()
{
 // ピン設定。
 pinMode(PIN_SPI_MOSI, OUTPUT);
 pinMode(PIN_SPI_MISO, INPUT);
 pinMode(PIN_SPI_SCK, OUTPUT);
 pinMode(PIN_L6470_SS, OUTPUT);
 
 // SSはHigh(~SSをdisable)状態に。
 digitalWrite(PIN_L6470_SS, HIGH);
 // SPI開始。
 SPI.begin();
 
 // シリアル通信。
 Serial.begin(9600);
 
 // L6470の初期化。
 L6470_init();
 
 Serial.println("Start...");
 
 // テスト回転。
 L6470_run(speed);
}

void loop()
{
 
 for (int i = 0; i < 5; i++)
 {
  speed += 10000;
  L6470_run(speed);
  delay (5000);
 }
 for (int i= 0; i < 5; i++)
 {
  speed -= 10000;
  L6470_run(speed);
  delay (5000);
 }

}


void L6470_write(unsigned char data)
{
 // ~SSイネーブル。
 digitalWrite(PIN_L6470_SS, LOW);
 // SPI転送。
 SPI.transfer(data);
 // ~SSディスエーブル。
 digitalWrite(PIN_L6470_SS, HIGH);
}

void L6470_init()
{
 // MAX_SPEED設定。
 /// レジスタアドレス。
 L6470_write(0x07);
 // 最大回転スピード値(10bit)
 L6470_write(0x00);
 L6470_write(0x20);
 
 // KVAL_HOLD設定。
 /// レジスタアドレス。
 L6470_write(0x09);
 // モータ停止中の電圧設定(8bit)
 L6470_write(0xFF);
 
 // KVAL_RUN設定。
 /// レジスタアドレス。
 L6470_write(0x0A);
 // モータ定速回転中の電圧設定(8bit)
 L6470_write(0xFF);
 
 // KVAL_ACC設定。
 /// レジスタアドレス。
 L6470_write(0x0B);
 // モータ加速中の電圧設定(8bit)
 L6470_write(0xFF);
 
 // KVAL_DEC設定。
 /// レジスタアドレス。
 L6470_write(0x0C);
 // モータ減速中の電圧設定(8bit)
 L6470_write(0xFF);
 
 // OCD_TH設定。
 /// レジスタアドレス。
 L6470_write(0x13);
 // オーバーカレントスレッショルド設定(4bit)
 L6470_write(0x0F);
 
 // STALL_TH設定。
 /// レジスタアドレス。
 L6470_write(0x14);
 // ストール電流スレッショルド設定(4bit)
 L6470_write(0x7F);
}

void L6470_run(long speed)
{
 unsigned short dir;
 unsigned long spd;
 unsigned char spd_h;
 unsigned char spd_m;
 unsigned char spd_l;
 
 // 方向検出。
 if (speed < 0)
 {
  dir = 0x50;
  spd = -1 * speed;
 }
 else
 {
  dir = 0x51;
  spd = speed;
 }
 
 // 送信バイトデータ生成。
 spd_h = (unsigned char)((0x0F0000 & spd) >> 16);
 spd_m = (unsigned char)((0x00FF00 & spd) >> 8);
 spd_l = (unsigned char)(0x00FF & spd);
 
 // コマンド(レジスタアドレス)送信。
 L6470_write(dir);
 // データ送信。
 L6470_write(spd_h);
 L6470_write(spd_m);
 L6470_write(spd_l);
}