2016年9月23日金曜日

I2CとSPIで3軸ジャイロセンサL3GD20を使ってみた

以前に、自律走行する戦車を作った時にはMPU-6050を使ったジャイロセンサを使用していたのですが、今回はL3GD20をDIPモジュール化した秋月電子のAE-L3GD20を使ってみたいと思います。

基本構成
  • 電源電圧:DC3.3V(動作範囲:DC2.4V~DC3.6V)
  • 消費電流:6.1mA(Vdd 3V カタログ値)
  • インターフェース:I2C、SPIのどちらかを選択できます
PIN配置

PIN No.I2CSPI
1VDD 電源入力 DC2.4V~3.6V
2SCL シリアルクロックSPC シリアルポートクロック
3SDA シリアルデータSDI シリアルデータインプット
4SA0 スレーブアドレスの下位ビット選択SDO シリアルデータアウトプット
5VDDに接続するとI2CモードになるCS チップセレクト
6インターラプト2
7インターラプト1
8GND

I2CモードでArduinoと接続

以下説明書からの引用です。
  1. CS(5ピン)をVDDに接続すると、I2Cモードになります。

  2. SA0(4ピン)は、スレーブアドレスの下位ビット選択です。(この機能により2台まで使えます)
    VDD(1ピン)に接続すると1101011x(0x6B)、GND(8ピン)に接続すると1101010x(0x6A)になります。(x:readの時1、writeの時0)
    I2Cの場合、必ずどちらかに接続してください。
    ※ここではGNDに接続しています。

  3. SCL、SDAは外部抵抗でプルアップしてください。

    使用しているArduino UNOでは、AREFの隣2つのSDA、SCLピンと、汎用のA4ピンがSDA、A5ピンがSCLがあります。



    どちらかをL3GD20の3(SDA)、2(SCL)番ピンとそれぞれ接続します。



    プルアップはI2C接続用にWireライブラリを使用するとArduinoの内部でプルアップされるので問題ありません。
配線は以上で完了です。
とりあえずは、通信出来ているか調べてみましょう。

#include <Wire.h>

const byte L3GD20_ADDR = 0x6a;  //GND:1101010=0x6a
const byte L3GD20_WHOAMI = 0x0f;

void setup() {
  Wire.begin();
  Serial.begin(9600);
}

void loop() {
  Wire.beginTransmission(L3GD20_ADDR);
  Wire.write(L3GD20_WHOAMI);
  Wire.endTransmission();

  Wire.requestFrom(L3GD20_ADDR, 1);
  Serial.println(Wire.read(), HEX);
  delay(500);
}

シリアルモニタに0xD4が表示されていれば通信成功です。
次に実際にジャイロセンサの値を取得してみます。

#include <Wire.h>

const byte L3GD20_ADDR = 0x6a;
const byte L3GD20_WHOAMI = 0x0f;
const byte L3GD20_CTRL_REG1 = 0x20;
const byte L3GD20_OUT_X_L = 0x28;
const byte L3GD20_OUT_X_H = 0x29;
const byte L3GD20_OUT_Y_L = 0x2A;
const byte L3GD20_OUT_Y_H = 0x2B;
const byte L3GD20_OUT_Z_L = 0x2C;
const byte L3GD20_OUT_Z_H = 0x2D;

byte L3GD20_read(byte reg) {
  Wire.beginTransmission(L3GD20_ADDR);
  Wire.write(reg);
  Wire.endTransmission();
  Wire.requestFrom(L3GD20_ADDR, 1);
  return Wire.read();
}

void setup() {
  Wire.begin();
  Serial.begin(9600);
  Serial.println(L3GD20_read(L3GD20_WHOAMI), HEX);
  Wire.beginTransmission(L3GD20_ADDR);
  Wire.write(L3GD20_CTRL_REG1);
  Wire.write(0x0f);
  Wire.endTransmission();
}

void loop() {
  int x, y, z;
  int h, l;

  l = L3GD20_read(L3GD20_OUT_X_L);
  h = L3GD20_read(L3GD20_OUT_X_H);
  x = (h << 8) | l;
  l = L3GD20_read(L3GD20_OUT_Y_L);
  h = L3GD20_read(L3GD20_OUT_Y_H);
  y = (h << 8) | l;
  l = L3GD20_read(L3GD20_OUT_Z_L);
  h = L3GD20_read(L3GD20_OUT_Z_H);
  z = (h << 8) | l;

  Serial.print(x);
  Serial.print("(");
  Serial.print(x*0.00875);
  Serial.print("),\t");
  Serial.print(y);
  Serial.print("(");
  Serial.print(y*0.00875);
  Serial.print("),\t");
  Serial.print(z);
  Serial.print("(");
  Serial.print(z*0.00875);
  Serial.println(")");

  delay(500);
}

実行するとX、Y、Zの取得値が表示されるかと思います。
MPU-6050の時と比べると何だか値がよくわからないのですが。。一応完了としておきます。

SPIモードでArduinoと接続

以下説明書からの引用です。
  1. SPC(2ピン)、SDI(3ピン)、SDO(4ピン)、CS(5ピン)の4線で接続します。
    • 2:SPC - 13:SCK
    • 3:SDI - 11:MOSI
    • 4:SDO - 12:MISO
    • 5:CS - 10:SS
  2. CS=Lでアクテイブ、クロックアイドル時=H、クロック立ち上がりでデータ読み込みです。
配線は以上で完了です。

#include

const int L3GD20_CS = SS;

const byte L3GD20_ADDR = 0x6a;
const byte L3GD20_WHOAMI = 0x0f;
const byte L3GD20_CTRL_REG1 = 0x20;
const byte L3GD20_OUT_X_L = 0x28;
const byte L3GD20_OUT_X_H = 0x29;
const byte L3GD20_OUT_Y_L = 0x2A;
const byte L3GD20_OUT_Y_H = 0x2B;
const byte L3GD20_OUT_Z_L = 0x2C;
const byte L3GD20_OUT_Z_H = 0x2D;

const byte L3GD20_RW = 0x80;
const byte L3GD20_MS = 0x40;

byte L3GD20_read(byte reg) {
  byte ret = 0;

  digitalWrite(L3GD20_CS, LOW);
  SPI.transfer(reg | L3GD20_RW);
  ret = SPI.transfer(0);
  digitalWrite(L3GD20_CS, HIGH);

  return ret;
}

void setup() {
  digitalWrite(SS, HIGH);
  pinMode(SS, OUTPUT);

  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV8);

 Serial.begin(9600);
 while (!Serial) {}

  Serial.println(L3GD20_read(L3GD20_WHOAMI), HEX);
  digitalWrite(L3GD20_CS, LOW);
  SPI.transfer(L3GD20_CTRL_REG1);
  SPI.transfer(B00001111);
  digitalWrite(L3GD20_CS, HIGH);
}

void loop() {
  short h, l;
  float x, y, z;

  l = L3GD20_read(L3GD20_OUT_X_L);
  h = L3GD20_read(L3GD20_OUT_X_H);
  x = (h << 8) | l;
  l = L3GD20_read(L3GD20_OUT_Y_L);
  h = L3GD20_read(L3GD20_OUT_Y_H);
  y = (h << 8) | l;
  l = L3GD20_read(L3GD20_OUT_Z_L);
  h = L3GD20_read(L3GD20_OUT_Z_H);
  z = (h << 8) | l;

  Serial.print(x);
  Serial.print("(");
  Serial.print(x*0.00875);
  Serial.print("),\t");
  Serial.print(y);
  Serial.print("(");
  Serial.print(y*0.00875);
  Serial.print("),\t");
  Serial.print(z);
  Serial.print("(");
  Serial.print(z*0.00875);
  Serial.println(")");

  delay(500);
}

実行してみるとI2Cと同じようにX、Y、Zの取得値が表示されますが、何故かしらSPIの値の方が想定値っぽい気が。。I2Cのソース何か間違ってるかも。

何にせよ、L3GD20を用いたI2C、SPIの両モードの使い方でした。

0 件のコメント:

コメントを投稿