2013年7月15日月曜日

夏休み前の工作(2) ~ArduinoでI2Cモータドライバを動かしたときのメモ~

秋月電子とかストロベリーリナックスで売ってるDRV8830を使ったモータードライバモジュールをかろうじて使えるようになったのでそのあたり+ArduinoでI2Cを使うにあたっての自分用メモ

この記事の内容によって生じたことの責任は取りかねますのであくまで自己責任でお願いします。


1、重要な参考文献: mixture-art@Q 様の記事(「Arduino I2C」でぐぐるとトップに出る)

http://mixture-art.net/arduino%E3%81%A7i2c%E9%80%9A%E4%BF%A1%E3%82%92%E3%82%84%E3%82%8B%E9%9A%9B%E3%81%AE%E3%83%A1%E3%83%A2/

↑参考にしないとI2C用ライブラリ(Wire)で適切なデータ受信ができなくなる。じぶんでC言語とかで解決するハメに・・・

2、DRV8830の日本語データシート(ストリナのDRV8830ドライバのページにリンクがある)

↑見ないと使い方がわからない(秋月のドライバのトリセツは情報が不十分)


とりあえず以下が最低限動くソースとコメント↓

ArduinoIDEに最初から入ってる 「master_writer」をベースに改造

#include <Wire.h>

byte m_driver=0x64;  ←A0 A1をオープンにしてるとドライバのアドレスは
「1100100」=「01100100」→16進数にすると「0110(←6) 0100(←4)」=64(HEX) となる。重要

↓モータの速度を設定する関数。適当
void setmotor(byte val,byte ori){  ←モータ出力設定(VSET)とブリッジ制御用の2ビットを入力
  Serial.print("setmot start\n");
  Wire.beginTransmission(m_driver); ←「書き込みモード」でドライバと通信開始。この命令を使うと勝手にアドレス(7桁)の末尾に「0(Write)」が加えられて通信される(長期間詰まった)
  Wire.write(0x00);  ←サブアドレス。レジスタ0(アドレス:0x00)のアドレスを送信
  byte sp6=val << 2; ←引数valを2ビット左にシフト
  byte mot = sp6|ori; ←方向の2ビットとorをとる。これで送信用のデータバイトができる。  Serial.println(mot,HEX); ←なんとなくシリアルに出力
  Wire.write(mot);  ←データバイトを送信。ちゃんと通ればモータが回ったりする。

  Wire.endTransmission();    ←通信終わり。「STOP」ビットをドライバに送信する。 
}

void fault_clear(){ ←faultレジスタ(0x01のレジスタ)内の障害状態をリセットする。フェールの種類によってはリセットしないとドライバが使用できない場合がある。
  Serial.print("fault_clear\n");
  Wire.beginTransmission(m_driver);
  Wire.write(0x00);       
  Wire.write(B10000000);     ←第7ビットに1を書き込むとフェールのログが消える。
             
  Wire.endTransmission();

}

void setup()
{
  Wire.begin();
 
  Serial.begin(9600);
  Serial.println("\n set ");
  Serial.println(m_driver,HEX);
 
  fault_clear();    ←最初に一応フェールをリセットしておく
}


ここからメインループ
void loop()
{
↓適当にモータを動かしてみた。第1引数は0x3fあたりが最大、第2引数は0x0,1,2,3のどれかを入力。詳しくはデータシート参照。待ち時間は別に2秒とかじゃなくていい(多分不要)
 delay(2000);
 setmotor(0x1E,0x0);
 delay(2000);
 setmotor(0x1E,0x0);
 delay(2000);
 setmotor(0x3E,0x0);
 delay(2000); 
   

↓ここからデータ読み出し。非常に重要な箇所あり(知らないとI2Cデータ受信できない)

  Serial.print("0x01 read start\n");
  Wire.beginTransmission(m_driver);  ←受信だけど書き込みモードでデータ通信開始、ドライバの仕様。
  Wire.write(0x01);        ←読みたいレジスタのアドレス
  Wire.endTransmission(false); ←参考文献より。これを入れないとドライバとの通信が維持できない。

  Wire.requestFrom(int(m_driver),1,false);  ←読み込みモードで通信開始。こちらは勝手に末尾に「1(read)」が付け加えられる。ドライバのマニュアルに「アドレス(書き込み)、アドレス(読み込み)」とか親切に書いてくれているが、そのアドレスは末尾の0,1を加えたアドレスなのでそれをこことかbeginTransimission()に入れても通信できない。こんな馬鹿なところでハマってしまってドライバを数ヶ月放置してた・・・(つд;)

  byte out = Wire.read();     ←普通にread。
  Serial.println(out,HEX);  ←シリアルに出力して内容を確認

  Wire.endTransmission(true);    ←通信終了。()内のtrueは必要。これも参考文献より
  delay(2000);

↓レジスタ0も同様にreadしてみる。
 Serial.print("0x00 read start\n");
  Wire.beginTransmission(m_driver);
  Wire.write(0x00);       
 Wire.endTransmission(false);
  Wire.requestFrom(int(m_driver),1,false);
  byte out2 = Wire.read();              
  
  Serial.println(out2,HEX);

  Wire.endTransmission(true);   
  delay(2000);
}










あと、配線について。電流センス抵抗に適切な抵抗をつないでGND接続しないといけないが、制限とか気にしないのであればここはGND直結でいい(直結(か小さい抵抗をGND接続)しないとドライバが動作しない。注意)。Faultnのピンは何も接続しなくても動作した。

以上。上記の情報でモータを動かせる・・・はず。動作確認したが動かせるモーターと動かせないモータがあった(ドライバのせいでは無く、多分電流流れすぎか何かで何らかの制限がかかってると推測)

 今回ArduinoのWireライブラリの親切設計(自動的にW,Rビットを付加)についてよく理解してなかったのがひどかった。しかしこれで他のI2Cデバイスも普通に使えるようになるはず( ´д`)b

0 件のコメント:

コメントを投稿