PR

3軸加速度センサ「ADXL345」の使い方まとめ

アナデバの3軸加速度センサ「ADXL345」の使い方 組み込み機器

公式のライブラリ使ってるのに、うまく動かないのだが…

SpeedStudioのADXL345 + M5stack、開発環境はPlatformIO。

SpeedStudioのライブラリをインストールして測定が…できない!?

設定項目も多く、こういう時はデータシートで順に見ていくのが良い。

そこで本記事ではデータシート見ながら、ADXL345の使い方についてまとめていきます。
※書きながらまとめていくんで、読みづらかったらごめんなさいね。

立プロ

新卒でメーカーに入り、10年間組み込みの現場で設計を行う。
今は個人事業主として自作の組み込み機器開発や、エージェント様に紹介いただき業務委託を行っています。
C,C#,JavaScript, Vue, PHP, VBA, GAS, Kotlinなど、扱う言語が増えゆく日々。

立プロをフォローする

はじめに

ADXL345はアナデバ製の3軸加速度センサです。

データシートはこちらを参照。

多くの会社がキットにして販売してますが、今回使用するSpeedStudioが販売するADXL345はI2Cによる通信を行うものになってます。

電源系統のセットアップ

まず、ADXL345はセンサに電源が入るとスタンバイ状態になります。

このままでは測定できなくて、POWER_CTL レジスタ(アドレス 0x2D)のMeasureビットを1にすることで測定が開始されます。

Measure ビットをクリアすると、デバイスはスタンバイ・モードに戻ります。

電力モード

ADXL345は設定した出力レートによって消費電力の自動調整機能が内蔵されますが、節電モードに設定することもできます。

BW_RATEレジスタ(アドレス0x2C)のLOW_POWER ビット(ビット 4)をセットすることで低消費電力モードになります。

ただ電力落とした分、サンプリングレートが下がるので、ノイズによる影響を受けやすくなるのがデメリット。

何かのタイミングで動作させる場合は、スリープモードで電力を落とすこともできます。

インアクティブスリープの機能を有効にするには、THRESH_INACT レジスタ(アドレス 0x25)と TIME_INACT レジスタ(アドレス 0x26)をそれぞれ設定してから、POWER_CTL レジスタ(アドレス 0x2D)の AUTO_SLEEP ビットと Link ビットをセットします。

まあ、言っても上限140uA, 下限23uAの電力使用量ですからね、無線通信とか使うこと考えると、節電しなくても…とか思っちゃいますね。

シリアル通信

ADXL345はSPIとI2Cに対応しています。

ピン配置によって切替ができて、SpeedStudioのADXL345はI2C、アドレス0x53が設定されています。

割込み

これがまあたくさんあります…。それだけ用途があるってことですねえ。

ADXL345にはIN1, INT2の2つの割込み端子があります。

デフォルトでアクティブハイ(=High検出で割込み発生)ですが、アクティブローにも設定できます。

アクティブ・ローに変更するには、DATA_FORMAT(アドレス 0x31)レジスタのINT_INVERT ビット(ビット D5)をセットします。

情報が多すぎる…データシート見て下さい。

アクティブ / 非アクティブ

アクティブについて:
Activity ビットは、THRESH_ACT レジスタ(アドレス 0x24)に格納された閾値より大きい加速度が、ACT_INACT_CTL レジスタ(アドレス 0x27)で設定した関係する軸に生じた場合にセットされます。

Inactivity ビットは、THRESH_INACT レジスタ(アドレス 0x25)に格納された値より小さい加速度が TIME_INACT レジスタ(アドレス 0x26)で指定された値よりも長い時間、ACT_INACT_CTLレジスタ(アドレス0x27)で設定した関係する軸に発生した場合にセットされます。TIME_INACT の最大値は 255 秒です。

adxl.setActivityThreshold(75); //62.5mg per increment
adxl.setInactivityThreshold(75); //62.5mg per increment
adxl.setTimeInactivity(10); // how many seconds of no activity is inactive?

75 * 62.5m = 4.6gでアクティブ、非アクティブが設定される。

10秒間、4.6gより小さい加速度だと、割込み発生する。

タップ/ダブルタップ

指定アドレスに情報を入れていきます。

例えば下記のように。

  Wire.beginTransmission(ADXL345_ADDR);//データ送信開始
  Wire.write(0x1D);//タップしきい値
  Wire.write(50);//62.5mg per increment 0.0625*50 = 3.125g
  Wire.endTransmission();//データ送信終了

0x2A:どの軸でタップ判定するか決める

0x1D:タップとみなすしきい値を決める

0x21:タップ時間(この時間以上、しきい値以上の加速度検出するとタップとみなさない)

0x22:タップ検出後の待ち時間(この時間だけ待って、ダブルタップ検出が始まる)

0x23:ダブルタップ検出の待ち時間

0x28:自由落下発生の判定機能有無(300~600mg推奨)

割込み

INT1かINT2ピンから外部出力させないといけないっぽい。

0x2E:どのイベント(タップや自由落下など)で割込み発生させるか

0x2F:割込み発生をINT1,INT2どちらかに出力させるか

測定値

0x31:データフォーマット

FULL_RESビットが0なら、10ビットモード。レンジビットで設定した最大値を10bitで均等割り。

FULL_RESビットが1なら、最大分解能モードになり、4mg/LSBとなる。

レンジは±2,4,8,16から選択可。

0x33にx軸の上位8ビット、0x32にx軸の下位8ビットが格納。

次に同じようにY,Zの値が入っている。

だから、X,Y,Zそれぞれ2バイトで格納される。

ただこれはカウント値であって、例えば最大分解能モードにしてて、カウント値が50だったとすると、

50 * 0.004 * g = 0.2g

となるわけだよね。

g=9.80665とすると、

0.2 * 9.80665 = 1.96m/(s^2)

と、加速度を計算できる。

ちなみに、重力加速度は常に働くので、ある軸方向にセンサ向きを設定するとその方向に対して9.80665m/(s^2)が出力されるはずだから、セットアップの際は重力加速度で確認するとよいです。

なぜライブラリ使ったサンプルコードが動作しないのか

PlatformIOでライブラリのサンプルコードをコピペして動かしてもダメなんですねえ。

  adxl.setActivityX(1);

センサ電源をONにして、アクティビティ設定をやると固まります。

これを深堀すると、

void ADXL345::setActivityX(bool state) {  
    setRegisterBit(ADXL345_ACT_INACT_CTL, 6, state); 
}

↓setRegisterBit関数の中を見ると

void ADXL345::setRegisterBit(byte regAdress, int bitPos, bool state) {
    byte _b;
    readFrom(regAdress, 1, &_b);

    if (state) {
        _b |= (1 << bitPos);  // forces nth bit of _b to be 1.  all other bits left alone.
    } 
    else {
        _b &= ~(1 << bitPos); // forces nth bit of _b to be 0.  all other bits left alone.
    }
    writeTo(regAdress, _b);  
}

↓readFrom関数の中を見ると

// Reads num bytes starting from address register on device in to _buff array
void ADXL345::readFrom(byte address, int num, byte _buff[]) {
    Wire.beginTransmission(ADXL345_DEVICE); // start transmission to device 
    Wire.write(address);             // sends address to read from
    Wire.endTransmission();         // end transmission
    Wire.beginTransmission(ADXL345_DEVICE); // start transmission to device
    Wire.requestFrom(ADXL345_DEVICE, num);    // request 6 bytes from device
    int i = 0;
    while(Wire.available())         // device may send less than requested (abnormal)
    { 
        _buff[i] = Wire.read();    // receive a byte
        i++;
    }
    if(i != num){
        status = ADXL345_ERROR;
        error_code = ADXL345_READ_ERROR;
    }
    Wire.endTransmission();         // end transmission
}

こうなってるわけです。ここのrequeesFromで止まるんですね。

で、これはなぜかと言うと、直前にbeginTransmissionで送信開始準備をしてるからです。

requestFromは受信の関数なわけですよ。送信じゃなくて。

だから、コメントアウトするなりして、beginTransmissionを取り除けばよい。

あと、下にもendTransmissionが入っているので、これも取り除く。

すると、requestfromは問題なく動作します。

まとめ

SpeedstudioのADXL345サンプルコードが動作しないのは、requestfromで止まるから。

止まる原因として、受信したいのに直前に送信設定をしてるから。

ArduinoのWire関数って何かトラブルが多い気がする…。

コメント

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