記事

Raspberry PiにI2CインターフェースのLCDモジュールを接続する(5)I2cDeviceの作成

複数のI2Cを利用するデバイスを作る

 今回は、最初の変数名などの有効領域について確認し、その後それぞれのI2C通信を行うI2cDeviceを作成します。

定義した名前の有効範囲
 今回作成しているプログラムで、実際にコーディングしているのはMainPage.xaml.csとMainPage.xmalのウィンドウの表示を設定する二つのソース・ファイルです。画面の設定のためのMainPage.xmalはデザイナーとプロパティの設定ウィンドウでコードを書かずに済ますこともできます。しかし実際の処理を記述するMainPage.xaml.csは、一つ一つ具体的に実行する処理を記述しなければなりません。
 このMainPage.xaml.csはつぎのような書き方をしています。

using System;
    { ・・・


 ここに、今回使用するシステムが提供するクラス(プログラムの設計図)が属するnamespaceを利用することを宣言します。この記述で、利用するクラスが属するnamespaceの記述を省略することができるようになります。I2Cの処理を行うI2cDviceクラスを使用するので、using Windows.Device.I2c;を追加しています。その他、テンプレートで用意されたものに対して必要に応じて追加削除しています。

namespace i2clcd010015
   

 プロジェクト名のついた名前空間(namespace)を設定します。この名前空間の から の範囲にMainPage.xaml.csの具体的なプログラムを記述します。初期画面を表示するプログラムのためのMainPageのクラスを定義し、その後にMainPageのインスタンス、その他の処理を記述します。

  public sealed partial class MainPage : Page
        {


  システムが用意したSystem.Windows.Controlsの名前空間のPageクラスを継承して、初期画面の表示などを行うためのもとになるMainPageのクラスを定義しています。このpublic sealed partial class MainPage : Pageはテンプレートとして提供されるプログラムの記述をそのまま利用しています。
 publicは、このクラスのアクセスについては制限がなくこのクラス以外からもアクセスできることを示します。privateの場合は、定義されているクラスからのアクセスとなります。
 sealedは、このクラスを継承することができないと設定します。
 partialは、このクラスのファイルが大きくなったときに分割することができることを示します。

 classは、「:」に続く「Page」で示されたPageクラスをもとに「Main.Page」のクラスを新たに定義します。

 クラスで使用する各種のオブジェクトなどを定義します。クラスで利用するオブジェクトなどの定義は、ここで行うとわかりやすくなります。

 具体的なプログラムの記述、

public MainPage(){


 今回定義したクラスMainPageで最初に実行されるプログラムです。テンプレートにクラスと同じMainPageの名で定義され、画面表示の初期化を行うコードthis.InitializeComponent();もセットされています。
 このコードの後に必要なコードを追加します。


private ・・・・(){


 各種の処理を行うモジュールを必要に応じて追加していきます。

                  }
     }クラス MainPageの終わり
 名前空間 i2clcd010015の終わり

I2C接続LCDキャラクタ・ディスプレイの接続
 I2C接続キャラクタ・ディスプレイは、現状市販されているものは次のような理由で、Raspberry Piに直接接続してデータを表示することができません。

I2C接続キャラクタLCDモジュール(ACM1602NI-FLW)
 スタンダード・モードの100kHzのスピードで、マスタからこのモジュールに要求を出しても、ACKを返さなくI2C通信ができません。ACM1602NI-FWのデータシートを見るとSCLの信号のTlowの最小値が5.2usとI2Cの規格の4.7usより大きく、I2Cの100kHzより低い96kHz以下のスピードでなければ通信できないようです。
 Raspberry PiのI2Cのスタンダード・モードで、ACM1602NI-FLWへ通信要求を出してもACKは返ってきません。
 そのときの波形のようすです。アドレス 0x50にR/Wの1ビットを最下位に追加した0xa0を書き込み、LCDモジュールはACKをLOWにすることなくHIGHのままです。

 Arduinoに接続して波形を見ると、0xa0を書き込むと9番目のSCLのパルスに合わせてLOWのACKが戻っています。次にデータを示す0x00が送信され、ACKが戻り、その後0x38の8の文字コードが送信されACKが返り、LCDモジュールへの送信が終わっています。

 Arduinoでは問題なく書き込みが行われていますが、Raspberry Piでは今のところ通信できません。

AQMシリーズのI2C接続キャラクタLCDモジュール
 I2C接続小型キャラクタLCDモジュール(8×2行のAQM0802A-RN-GBW)、I2C接続小型キャラクタLCDモジュール(16×2行のAE-AQM1602A(KIT))はACK信号を出力しますが、これらのモジュールのSDA端子のI2Cバスのドライブ能力が低く、ACK信号を完全なLOWとすることができなく通信ができません。
 そのため、I2Cバス・リピータPCA9515ADでLCDモジュールのバスのドライブ能力を増強する必要があります。
 I2Cバスの波形を次に示します。0x3EにR/Wの1ビットを0(W)にして追加し0x7Cの値を書き込んでいます。LCDモジュールからのACKのパルスはHIGHから少し下がっただけでLOWと認識できるレベルまで下がっていません。次回詳しく検討します。

I2Cバス・リピータ
 ACMシリーズのバスのドライブ能力不足を補うために、バス・リピータPCA9515ADを利用します。秋月電子通商必要な部品がありますので、昼間注文すると翌日には届きますので重宝しています。送料が500円かかりますが、交通費と時間のセーブを考え納得しています。

 PCA9515AD、DIP化、丸ピンIC連結ソケットを用意して、ブレッドボードでPCA9515ADを利用できるようにします。このICのピン間は通常のICの半分と狭く、はんだ付けに少し気合を入れる必要がありますが、慣れるとあまり苦になりません。

 丸ピンのIC連結ピンにはんだ付けすると、ブレットボードで利用できるようになります。
 はんだ付けの方法、PCA9515ADの詳しい話は次回以降再度行います。
 これらの準備の後、次に示す回路でテストを行います。

 次のプログラムで、LCDへの書き込みのテストを行いました。
 MainPage.xaml.csのソース・プログラムは次のものを利用しました。

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.Devices.Enumeration;
using Windows.Devices.I2c;
using System.Threading.Tasks;
using System.Text;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace i2clcd010015
{
    public sealed partial class MainPage : Page
    {
        private SolidColorBrush redBrush = new SolidColorBrush(Windows.UI.Colors.Red);
        private DispatcherTimer timer;
        private int cnt = 0;
        private I2cDevice I2CLCD;
        private byte LCD_I2C_ADDR = 0x3E;
        private I2cDevice tmp102i2c;
        private const byte TMP102_I2C_ADDR = 0x48;
        private I2cDevice I2CTMP102;
        private const byte I2CTMP102_REG_READ_TEMP = 0x00;

        public MainPage()
        {
            this.InitializeComponent();
            ledball.Fill = redBrush;
            textBlock.Text = "initialmsg";
            button.Content = "countup";
            InitI2c();
        }
        private async void InitI2c()
        {
            string aqs = I2cDevice.GetDeviceSelector();
            var dis = await DeviceInformation.FindAllAsync(aqs);
            var settings = new I2cConnectionSettings(TMP102_I2C_ADDR);
            settings.BusSpeed = I2cBusSpeed.FastMode;
            I2CTMP102 =await I2cDevice.FromIdAsync(dis[0].Id, settings);
            var settings2 = new I2cConnectionSettings(0x3E);
            settings2.BusSpeed = I2cBusSpeed.StandardMode;
            I2CLCD = await I2cDevice.FromIdAsync(dis[0].Id, settings2);
            Initlcd();
            i2cprint("stra12345");
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(500);
            timer.Tick += Timer_Tick;
            timer.Start();
        }
        private void i2cwritecmd(byte cmd)
        {
            byte[] writebuf = new byte[2] { 0x80, cmd };
            I2CLCD.Write(writebuf);
        }
        private void i2cwritedata(byte data)
        {
            byte[] writebuf = new byte[2] { 0xC0, data };
            I2CLCD.Write(writebuf);
        }
        void i2cprint(String pdata)
        {
            byte[] pd1 = Encoding.ASCII.GetBytes(pdata);
            byte[] pd0 = new byte[] {0x40 };
            byte[] writebuf = new byte[pd0.Length + pd1.Length];
            pd0.CopyTo(writebuf, 0);
            pd1.CopyTo(writebuf, pd0.Length);
            I2CLCD.Write(writebuf);
        }
        private void Initlcd()
        {
            Task.Delay(145);
            i2cwritecmd(0x38);
            Task.Delay(2);
            i2cwritecmd(0x39);
            Task.Delay(2);
            i2cwritecmd(0x10);
            Task.Delay(2);
            i2cwritecmd(0x78);
            Task.Delay(2);
            i2cwritecmd(0x55);
            Task.Delay(2);
            i2cwritecmd(0x6C);
            Task.Delay(300);
            i2cwritecmd(0x38);
            Task.Delay(2);
            i2cwritecmd(0x0C);
            Task.Delay(2);
            i2cwritecmd(0x01);
            Task.Delay(2);
        }
        private double get_temp()
        {
            byte[] writeBuf = new byte[] { 0x00 };
            byte[] readBuf = new byte[2];
            I2CTMP102.WriteRead(writeBuf, readBuf);
            int valh = ((int)readBuf[0]) << 4;
            int vall = ((int)readBuf[1] >> 4);
            int val = valh + vall;
            double reading = val * 0.0625;
            textBlock.Text = reading.ToString();
            return reading;
        }
        private void Timer_Tick(object sender, object e)
        {
            i2cwritedata(0x38);
            cnt = cnt + 1;
            textBlock.Text = cnt.ToString();
        }
    }
}


 テストでは”stra12345”が書き込めるか確認しました。テストの結果、次に示すように期待通りの表示が得られました。

 次回以降、I2Cバスのドライブ能力、バス・リピータ、ハーフ・ピッチのICのはんだ付けの方法、テスト・プログラムの説明を進めます。

(2016/10/20 V1.0)

<神崎康宏>

連載メニュー Raspberry PiにI2CインターフェースのLCDモジュールを接続する

(1) Raspberry Pi 3 model Bで新規のプロジェクトを作成しスタート画面を表示する

(2) モニタにメッセージを表示する

(3) モニタのデザインにタイマを追加

(4) I2cDeviceクラスと非同期処理

(5) I2cDeviceの作成

(6) バス・リピータを使用

(7) 温度の表示

(8) プログラムの配置

(9) バックグラウンド動作