NETMF : 複数の I2C モジュールを接続(三軸加速度センサー ADXL345+キャラクターディスプレイ)

I2C の使用例として、これまで二つ紹介しました。

今回は I2C モジュールを二つ接続してみます。

WP_20160118_10_18_49_Pro

I2C のメリットは、複数のモジュールがあっても信号線 2本+電源の接続で済むこと。
I2C の概要は こちら のエントリーを参照していただければ。


I2CDevice の継承クラス / ADXL345 固有のクラス

.NET Micro Framework の I2CDevice クラスを使いやすくする拡張、および ADXL345 (三軸加速度センサー)は、こちらのコード がそのまま使えます。
特に変更する必要はありません。名前空間が気に入らなければ適当に変更してください。


キャラクターディスプレイのクラス

キャラクターディスプレイクラスは こちらのコード が使える・・・のですが、今回は 8×2行の別のモジュール、AQM0802A-RN-GBW を使ってみました。
理由は、実験用シールドに加速度センサーとキャラクターディスプレイの両方を載せるため。

キャラクターディスプレイは多くがHD44780 互換なのですが、AQM0802A は拡張機能セットを使います。
標準的な機能セットと共通の部分が多いのですが、モジュールの初期化コマンドおよびキャラクター出力コマンドが標準とは異なります。

ということで、以下のコードにします。

public class Aqm0802A : I2CDeviceEx
{
    private bool _displayOn = true;         // ディスプレイをオンにするか
    private bool _cursorOn = false;         // カーソルを表示するかどうか
    private bool _blinkOn = false;          // カーソル位置でブリンクするか

    private readonly int _commandWait = 1;  // コマンド実行後のウェイト

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

        // AQM0802A は HD44780 の拡張機能セットを使用する
        // 以下は拡張機能セットでの初期化コマンド
        // 標準機能セットを使用するモジュールについては以下を参照
        //   yseosoft.wordpress.com/2015/12/31/i2c_clcd_demo/ の記事
        //   GrFamilyLibrary のソースコード (github.com/netmf-lib-grfamily/GrFamilyLibrary)
        WriteCommand(0x38);         // 標準機能セットを指定
        WriteCommand(0x39);         // 拡張機能セットを指定
        WriteCommand(0x14);         // 内部オシレーター周波数を指定
        WriteCommand(0x70);         // コントラストを指定(下位4ビット)
        WriteCommand(0x56);         // コントラストを指定 (上位4ビット)
        WriteCommand(0x6c);         // フォロワーコントロール
        WriteCommand(0x38);         // 標準機能セットに戻す
        WriteCommand(0x0c);         // 表示オン

        WriteCommand(0x01);         // 表示クリア
        WriteCommand(0x06);         // カーソルと表示のシフト設定
        WriteCommand(0x0c);         // カーソルとブリンクの表示をオフ

        Thread.Sleep(100);
    }

    public void Print(string msg)
    {
        for (var i = 0; i < msg.Length; i++)
        {
            WriteCharactor((byte)msg[i]);
        }
    }

    // 表示クリア
    public void Clear()
    {
        WriteCommand(0x01, 5);      // Clear Displayはウェイトが必要
    }

    // カーソルを初期位置に戻す
    public void Home()
    {
        WriteCommand(0x02, 5);      // Return Homeはウェイトが必要
    }

    public void DisplayOn(bool displayOn)
    {
        ControlDisplay(displayOn, _cursorOn, _blinkOn);
        _displayOn = displayOn;
    }

    // カーソル表示オン・オフを切り替える
    public void CursorOn(bool cursorOn)
    {
        ControlDisplay(_displayOn, cursorOn, _blinkOn);
        _cursorOn = cursorOn;
    }

    // カーソル位置のブリンクのオン・オフを切り替える
    public void BlinkOn(bool blinkOn)
    {
        ControlDisplay(_displayOn, _cursorOn, blinkOn);
        _blinkOn = blinkOn;
    }

    public void SetCursor(int row, int col)
    {
        var addr = (byte)(((byte)row) << 6) + (byte)col;
        WriteCommand((byte)(0x80 | addr));
    }

    private void ControlDisplay(bool displayOn, bool cursorOn, bool blinkOn)
    {
        var cmd = (byte)0x08;
        if (displayOn)
            cmd |= 0x04;
        if (cursorOn)
            cmd |= 0x02;
        if (blinkOn)
            cmd |= 0x01;

        WriteCommand(cmd, _commandWait);
    }

    public void WriteCharactor(byte data)
    {
        // AQM0802A は拡張機能セットを使うので 0x40
        // 標準機能セットの場合は 0x80
        RegWrite((byte)0x40, data);
    }

    public void WriteCommand(byte cmd, int wait = 1)
    {
        var reg = (byte)0x00;
        RegWrite(reg, cmd);
        Thread.Sleep(wait);
    }
}

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

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

public class Program
{
    private const ushort Adxl345Address = 0x1d;     // ADXL345のアドレス
    private const ushort Aqm0802AAddress = 0x3e;    // AQM0802A-RN-GBWのアドレス
    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);
        var lcd = new Aqm0802A(Aqm0802AAddress, DefaultClockRateKhz, Timeout);

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

            accel.Measure();
            accel.GetXYZ(out x, out y, out z);

            lcd.Clear();
            lcd.Print(x.ToString() + "," + y.ToString());
            lcd.SetCursor(1, 0);
            lcd.Print(z.ToString());

            Thread.Sleep(1000);
        }
    }
}

加速度センサーの使い方、キャラクターディスプレイの使い方が分かれば、(当然ですが)特に不思議なところも難しいところもないですね。


結線

結線は以下の通り。

I2C モジュールは信号線をパーティーライン状に接続するだけです。通信時にモジュールのアドレスが含まれているので(.NET Micro Framework では隠蔽されていますが)、どちらに対しても正しくデータを送受信できます。

WP_20160118_10_17_03_Pro2016-01-18 16-06-59

コメントを残す