公式のライブラリ使ってるのに、うまく動かないのだが…
SpeedStudioのADXL345 + M5stack、開発環境はPlatformIO。
SpeedStudioのライブラリをインストールして測定が…できない!?
設定項目も多く、こういう時はデータシートで順に見ていくのが良い。
そこで本記事ではデータシート見ながら、ADXL345の使い方についてまとめていきます。
※書きながらまとめていくんで、読みづらかったらごめんなさいね。
はじめに
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関数って何かトラブルが多い気がする…。
コメント