データシートを読んで、LIS331HH搭載三軸加速度センサモジュールを使いこなす

この記事は、[スイッチサイエンス社](https://www.switch-science.com/)で販売されている、[LIS331HH搭載3軸加速度センサモジュール](https://www.switch-science.com/catalog/570/)をArduinoで使いこなすためのドキュメントです。
![IMG_0403 2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412023/c9f6d899-1581-df09-db24-40e374773685.jpeg)

Githubにあるサンプルコードを使って動作を確認したのち、測定レンジを切り替えるための作業を、データシートを参照しながら説明していきます。

##サンプルコードを使って動かしてみる
この加速度センサは、Githubに[サンプルコード](https://github.com/sparkfun/SparkFun_LIS331_Arduino_Library)があるため、これでひとまずArduinoで動作を確認することができます。
ここでは、LIS331_I2C_Example.inoの方のコードを使ってみます。


このように配線を行い、プログラムを書き込むと、シリアルモニタから信号を確認できます。
![アセット 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412023/52bc3958-2993-3602-95c6-a7f4a0ea75a8.png)

ここでは、xl.convertToG(6,x)がx軸方向の加速度、yl.convertToG(6,y)がy軸方向の加速度、zl.convertToG(6,z)がz軸方向の加速度となり、単位はG(m/s^2)となります。

##データシートを読む
この加速度センサはHPで、プログラムで測定レンジを切り替え可能(±6g/±12g/±24g)と書かれていますが、デフォルト値は±6gとなっています。
この値を変更するために、[データシート](https://www.sparkfun.com/datasheets/Sensors/Accelerometer/LIS331HH.pdf)を参照します。

pdfファイル内でFull-scaleと検索すると、27ページ目に、このようなレジスタの説明が載っています。
![Screenshot 2019-08-15_14-37-31-874.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412023/6d8d0ceb-15ac-482a-3fde-6d1966033f6f.png)
画像元：https://www.sparkfun.com/datasheets/Sensors/Accelerometer/LIS331HH.pdf

ここで、FS1、 FS0のところを読んでみると、デフォルトの値が00であり、FS1,FS0が01の時は±12g、11の時は±24gとなることがわかります。
つまり、このレジスタの値を新たに書き込んでしまえば、測定レンジを変更することができます。

##ライブラリのファイルを読む

続いて、測定レンジを書き込むファイルの場所を探します。

[cppファイル](https://github.com/sparkfun/SparkFun_LIS331_Arduino_Library/blob/master/src/SparkFun_LIS331.cpp)を見てみると、251行目から以下のようなコードが見つかります。

```SparkFun_LIS331.cpp
void LIS331::setFullScale(fs_range range)
{
  uint8_t data; 
  LIS331_read(CTRL_REG4, &data, 1);
  data &= ~0xcf;
  data |= range<<4;
  LIS331_write(CTRL_REG4, &data, 1);
}
```
0xcfを2進数表示すると110011111、つまり、FS1とFS0の値は共にゼロに設定されていることがわかります。
そして、 data |= range<<4; という式が示すように、
rangeの値を入力することで、４つビットシフトされてdataの値に加算される、すなわち、FS1とFS0の値を設定することができます。

[ヘッダーファイル](https://github.com/sparkfun/SparkFun_LIS331_Arduino_Library/blob/master/src/SparkFun_LIS331.h)を見てみると、40行目に、
typedef enum {LOW_RANGE, MED_RANGE, NO_RANGE, HIGH_RANGE} fs_range;
と書かれています。これはつまり、rangeの値として、LOW_RANGEと入力すると0、MED_RANGEを入力すると1、NO_RANGEを入力すると2、HIGH_RANGEを入力すると3となるということです。
実際、LOW_RANGE0は2進数で00となり、FS1=0 FS0=0に一致、MED_RANGEは01でFS1=0 FS0=1に一致、HIGH_RANGEは11でFS1=1 FS0=1に一致します。


##サンプルコードを書き換える
いよいよ、Arduinoのサンプルコードを書き換えていきます。今回は測定レンジを±24gに変更します。
±24gはHIGH_RANGEに当たるので、void setup()内でxl.setFullScale(HIGH_RANGE); と書けば測定レンジは切り替わります。

書き換える場所はもう一点あります。加速度を単位Gで表示するxl.convertToG(6,x)らの中にある6は測定レンジを示すものであるため、24に変更します。
これで測定レンジを±24gに変更したコードができました。完成したコードは以下になります。

```LIS331_I2C_Example_acceralation.ino
#include "SparkFun_LIS331.h"
#include <Wire.h>

LIS331 xl;

void setup()
{
  // put your setup code here, to run once:
  pinMode(9, INPUT);      // Interrupt pin input
  Wire.begin();
  xl.setI2CAddr(0x19);    // This MUST be called BEFORE .begin() so
  //  .begin() can communicate with the chip
  xl.begin(LIS331::USE_I2C); // Selects the bus to be used and sets
  //  the power up bit on the accelerometer.
  //  Also zeroes out all accelerometer
  //  registers that are user writable.
  // This next section configures an interrupt. It will cause pin
  //  INT1 on the accelerometer to go high when the absolute value
  //  of the reading on the Z-axis exceeds a certain level for a
  //  certain number of samples.
  xl.intSrcConfig(LIS331::INT_SRC, 1); // Select the source of the
  //  signal which appears on pin INT1. In
  //  this case, we want the corresponding
  //  interrupt's status to appear.
  xl.setIntDuration(50, 1); // Number of samples a value must meet
  //  the interrupt condition before an
  //  interrupt signal is issued. At the
  //  default rate of 50Hz, this is one sec.
  xl.setIntThreshold(2, 1); // Threshold for an interrupt. This is
  //  not actual counts, but rather, actual
  //  counts divided by 16.
  xl.enableInterrupt(LIS331::Z_AXIS, LIS331::TRIG_ON_HIGH, 1, true);
  // Enable the interrupt. Parameters indicate
  //  w  which interrupt source we're configuring,
  //hich axis to sample, when to trigger
  //  (in this case, when the absolute mag
  //  of the signal exceeds the threshold),
  //  and whether to enable (true) or disable
  //  (false) the interrupt.
  xl.setFullScale(HIGH_RANGE);

  Serial.begin(115200);
}

void loop()
{
  static long loopTimer = 0;
  int16_t x, y, z;
  if (millis() - loopTimer > 0)
  {
    loopTimer = millis();
    xl.readAxes(x, y, z);  // The readAxes() function transfers the
    //  current axis readings into the three
    //  parameter variables passed to it.
    // Serial.println(x);
    // Serial.println(y);
    // Serial.println(z);
    // Serial.println(xl.convertToG(6,x)); // The convertToG() function
    // Serial.println(xl.convertToG(6,y)); // accepts as parameters the
    // Serial.println(xl.convertToG(6,z)); // raw value and the current
    // Serial.println(" ");                // maximum g-rating.


    Serial.println(sqrt(pow(xl.convertToG(24, x), 2) + pow(xl.convertToG(24, y), 2) + pow(xl.convertToG(24, z), 2)));
    Serial.println("\n");

  }
  if (digitalRead(9) == HIGH)
  {
    Serial.println("Interrupt");
  }
}
```