Grove Beginner Kit for Arduinoの加速度センサーの使い方

組み込みエンジニア
本記事はプロモーションが含まれています。

こんにちは、ENGかぴです。

Grove Beginner kit for Arduinoは初心者のためのスターターキットです。加速度センサーなど複数のセンサーが実装されておりArduinoライブラリの使い方やC言語(C++)の学習ができます。

本記事ではGrove Beginner Kit for Arduino(Seeed Studio製)を使用してLIS3DHTR(以下、加速度センサーとする)の加速度の情報を取得してOLEDに表示します。

Grove Beginner kit for Arduino(以下スターターキットとします。)はArduino UNOと同じシリーズのマイコンを使用しているためArduino UNOと同じように開発することができます。Arduinoのライブラリを使用して動作確認したことをまとめています。

Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方

広告

開発環境の作り方

スターターキットの詳細はSeeed Studioのページにまとめられています。Arduinoライブラリの説明やセンサーの使用例やPWMの考え方などが解説されています。

Grove Beginner Kit for Arduino – Seeed Wiki (seeedstudio.com)

日本語対応のページが作成されていませんが、Google Chromeのブラウザーによる変換機能を使用することで日本語でページを表示することができます。

スターターキットにはソフトがプリインストールされているためUSBを接続すると各センサーの動作を確認することができます。プリインストールされているソフトは公開されているのでいつでも初期状態に戻すことができます。

タイマ管理で使用するMsTimer2ライブラリとOLEDの表示を行うU8g2ライブラリは標準ライブラリとして搭載されていないためライブラリマネージャーで追加します。ライブラリの追加の仕方や使用例については下記記事にまとめています。

Grove Beginner Kit for Arduinoの使い方

Grove Beginner Kit for Arduinoの照度センサーの使い方

MsTimer2はOLEDの表示を更新するタイミングを管理し、U8g2は取得したデータをOLEDに表示する目的で使用します。

加速度センサーからデータを取得する

加速度センサーはWire(I2C)でデータを取得します。加速度センサーの初期設定からデータ取得の手順をまとめています。加速度センサーのFIFOモードを使用して加速度センサーが測定している加速度の情報を取得します。またシングルタッチ及びダブルタッチのイベントを検知します。

広告

加速度センサーの設定を行う

加速度センサーは測定条件の初期化を行ってからデータを取得します。加速度のレンジを選択するレジスタ、FIFOモードの設定のレジスタ、イベント検出のレジスタの設定を行います。

LIS3DHTRのデータの取得手順
  • 手順1
    デバイスの確認

    WHO_ AM_I (0Fh) レジスタを読み込んで0x33であるかを確認する。0x33であればデバイスと通信ができているので測定条件の初期化を行う。

  • 手順2
    レジスタの設定

    初期値から変更するレジスタの設定を行う。

  • 手順3
    加速度センサーから測定データを取得

    FIFO_SRC_REG (2Fh) レジスタのWTMビットを確認して、FIFOモードで格納しているサイズ分データを取得する。加速度データはOUT_X_L (28h) レジスタから6バイト分を取得し換算する。

  • 手順4
    イベント検出の確認

    加速度センサーのイベントを割り込みで通知する場合はINT1から出力される(Groveモジュールの場合)のでDIでピンの変化を検出した後、CLICK_SRC (39h)レジスタを読み込んで対象のビットが立っているかを確認する。

手順1はWireの初期化を行った後、デバイスが存在するか確認を行います。0x33が読み込めた場合はデバイスが応答しているので、手順2に進みレジスタの設定を行います。

手順2は初期値からレジスタの値を変更する場合に処理を追加します。加速度の情報を±2gで取得するだけの目的であれば処理を追加する必要がありません。設定変更する項目について以下にまとめています。

レジスタ設定値内容
CTRL_REG1 (20h)0x57サンプリングタイミング及び測定対象の軸を指定する。
ODR[3:0]:0101、Zen:1、Yen:1、Xen:1
CTRL_REG3 (22h)0x80割り込み要因を設定する。
I1_CLICK:1
CTRL_REG4 (23h)0x00フルスケールを指定する。
FS[1:0]:00:±2g、01:±4g、10:±8g、11:±16g
CTRL_REG5 (24h)0x40FIFOの使用を設定する。
FIFO_EN:1
FIFO_CTRL_REG (2Eh)0xc8FIFOモードを設定する。Steam-to-FIFOを指定する。
またFIFOで格納するデータ数を指定する。
FM[1:0]:11、FTH[4:0]:01000
INT1_DURATION (33h)0x20INT1の出力を設定
D[6:0]:0100000
CLICK_CFG (38h)0x09クリックイベントを指定する。
Sはシングルクリック、Dはダブルクリック
XS:1、YD:1
CLICK_THS (3Ah)0x2fクリックイベントを検出する閾値を指定する。
Ths[6:0]:0101111
TIME_LIMIT (3Bh)0x3fクリックイベントの検出タイムリミットを指定する。
TLI[6:0]:0111111
TIME_LATENCY (3Ch)0x1fシングルイベント検出からの待ち時間を指定する。
TLA[7:0]:00011111
TIME WINDOW (3Dh)0x2fLATENCYからダブルクリックを検出する時間を指定する。
TW[7:0]:00101111
設定を変更するレジスタと内容

データシートを確認しましたがTIME_LATENCY (3Ch)及びTIME WINDOW (3Dh)レジスタについては説明が不足しており正確に用途が分かりません。類似の加速度センサーに同様の設定があるので同じものと判断して指定しています。

CLICK_CFG (38h) レジスタでXS:1、XD:1のように同じ軸上でシングルクリックとダブルクリックを指定するとシングルクリックが検知できない現象がありました。XS:1(XD:1)のみの設定ではそれぞれ検出できているため設定の調整によるものかもしれません。

手順3はFIFOモードで測定している加速度データを取得します。FIFO_CTRL_REG (2Eh)レジスタのFTH[4:0]で指定した回数測定するとFIFO_SRC_REG (2Fh) レジスタのWTMビットがセットされます。加速度データはOUT_X_L (28h)レジスタから6バイト分を取得し換算します。

手順4はイベントが発生するとか加速度センサーのINT1ピンが一定期間HIGHになるのでDIで状態変化を確認した後、CLICK_SRC (39h)レジスタのビットを確認して発生したイベントを判別します。

スポンサーリンク

Wireライブラリの初期化

#include <Wire.h>

void setup() {

  Wire.begin(); //begin()内にアドレスを入れるとスレーブになる
  //Wire.setClock(100000); //クロック周波数を設定する場合にセット初期は100kHz
}

Wire(I2C)を使用する場合はWire.hをインクルードします。begin()関数の引数の有無によってマスタで動作するかスレーブで動作するかが決まります。引数に指定した値でスレーブ動作を開始します。マスタとして使用するため引数は無しとします。

クロックは設定しなければ初期条件(ライブラリのソースコードを確認すると100kHzになっている)となります。引数として指定した値に近似した値がクロック周波数になりますが誤差が大きくなると通信エラーの原因になるため注意が必要です。

I2Cによる信号はプルアップ抵抗にも影響するためクロックを早く設定しすぎると波形がなまってしまうこともあるので特に意識せず100kHzで十分だと思います。

PR:技術系の通信教育講座ならJTEX

Wire(I2C)の送信と実装例

Wireライブラリを使った送信の手順は以下の通りです。

  1. beginTransmission()関数で初期化とスレーブアドレスをセット
  2. write()関数で書き込み対象のアドレスをセット
  3. write()関数で書き込むデータをセット
  4. endTransmission()関数で送信

1~3まではデータの準備です。4のendTransmission()関数はスタート・コンディションの発行やコントロール・バイト(7ビットのスレーブアドレスを左詰めにして最下位ビットにWriteフラグ(0)をセット)の処理を行いデータを送信した(書き込んだ)後ストップ・コンディションの発行を行います。以下に実装例を示します。

void WriteData(uint8_t adr, uint8_t* dat, uint8_t sz){

  Wire.beginTransmission(LIS3DHTR_ADDRESS); //スタート・コンディションの発行
  Wire.write(adr);  //書き込む対象のアドレスをセット
  for( uint16_t i=0; i < sz; i++ ){
    Wire.write(*dat); //sz分データを書き込む
    ++dat;
  }
  Wire.endTransmission(); //ストップ・コンディションの発行
}

最初にbeginTransmission()関数で初期化とスレーブアドレスをセットします。

次に書き込む対象のレジスタのアドレスをwrite()関数でセットします。続けてszのサイズに応じてwrite()関数でデータをセットします。

最後にendTransmission()関数でスタート・コンディションからストップ・コンディションまでを含めたデータを送信します。

PR: ゼロからはじめるPython入門講座の申込 テックジム

Wire(I2C)の受信と実装例

Wireライブラリを使った受信の手順は以下の通りです。

  1. beginTransmission()関数で初期化とスレーブアドレスをセット
  2. write()関数で書き込み対象のアドレスをセット
  3. endTransmission()関数で送信
  4. requestFrom()関数で対象のアドレスのデータを取得する
  5. read()関数で取得したデータを読み込む

1~3まではスレーブアドレスに対して書き込み対象のアドレスを指定します。4のrequestFrom()関数はスタート・コンディションの発行やコントロール・バイト(7ビットのスレーブアドレスを左詰めにして最下位ビットにReadフラグ(1)をセット)の処理を行い指定した数のデータを取得し、ストップ・コンディションの発行を行います。

5は4で取得したデータを読み込みます。送信と異なる点はrequestFrom()でストップ・コンディションを発行するためendTransmission()の発行は必要ありません。以下に実装例を示します。

void ReadData(uint8_t adr, uint8_t* dat, uint8_t sz){

  if( sz > 1){
    adr |= 0x80; //最上位ビットを立てる
  }

  Wire.beginTransmission(LIS3DHTR_ADDRESS); //スタート・コンディションの発行
  Wire.write(adr); //書き込む対象のアドレスをセット(ライトで指定)
  Wire.endTransmission(); //ストップ・コンディションの発行
  Wire.requestFrom(LIS3DHTR_ADDRESS, sz); //受信開始(スタート(ストップ)・コンディションの発行)
  for( uint16_t i=0; i < sz; i++ ){
    *dat = Wire.read(); //len分だけデータをリードする
    ++dat;
  }
}

加速度センサーの仕様で連続してデータを読み込む場合はアドレスのMSB(最上位ビット)を立てる必要があります。読み込みサイズが1よりも大きい場合にMSBをセットします。

beginTransmission()関数で初期化とスレーブアドレスをセットします。次に書き込む対象のレジスタのアドレスをwrite()関数でセットします。endTransmission()関数でスレーブのレジスタを選択した状態にします。

requestFrom()関数でスレーブから指定した数のデータを取得します。read()関数で取得したデータを読み込んで格納します。例では引数で指定したアドレス(ポインタ指定)に取得したデータを格納しています。

PR:テックジム:プログラミングの「書けるが先で、理解が後」を体験しよう!

データの換算とチェック

int32_t sumxyz[3];
uint8_t out[6];
int16_t xdata;

//FIFO_SRCレジスタを確認
ReadData(REGISTER_FIFO_SRC_REG,&reg, 1);

if( reg & 0x80){ //WTMビットの確認
  cnt = reg & 0x1F;

  if(cnt >= 8){
    cnt = 8;
    sumxyz[0] = 0; 
  
    for( i=0;i < cnt; i++){ //FIFOで貯めたデータ分を繰り返す
      ReadData(REGISTER_OUT_X_L,&out[0], sizeof(out)); //6ビット取得
      xdata = ( out[1] << 8 )+ out[0]; //2バイトデータに変換
      sumxyz[0] += xdata; //平均をとるために総数を計算
    }
    //平均値を算出
    sumxyz[0] = sumxyz[0] / cnt;
    //左寄せで10bit/normal
    sumxyz[0] = (sumxyz[0] >> 6 ); 
    //フルスケールに合わせてgain/digitを入れる
    sumxyz[0] = sumxyz[0]*mode.gain;
    //mg→gに変換
    now.x = (float)sumxyz[0] /1000;
    
    Serial.print("X:");
    Serial.println(now.x);
  }
}

FIFOモードは測定した加速度データを一時的に保管するモードです。測定データが指定サイズ格納されるとFIFO_SRC_REG (2Fh) レジスタのWTMビットをセットしてデータが貯まっていることを通知します。

FIFOのサンプリングタイミングはCTRL_REG1 (20h) レジスタで100Hzを指定しているので10ms毎になります。またFIFOのサイズはFIFO_CTRL_REG (2Eh) で8を指定しているので本記事の条件では80ms毎にWTMビットがセットされます。

FIFOで取得したデータを2バイトデータに変換してから加速度データの平均値を計算します。平均化することでノイズなどの外乱や測定誤差による影響を少なくすることができます。FIFOのサイズは8回なので8回分加算した結果を8で割って平均値を算出します。

Normalモード時では2バイトデータにおいて左寄せの10ビットデータになっているので右に6回シフトすることで10ビットに変換します。

フルスケールによって1デジット当たりの加速度が異なるためフルスケールに応じてゲインを乗算します。Normalモード時では2gで4mg/デジット、4gで8mg/デジット、8gで16mg/デジット、16gで48mg/デジットになります。

最後に、gで表示するためにmgをgに換算するため1000で除算します。

広告

OLEDに測定データを表示する

U8g2ライブラリで測定値とイベント発生の様子を表示します。ライブラリの追加の仕方や使用例については下記記事を参考にしてください。

Grove Beginner Kit for Arduinoの使い方

Grove Beginner Kit for Arduinoの照度センサーの使い方

以下ではOLEDに測定値を表示する方法を中心に説明します。

void Show(void){

  u8g2.firstPage(); //バッファをクリア
  do{
    u8g2.setFont(u8g2_font_t0_16_mr);
    u8g2.setCursor(10, 16);
    u8g2.print("X:");
    u8g2.setCursor(30, 16);
    u8g2.print(now.x);

    if( timesigle > TIME_UP || timedouble > TIME_UP){
      u8g2.setCursor(80, 16);
      u8g2.print("EVENT");
    }

    if( timesigle > TIME_UP ){
      u8g2.setCursor(80, 32);
      u8g2.print("S");
    }
  }while(u8g2.nextPage());
}

最初にfirstPage()関数で内部のバッファをクリアします。

setFont()関数でOLEDに表示する文字のフォントを指定します。フォントの定義はライブラリのフォルダ(XXX\Arduino\libraries\U8g2\src\clib)にu8g2.hにあります。XXX\はArduinoのライブラリの保存先に指定しているアドレスです。

setCursor()関数でOLEDの表示位置にカーソルを合わせます。第1引数にX座標を指定します。X座標は画面左から右に向かって進みます。第2引数にY座標を指定します。Y座標は画面上から下に向かって進みます。

print()関数は引数に指定した文字列を表示します。変数を引数に指定した場合は引数の値を文字列に変換して表示します。print()関数で文字列と取得したデータを表示しています。

nextPage()関数で行データごとのデータを更新してOLEDの表示を作りますが、ウェイトが必要となるためdo while()で表示が終えるまでループさせています。本記事では約120ms必要でした。OLEDの表示は遅延が発生するため頻繁な更新はしないように調整が必要です。

スポンサーリンク

LIS3DHTRライブラリを追加して使用する(参考)

LIS3DHTRライブラリ追加
LIS3DHTRライブラリ追加

加速度センサー(LIS3DHTR)からWireライブラリで加速度データを取得する方法を説明しましたが、Arduino IDEでLIS3DHTRライブラリを追加する方法もあります。Seed Studio が公開しているLIS3DHTRライブラリを使用する方法を参考として説明します。

Arduino IDEのライブラリマネージャの検索欄にgrove lis3dhtrを入力するとライブラリの候補が表示されます。候補の中からGrove_3_Axis_Digital_Accelerometer_2g_to_16g_LIS3DHTRをインストールします。使用例は以下の通りです。

#include "LIS3DHTR.h"
#include <Wire.h>
#include <MsTimer2.h>

LIS3DHTR<TwoWire> LIS;  //IIC

#define TIME_UP 0
#define TIME_OFF -1
#define TIM_MEAS 10

int16_t timmeas = TIM_MEAS;
float x;
float y;
float z;

void mainTimer(void);

void setup() {

  Serial.begin(115200);
  LIS.begin(Wire, 0x19);
  delay(100);
  LIS.setOutputDataRate(LIS3DHTR_DATARATE_100HZ);
  LIS.setHighSolution(true);

  MsTimer2::set(10, mainTimer); // 10ms period
  MsTimer2::start();
}

void loop() {

  if(timmeas == TIME_UP){
    timmeas = TIM_MEAS;

    x = LIS.getAccelerationX();
    y = LIS.getAccelerationY();
    z = LIS.getAccelerationZ();

    Serial.print("X:");
    Serial.print(x);
    Serial.print(" Y:");
    Serial.print(y);
    Serial.print(" Z:");
    Serial.println(z);
  }
}
/* タイマ管理 */
void mainTimer(void){

  if(timmeas > TIME_UP){
    --timmeas;
  }
}

LIS3DHTR.hをインクルードします。LIS3DHTRクラスの変数に通信タイプを指定してインスタンス化します。例では通信タイプをI2C<TwoWire>を指定しLISでインスタンス化しています。

begin()関数でLIS関係の初期化を行います。第1引数にWire(Arduinoの環境でのI2Cのピン設定)を指定します。第2引数にスレーブアドレス(デフォルト値は0x18)を指定します。加速度センサーモジュールのスレーブアドレスに合わせて0x19を指定しています。

setOutputDataRate()関数で測定タイミングの設定を行います。例では100Hzを指定しています。測定の分解能を上げる場合はsetHighSolution()関数を使用します。

X軸の加速度はgetAccelerationX()関数、Z軸の加速度はgetAccelerationY()関数、Z軸の加速度はgetAccelerationZ()関数を使用します。

使用例のようにデータを取得した場所で関数をコールするだけで簡単に測定値が取得できるため手軽に動作確認できます。

PR:(即戦力のスキルを身に着ける:DMM WEBCAMP 学習コース(はじめてのプログラミングコース))

動作確認

加速度センサーの動作確認結果
加速度センサーの動作確認結果

加速度センサーモジュールのINT出力ピンをArduinoの6ピン(DI)に入力するためジャンパーをします。ジャンパーしない場合はイベントを検出することができません。

電源を入れると加速度データが表示されます。スターターキットの箱においてX軸方向に指でタッチするとシングルクリックとなりOLEDに「S」を表示します。Y軸方向に指でダブルクリック(シングルクリックを2回する)とOLEDに「D」を表示します。2つのイベントが同時に発生した場合は「S」「D」を同時に表示します。

Y軸をクリックしたときX軸が振動してしまうと誤検知してシングルクリックになることがありますが箱を固定できていると誤検知する頻度がかなり軽減できました。

スターターキットをいろいろな方向に傾けると連動してX、Y、Zの加速度データが変化することも確認できました。

広告

ソースコード全体

以下のソースコードはコンパイルして動作確認をしております。コメントなど細かな部分で間違っていたりやライブラリの更新などにより動作しなくなったりする可能性があります。参考としてお使いいただければと思います。

//#include "LIS3DHTR.h"
#include <Wire.h>
#include <MsTimer2.h>
#include <U8g2lib.h>

#define TIME_UP 0
#define TIME_OFF -1
#define TIME_INT 5
#define TIM_OLED 50
#define TIM_EVENT 500

#define LIS3DHTR_ADDRESS 0x19
#define REGISTER_WHO_AM_I 0x0F
#define REGISTER_CTRL_REG1 0x20
#define REGISTER_CTRL_REG3 0x22
#define REGISTER_OUT_X_L 0x28
#define REGISTER_CTRL_REG4 0x23
#define REGISTER_CTRL_REG5 0x24
#define REGISTER_FIFO_CTRL_REG 0x2E
#define REGISTER_FIFO_SRC_REG 0x2F
#define REGISTER_INT1_THS 0x32
#define REGISTER_INT1_DURATION 0x33
#define REGISTER_CLICK_CFG 0x38
#define REGISTER_CLICK_SRC 0x39
#define REGISTER_CLICK_THS 0x3A
#define REGISTER_TIME_LIMIT 0x3B
#define REGISTER_TIME_LATENCY 0x3C
#define REGISTER_TIME_WINDOW 0x3D

struct MODE
{
  uint8_t fs;
  uint8_t gain;
};

struct NOW_TYP{
  float x;
  float y;
  float z;
};

U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R2, /* reset=*/U8X8_PIN_NONE);
int16_t timoled = TIM_OLED;
int16_t timint = TIME_OFF;
int16_t timesigle = TIME_OFF;
int16_t timedouble = TIME_OFF;
uint8_t out[6];
MODE mode;
int16_t xdata;
int16_t ydata;
int16_t zdata;
bool intflg;
NOW_TYP now;

void Lis3Init(void);
void mainTimer(void);
void WriteData(uint8_t adr, uint8_t* dat, uint8_t sz);
void ReadData(uint8_t adr, uint8_t* dat, uint8_t sz);
void mainApp(void);
void Show(void);

void setup() {

  Serial.begin(115200);
  Wire.begin();

  pinMode(DD6,INPUT);
  Lis3Init();
  u8g2.begin();
  MsTimer2::set(10, mainTimer); // 10ms period
  MsTimer2::start();
}

void loop() {

  mainApp();
  if(timoled == TIME_UP){
    timoled = TIM_OLED;
    Show();
  }

  if(timesigle == TIME_UP){
    timesigle == TIME_OFF;
  }

  if(timedouble == TIME_UP){
    timedouble == TIME_OFF;
  }

}
/* タイマ管理 */
void mainTimer(void){

  if(timoled > TIME_UP){
    --timoled;
  }

  if( timint > TIME_UP ){
    --timint;
  }

  if( timesigle > TIME_UP ){
    --timesigle;
  }

  if( timedouble > TIME_UP ){
    --timedouble;
  }

}
/* OLED表示 */
void Show(void){

  u8g2.firstPage(); //バッファをクリア
  do{
    u8g2.setFont(u8g2_font_t0_16_mr);
    u8g2.setCursor(10, 16);
    u8g2.print("X:");
    u8g2.setCursor(30, 16);
    u8g2.print(now.x);

    u8g2.setCursor(10, 32);
    u8g2.print("Y:");
    u8g2.setCursor(30, 32);
    u8g2.print(now.y);
    
    u8g2.setCursor(10, 48);
    u8g2.print("Z:");
    u8g2.setCursor(30, 48);
    u8g2.print(now.z);

    if( timesigle > TIME_UP || timedouble > TIME_UP){
      u8g2.setCursor(80, 16);
      u8g2.print("EVENT");
    }

    if( timesigle > TIME_UP ){
      u8g2.setCursor(80, 32);
      u8g2.print("S");
    }

    if( timedouble > TIME_UP ){
      u8g2.setCursor(90, 32);
      u8g2.print("D");
    }
    
  }while(u8g2.nextPage());
}
/* メイン処理 */
void mainApp(void){
  uint8_t reg;
  uint8_t click;
  uint8_t cnt;
  int32_t sumxyz[3];
  uint8_t i;

  if( digitalRead(DD6) == HIGH){
    if( intflg == false ){
      intflg = true;
    }
    if( timint == TIME_UP ){
      timint = TIME_OFF;
        ReadData(REGISTER_CLICK_SRC, &click, 1);
        if( click & 0x10){
          Serial.println("Single-Click");
          timesigle = TIM_EVENT;
        }
        if( click & 0x20){
          Serial.println("Double-Click");
          timedouble = TIM_EVENT;
        }
        //Serial.println(click);
    }
  }
  else{
    intflg = false;
    timint = TIME_INT;
  }

  ReadData(REGISTER_FIFO_SRC_REG,&reg, 1);

  if( reg & 0x80){
    cnt = reg & 0x1F;

    if(cnt >= 8){
      cnt = 8;
      sumxyz[0] = 0; 
      sumxyz[1] =0;
      sumxyz[2] =0;
      for( i=0;i < cnt; i++){
        //FIFOで貯めたデータ分を繰り返す
        ReadData(REGISTER_OUT_X_L,&out[0], sizeof(out));
        xdata = ( out[1] << 8 )+ out[0];
        ydata = ( out[3] << 8 )+ out[2];
        zdata = ( out[5] << 8 )+ out[4];
        sumxyz[0] += xdata; //平均をとるために総数を計算
        sumxyz[1] += ydata;
        sumxyz[2] += zdata;
      }
      //平均値を算出
      sumxyz[0] = sumxyz[0] / cnt;
      sumxyz[1] = sumxyz[1] / cnt;
      sumxyz[2] = sumxyz[2] / cnt;
      //左寄せで10bit/normal
      sumxyz[0] = (sumxyz[0] >> 6 );
      sumxyz[1] = (sumxyz[1] >> 6 );
      sumxyz[2] = (sumxyz[2] >> 6 ); 
      //フルスケールに合わせてgain/digitを入れる
      sumxyz[0] = sumxyz[0]*mode.gain;
      sumxyz[1] = sumxyz[1]*mode.gain;
      sumxyz[2] = sumxyz[2]*mode.gain;

      now.x = (float)sumxyz[0] /1000;
      now.y = (float)sumxyz[1] /1000;
      now.z = (float)sumxyz[2] /1000;

      Serial.print("X:");
      Serial.println(now.x);
      Serial.print("Y:");
      Serial.println(now.y);
      Serial.print("Z:");
      Serial.println(now.z);
    }
  }
}
/* 初期化処理*/
void Lis3Init(void){
  uint8_t data;
  uint8_t reg;

  ReadData(REGISTER_WHO_AM_I, &data,1);
  Serial.println(data);

  if( data == 0x33){
    Serial.println("Lis3DHTR-OK");
    reg = 0x57; //100Hz X,Y,Zを測定を許可
    WriteData(REGISTER_CTRL_REG1, &reg, 1);   
    reg = 0x80; //I1_CLICK
    WriteData(REGISTER_CTRL_REG3, &reg, 1);
    reg = 0x00;
    mode.fs = 0; //2g
    switch (mode.fs){
    case 0:
      mode.gain = 4;
      break;
    case 1:
      mode.gain = 8;
      reg |= 0x10;
      break;
    case 2:
      mode.gain = 16;
      reg |= 0x20;
      break;
    case 3:
      mode.gain = 48;
      reg |= 0x30;
      break;
    default:
      break;
    }
    //FS[フルレンジ]の設定
    WriteData(REGISTER_CTRL_REG4, &reg, 1);
    reg=0x40; //FIFO_EN
    WriteData(REGISTER_CTRL_REG5, &reg, 1);
    reg=0xc8; //FIFO:Stream-to-FIFO FTH[]:0x08
    WriteData(REGISTER_FIFO_CTRL_REG, &reg, 1);
    reg=0x20; //D[] INT1の出力期間
    WriteData(REGISTER_INT1_DURATION, &reg, 1);
    reg=0x09; //YD XS
    WriteData(REGISTER_CLICK_CFG, &reg, 1);
    reg=0x2f; //ths[] clickの閾値
    WriteData(REGISTER_CLICK_THS, &reg, 1);
    reg=0x3f; //clickの検出タイムリミット
    WriteData(REGISTER_TIME_LIMIT, &reg, 1);
    reg=0x1f; //sイベント後の検出待ち
    WriteData(REGISTER_TIME_LATENCY, &reg, 1);
    reg=0x2f; //s後dを検出する時間
    WriteData(REGISTER_TIME_WINDOW, &reg, 1);
  }
}
/* データ書き込み */
void WriteData(uint8_t adr, uint8_t* dat, uint8_t sz){

  Wire.beginTransmission(LIS3DHTR_ADDRESS); //スタート・コンディションの発行
  Wire.write(adr);  //書き込む対象のアドレスをセット
  for( uint16_t i=0; i < sz; i++ ){
    Wire.write(*dat); //sz分データを書き込む
    ++dat;
  }
  Wire.endTransmission(); //ストップ・コンディションの発行
}
/* データ読み込み */
void ReadData(uint8_t adr, uint8_t* dat, uint8_t sz){

  if( sz > 1){
    adr |= 0x80; //最上位ビットを立てる
  }

  Wire.beginTransmission(LIS3DHTR_ADDRESS); //スタート・コンディションの発行
  Wire.write(adr); //書き込む対象のアドレスをセット(ライトで指定)
  Wire.endTransmission(); //ストップ・コンディションの発行
  Wire.requestFrom(LIS3DHTR_ADDRESS, sz); //受信開始(スタート(ストップ)・コンディションの発行)
  for( uint16_t i=0; i < sz; i++ ){
    *dat = Wire.read(); //len分だけデータをリードする
    ++dat;
  }
}

関連リンク

Arduinoのライブラリを使って動作確認を行ったことを下記リンクにまとめています。

Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方

Seeeduino XIAOで学べるソフト開発と標準ライブラリの使い方

ESP32-WROOM-32Eで学べるソフト開発と標準ライブラリの使い方

PR:エンジニア転職なら100%自社内開発求人に強い【クラウドリンク】

最後まで、読んでいただきありがとうございました。

タイトルとURLをコピーしました