2013年7月29日月曜日

メモ:いつものI2C

ArduinoでI2Cを使うときによく使うコピペ用

↓ここから
//書き込み
Wire.beginTransmission();
Wire.write(0x);

Wire.endTransmission();


//読み込み、パターンはデータシート確認のこと
Wire.beginTransmission();
Wire.write(0x);
Wire.endTransmission(false);
Wire.requestFrom(int(),1,false);
output = Wire.read();

Wire.endTransmission(true);

//連続読み込み(6つのレジスタから1byteずつ読み込む場合)
byte addr[6]={0x,0x,0x,0x,0x,0x,};
byte read_data[6]={0,0,0,0,0,0};   //2byte以上のときは2次元配列に

for(int i=0;i<6;i++){
Wire.beginTransmission( );
Wire.write( addr[i] );
Wire.endTransmission(false);
Wire.requestFrom(int( ),1,false);
read_data[i] = Wire.read();   
Wire.endTransmission(true);
  }

//データを8ビットシフトして他のbyteとつなげる。便利

int hl_joint(byte high,byte low){
  int high_data = int(high) << 8;
  int output = high_data | int(low);

  return output;
}

//レジスタ6つのデータを読み込んで繋げて出力する関数。3軸センサーに。
//devはデバイスのアドレス、xyzは出力を入れる配列(出力の型は自由)
void read_xyz(byte dev,int xyz[]){

byte addr[6]={0x,0x,0x,0x,0x,0x};
byte read_data[6]={0,0,0,0,0,0};   //2byte以上のときは2次元配列に

for(int i=0;i<6;i++){
Wire.beginTransmission(dev);
Wire.write( addr[i] );
Wire.endTransmission(false);
Wire.requestFrom(int(dev),1,false);
read_data[i] = Wire.read();   
Wire.endTransmission(true);
  }
// read_data[0]=Low_byte ,read_data[1]=High_byte・・・の場合

for(int j=0;j<3;j++){
 xyz[j]=hl_joint(read_data[2*j+1],read_data[2*j]);
}

}

とりあえず以上

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

2013年7月13日土曜日

夏休み前の工作(1)

今回つくったのはこちら↓
















 なんてことはないただのUSBハブですが、USBの線が2つ出ています。
片方は電源用、片方は信号用になっており、スマホ用USBチャージャーなんかから
電源を取れるようにしてあります。 これで電源用のインターフェースをUSBに統一できる。

















 つなぎ方(重要) : 試行錯誤があったが以下のように配線します。

1、元から繋がってるV+線を切断、こっちはオープンにしておく
2、 基板のV+と外部電源用電源V+線(写真手前赤線)を半田付け
3、外部電源用GNDを基板GNDに半田付け、元からある線と一緒につける(GNDを共通にする)
4、外装に適当な穴を開ける
5、いろいろ絶縁とか、ショートしないように注意


















Raspberrypi とかPCでも一応正常動作を確認(なんとなく不審な挙動がみられたけど・・・)
よい子は真似しないでね。

~おわり~