NETMF : I2C 接続のセンサーモジュール活用例(三軸加速度センサー ADXL345 の場合)

I2C の使用例としてキャラクターディスプレイモジュールについてすでに紹介しました。
キャラクターディスプレイは出力モジュールなので、マイコンボードからのコマンドも出力方向のみ(キャラクターディスプレイからデータを読み打差宇ことはない)でした。

今回は双方向のデータ通信について紹介します。センサーデバイスですね。
センサーデータを要求するコマンドをマイコンボードからモジュールに送信し、センサーデータをマイコンボードで受け取るという通信です。
モジュールによって通信に使う領域(レジスター)は異なりますが、送受信ともに既定の領域を使ってデータをやりとりします。


今回使用するモジュール

センサーモジュールの例として、今回は ADXL345 を使用します。3軸の加速度センサーです。
安価で入手しやすいモジュールです。
PinKit のセンサーボードをお持ちの方は以下のコードがそのまま使えます。
GR-PEACH のみで購入して PinKit のセンサーボードを持っていない方は秋月あたりでモジュールを購入できます。

WP_20150313_006WP_20151103_003

※写真では実験用シールドに ADXL345 を載せていますが、もちろん普通のブレッドボードなどを使ってもかまいません。加速度センサーは持ち上げて傾けるのでブレッドボードが分かれているよりマイコンボードと一体化しているほうがやりやすいというだけの理由です。


ADXL345 固有の情報

ADXL345 を使うにあたって必要な(モジュール固有の情報)をまとめておきます。

I2C アドレスは、私が使った上記のモジュールでは 0x1d です。

レジスタ(通信のための領域)のうち、最低限必要なものは以下です。

  • 0x2d・・・電源管理(センサーデータ取得でも使います)
  • 0x31・・・データフォーマット(加速度の測定範囲を設定)
  • 0x32~0x37・・・x, y, x 方向の加速度データ

I2CDevice の継承クラス

.NET Micro Framework の I2CDevice クラスは少しだけ不便なところがあるので、少し拡張してあげます。
これは I2C キャラクターディスプレイの例で紹介したものと同じです。

using Microsoft.SPOT.Hardware;

namespace AccelTest01
{
    public class I2CDeviceEx
    {
        private readonly I2CDevice _i2C;
        private readonly int _timeout;

        private readonly byte[] _adata = new byte[1];   // アドレス指定用のバイトデータ領域
        private readonly byte[] _rdata = new byte[1];   // データ受信用のバイトデータ領域
        private readonly byte[] _wdata = new byte[2];   // データ送信用のバイトデータ領域

        private I2CDevice.I2CTransaction[] _trRegRead;      // データ受信用のトランザクションデータ
        private I2CDevice.I2CTransaction[] _trRegWrite;     // データ送信用のトランザクションデータ

        public I2CDeviceEx(ushort i2CAddress, int clockRateKhz = 100, int timeout = 1000)
        {
            _i2C = new I2CDevice(new I2CDevice.Configuration(i2CAddress, clockRateKhz));
            _timeout = timeout;

        }

        protected byte RegRead(byte reg)
        {
            _adata[0] = reg;
            _trRegRead = new I2CDevice.I2CTransaction[] {
                I2CDevice.CreateWriteTransaction(_adata),
                I2CDevice.CreateReadTransaction(_rdata) };
            _i2C.Execute(_trRegRead, _timeout);
            return _rdata[0];
        }

        protected void RegReads(byte reg, ref byte[] data)
        {
            _adata[0] = reg;
            _trRegRead = new I2CDevice.I2CTransaction[] {
                I2CDevice.CreateWriteTransaction(_adata),
                I2CDevice.CreateReadTransaction(data) };
            _i2C.Execute(_trRegRead, _timeout);
        }

        protected void RegWrite(byte reg, byte val)
        {
            _wdata[0] = reg;
            _wdata[1] = val;
            _trRegWrite = new I2CDevice.I2CTransaction[] { I2CDevice.CreateWriteTransaction(_wdata) };
            _i2C.Execute(_trRegWrite, _timeout);
        }

        protected void RegWriteMask(byte reg, byte val, byte mask)
        {
            var tmp = RegRead(reg);
            _wdata[0] = reg;
            _wdata[1] = (byte)(tmp & ~(int)mask | ((int)val & (int)mask));
            _trRegWrite = new I2CDevice.I2CTransaction[] { I2CDevice.CreateWriteTransaction(_wdata) };
            _i2C.Execute(_trRegWrite, _timeout);
        }
    }
}

 


ADXL345 固有のクラス

ADXL345 固有の機能をクラスにまとめるとこうなります。

アプリからは Measure メソッドを呼び出したあとに GetXYZ メソッドを呼び出すと加速度データが得られます。
なお ADXL345 では測定範囲は設定により変更できますが、今回はサンプルということで 4G に固定しています。
このあたりの変更は GrFamilyLibrary のソースコードを参考にしていただければ。

public class Adxl345 : I2CDeviceEx
{
    private const byte PowerCtl = 0x2d;
    private const byte DataFormat = 0x31;
    private const byte DataX0 = 0x32;

    private byte[] _xyz = new byte[6];

    public Adxl345(ushort adxl345Address, int defaultClockRateKhz, int timeout) :
        base(adxl345Address, defaultClockRateKhz, timeout)
    {
        Thread.Sleep(1000);

        SetRange4G();
        ToWakeup();
    }

    public void Measure()
    {
        RegWriteMask(PowerCtl, 0x08, 0x08);
    }

    public void GetXYZ(out Int16 x, out Int16 y, out Int16 z)
    {
        RegReads(DataX0, ref _xyz);
        x = (Int16)(((UInt16)_xyz[1] << 8) + (UInt16)_xyz[0]);
        y = (Int16)(((UInt16)_xyz[3] << 8) + (UInt16)_xyz[2]);
        z = (Int16)(((UInt16)_xyz[5] << 8) + (UInt16)_xyz[4]);
    }

    private void SetRange4G()
    {
        // 4Gまで測定するには第2引数を 0x01
        // 2G・・・0x00, 4G・・・0x01, 8G・・・0x10
        RegWrite(DataFormat, 0x01);     
    }

    private void ToWakeup()
    {
        RegWriteMask(PowerCtl, 0x00, 0x04);     // 通常モードに入る(スリープモードではない)
    }
}

 


アプリケーションのコード例

ADXL345 を使うアプリケーションのコード例は以下の通り。

1秒間隔で加速度データを読み出しています。

.NET っぽくイベントハンドラーを使いたいなどは、(ここでもやはり)GrFamilyLibrary を参照してください。

public class Program
{
    private const ushort Adxl345Address = 0x1d;     // ADXL345のアドレス
    private const int DefaultClockRateKhz = 100;    // 転送速度 (KHz)
    private const int Timeout = 1000;               // 送受信ごとのタイムアウト

    public static void Main()
    {
        var prog = new Program();
        prog.Run();
    }

    private void Run()
    {
        var accel = new Adxl345(Adxl345Address, DefaultClockRateKhz, Timeout);

        while (true)
        {
            Int16 x;
            Int16 y;
            Int16 z;

            accel.Measure();
            accel.GetXYZ(out x, out y, out z);
            Debug.Print("X = " + x + ", Y = " + y + ", Z = " + z);

            Thread.Sleep(1000);
        }
    }
}

 


念のため、結線について

I2C は本当に結線が簡単ですが、念のため紹介しておくと以下のようにします。
※PinKit のセンサーボードをお持ちの方は、もちろん GR-PEACH に載せるだけ。

2016-01-16-18-23-51WP_20151103_004

広告
カテゴリー: .NET Micro Framework, GR-PEACH, GrFamilyLibrary, IoT ALGYAN タグ: , , , パーマリンク

NETMF : I2C 接続のセンサーモジュール活用例(三軸加速度センサー ADXL345 の場合) への1件のフィードバック

  1. ピンバック: NETMF : 複数の I2C モジュールを接続(三軸加速度センサー ADXL345+キャラクターディスプレイ) | 技術との戯れ

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中