2013年10月28日月曜日

秋月のLIS3DH加速度センサー

半年ぐらい前、秋月で買ってきたまま部品箱の肥やしになっていたLIS3DHという三軸加速度センサーモジュールを週末にArduinoにつないでみることにした。 ネットを検索すればコードのサンプルでも出てくるかと思ったんだけど、適当なサンプルが見つからなかったので、データシートを読むことになっちゃった。
接続はSPIで、普通にArduino側の11,12,13をMOSI,MISO,SCKに使い、10ピンをセレクトに使う。



ArduinoAkizuki LIS3DH
MOSIDIGITAL 11--- SDIpin 4
MISODIGITAL 12--- SDOpin 5
SCKDIGITAL 13--- SPCpin 3
SSDIGITAL 10--- CSpin 6
電源3.3V--- VDDpin 1
GNDGND--- GNDpin 2
Arduino側のピンと、秋月のモジュール側のピン(LIS3HDのピンではないので注意)は表の通り。
MOSIとSDI、MISOとSDO、SCKとSPC、そしてSSとして使うArduinoの10ピンをcsにつなぐ。
そして電源はArduinoの3.3Vピンをモジュール側の1、グランドは2につなぐ。

とりあえずこれで接続はOK。次はコードを書くだけ、SPIライブラリがあるから楽勝だろうと思ったのだけど、まあ、レジスタの設定だの読み出しの方法だの、試行錯誤をすることになった。参考にしたページはArduinoの圧力センサーとの接続、「LIS3DHとの接続がうまくいかない」というArduino Uno SPI Accelerometer Code Issueなど。
初期設定は、デフォルトの設定に従い、ビットオーダーをMSBFIRST、データモードはSPI_MODE3、クロック分割はSPI_CLOCK_DIV2をセット。コントロールレジスタ1には0x47をセットする。 コントロールレジスタ1の内容は、上位4ビットがサンプリングの周期で0100で50Hz。4ビット目がパワーモードでここは0にしてノーマル。下3ビットはXYZの有効/無効で、0111。つまり2進で01000111、16進で0x47、10進で71をセットする。 コントロールレジスタ1から6までの内容を設定することで、各種のモードや動作の設定ができる。データシート参照。
とりあえず下のようなコードを書いてみたところ、3軸とも加速度のデータは取れる。データの表現は2の補数。 ただ、気になるのはなぜか下位6ビットがゼロになっている。コントロールレジスタ4で感度の設定ができるので高感度モードにしたり、いろいろやってみたけど、やっぱり下位6ビットはゼロ。SPIの読み出しで何か間抜けなことをしてるのかもしれないけれど、とにかく加速度センサーが使える、ということで満足することにして、もう夜も更けたので今日はこのへんでおしまい。
この続きはやるかもしれないし、やらないかもしれない。どなたか下位6ビットの秘密をご存じの方は教えてください。
10/29修正: コントロールレジスタ4での感度設定が間違っていたことに気がついた。4ビット目のフラグのHRを1にすると分解能12ビット、0にすると分解能10ビットになる。setupの所でwriteRegister(CTRL_REG4, 0x08);を指定すれば12ビットの分解能で加速度を読み込める。「おかしーなー」と悩んでいた時は、3ビット目を立てたり降ろしたりしてたのでした。やっぱり間抜けなポカミスでした。

#include 

//Register Addresses:
const int OUT_X_L = 0x28; //X-axis acceleration data
const int OUT_X_H = 0x29;
const int OUT_Y_L = 0x2A; //Y-axis acceleration data
const int OUT_Y_H = 0x2B;
const int OUT_Z_L = 0x2C; //Z-axis acceleration data
const int OUT_Z_H = 0x2D;
const int CTRL_REG1 = 0x20; //Register that can enable,disable axes
const int CTRL_REG2 = 0x21;
const int CTRL_REG3 = 0x22;
const int CTRL_REG4 = 0x23;
const int CTRL_REG5 = 0x24;
const int CTRL_REG6 = 0x25;
const int WHO_AM_I = 0x0F; //Dummy register
const byte READ = 0b10000000;    // LIS3DH's read command
const byte WRITE = 0b00111111;   // LIS3DH's write command
const byte TEMP_CFG_REG = 0x1F;  //Temperature sensor
//Axis definitions
int x_axis = 1; 
int y_axis = 2; 
int z_axis = 3; 

//Arduino ss pin10
const int ss = 10; 

void setup() {
  pinMode(ss, OUTPUT); // we use this for the SS at pin 10
  SPI.begin(); //wake up the SPI bus
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE3);
  SPI.setClockDivider(SPI_CLOCK_DIV2);

  Serial.begin(115200);
  writeRegister(CTRL_REG1, 0x47);
  Serial.println(readRegister(WHO_AM_I));
  delay(100);
}

int getValue(int axis) {
  int Val = 0;
  int h,l; 
  if (axis == 1)  {
    l = readRegister(OUT_X_L);
    h = readRegister(OUT_X_H);
  }  else if (axis == 2)  {
    l = readRegister(OUT_Y_L);
    h = readRegister(OUT_Y_H);
  }  else if (axis == 3)  {
    l = readRegister(OUT_Z_L);
    h = readRegister(OUT_Z_H);
  }
  Val = ((h << 8) | l);
  return Val;
}

unsigned int readRegister(byte thisRegister) {
  unsigned int result = 0;   // result to return
  byte dataToSend = thisRegister | READ;
  digitalWrite(ss,LOW);
  SPI.transfer(dataToSend);
  result = SPI.transfer(0x00);
  digitalWrite(ss, HIGH);
  return result;
}

void writeRegister(byte thisRegister, byte thisValue) {
 byte dataToSend = thisRegister & WRITE;
 digitalWrite(ss,LOW);
 SPI.transfer(dataToSend);
 SPI.transfer(thisValue);
 digitalWrite(ss,HIGH);
}

void loop () {
  Serial.print(" x = "); 
  Serial.print(getValue(x_axis));
  
  Serial.print(" y = "); 
  Serial.print(getValue(y_axis));
  
  Serial.print(" z = "); 
  Serial.println(getValue(z_axis));

  delay(500);
}

0 件のコメント:

コメントを投稿