Arduino+L6470+SPI通信でステッピングモータを回転させる方法です。
前回、A4988というドライバ使ってみたのですが、今回はL6470というドライバを使ってArduinoからステッピングモータを制御してみたいと思います。最終的には複数のモータを各々制御したいと考えていて、個人的にどちらのドライバが良いか試しているところです。
簡単な動作確認
Processingで簡単なコントローラーを作ってPCからArduino経由で制御してます。
▼ステッピングモータは手持ちの物▼
▼L6470ドライバは秋月から入手しました▼
ジャンパーピンのみ半田付けしてます・・・。
回路図(結線図)
ArduinoとL6470モジュールはSPI接続です。ロジック電源は、ジャンパーピンで内部レギュレータや外部電源などを切り替えられるようになってます。BUSYピンは使い方によっては接続無くても問題ありません。
A4988の場合は方向とパルスを送信する(2線)だけで回転できたのですが、L6470の場合はSPI通信でコマンド送信して制御を行います。コマンドにはモータの設定、制御、状態の取得ができるようなコマンドが多く準備されています。
ArduinoとL6470のSPI通信方法概要
設定や制御は、基本的にコマンドバイトを送信、その後、決められた長さのデータ(設定値など)を送信して行います。
~CSピン「LOW」で通信開始。情報を送信して~CSピンを「HIGH」にすると情報がデバイスに取り込まれます。基本的には1byte(8bit)送信するごとに~CSピンのHIGH、LOWを行います。
~CSピン「LOW」のまま複数byteを送信すると、先に送られた情報からSDOピンを通して、デバイスの外へ順次シフトされていきます。ここら辺はデイジー・チェーン接続で複数のモータ(複数のL6470を使って)を制御する場合です。今回は単一のモータ制御なので8bitごとに~CSピンのHIGH、LOWを切り替えます
設定例
L6470では最高速度や最低速度、加速度、μステップ、電圧などなど非常に多くの設定を行うことができます。
例えば、最高速度を設定する場合。
最高速度(MAX_SPEED)を設定する内部レジスタは「0x07」で、続いて送信する設定値のデータbit長は10bitです。
▼最高速度に「600」を設定する場合▼
(10進数) 600
(2進数) 00000010 01011000
(16進数)| 0x02 | 0x58 |
「600」を1byte(8bit)ごとに区切って上位から送信します。ですので設定値「600」を送信する場合は、「0x02」「0x58」を送信します。
内部レジスタと合わせると「0x07」「0x02」「0x58」の合計3byteの情報を送信することになります。
▼スケッチ(ソース)で表現するとこんな感じです▼
void setup() { send1_L6470(0x07); send2_L6470(600); } void send1_L6470(int8_t x) { digitalWrite(10, LOW); SPI.transfer(x); digitalWrite(10, HIGH); } void send2_L6470(int16_t x) { int8_t buf[2]; buf[0] = x >> 8; buf[1] = x & 0xff; digitalWrite(10, LOW); SPI.transfer(buf[0]); digitalWrite(10, HIGH); digitalWrite(10, LOW); SPI.transfer(buf[1]); digitalWrite(10, HIGH); }
一例です。少しわかり難いソースですが「0x07」「0x02」「0x58」の3byteの情報を、1byte送信ごとに~CS「LOW」「HIGH」を繰り返しているだけのソースです。
他、非常に多く設定できる項目がありますが送信(設定)のやり方はだいたい同じです。
制御コマンド例
制御コマンドの例です。制御コマンドも非常に多くのものが準備されてます。SPI通信のやり方は基本的にはほとんど同じです。
例えば、モータを正方向に速度「2000」で回転する場合。
定速、方向指定の回転は「0x50」もしくは「0x51」のコマンドバイトを指定します。どちらのコマンドバイトを送信するかで回転方向が決まります。続いて速度を指定します。速度指定は20bit長の長さでデータ送信します。
▼速度「2000」を指定する場合▼
(10進数) 2000
(2進数) 0000 00000111 11010000
(16進数)|0x00| 0x07 | 0xD0 |
「2000」を1byte(8bit)ごとに区切って上位から送信します。ですので「0x00」「0x07」「0xD0」を送信します。
コマンドバイトと合わせると「0x50」「0x00」「0x07」「0xD0」と合計4byteの情報を送信することになります。
▼スケッチ(ソース)で表現するとこんな感じです▼
send1_L6470(0x50); send3_L6470(10000); void send1_L6470(int8_t x) { digitalWrite(10, LOW); SPI.transfer(x); digitalWrite(10, HIGH); } inline void send3_L6470(int32_t x) { int8_t buf[3]; buf[0] = x >> 16; buf[1] = (x >> 8) & 0xff; buf[2] = x & 0xff; digitalWrite(10, LOW); SPI.transfer(buf[0]); digitalWrite(10, HIGH); digitalWrite(10, LOW); SPI.transfer(buf[1]); digitalWrite(10, HIGH); digitalWrite(10, LOW); SPI.transfer(buf[2]); digitalWrite(10, HIGH); }
SPI通信の行い方は設定する場合と基本同じです・・。少しわかり難いソースですが1byteごとに~CSピン「LOW」「HIGH」を繰り返しています。
データシート確認すると制御コマンドも結構たくさんあっていろいろな制御ができるようになってます。
モータの状態を取得
現在のモータ位置、速度などの情報を取得するコマンドも準備されます。
送信するコマンドバイトは取得したい情報のアドレス+5bit目を「1」にしたバイナリコード送信します。
▼例えば現在のモータ速度を取得する場合▼
速度情報アドレス(0x04) 0000 0100
(0x20) 0010 0000
送信するbyte(or) 0010 0100
速度情報のアドレスは「0x04」で、5bit目を「1」にしたbyte情報がコマンドバイトになります。
コマンドバイト送信後、速度情報の場合、20bit長(3byte分)の長さで情報が返ります。
▼モータ速度情報取得のスケッチ(ソース)例▼
int32_t val = read3_L6470(0x04); int32_t read3_L6470(int8_t x) { int32_t val = 0; int8_t add = x | 0x20; digitalWrite(10, LOW); SPI.transfer(add); digitalWrite(10, HIGH); digitalWrite(10, LOW); val = SPI.transfer(0x00); digitalWrite(10, HIGH); val = val << 8; digitalWrite(10, LOW); val = val | SPI.transfer(0x00); digitalWrite(10, HIGH); val = val << 8; digitalWrite(10, LOW); val = val | SPI.transfer(0x00); digitalWrite(10, HIGH); return val; }
情報を取得する場合も1byteごとに~CSピン「LOW」「HIGN」を繰り返します。受信した情報はbitシフトしながら3byte分を順に結合してます。
SPI通信の一例を紹介しましたが、コマンドは非常に多く準備されているのでいろいろ細かい制御ができるかと思います。詳しくはデータシートを見ましょう。
A4988とL6470をそれぞれ使ってみましたが、どちらも一長一短ですね。マイコンでいろいろなことさせながら複雑な制御する場合は、個人的にはL6470の方が好みです。
次は複数モータを各々で制御するのを試してみたいと思います。
参考サイト
コメント
データ送信の仕組みの解説が非常に助かりました。ありがとうございます!