SSブログ
English Version

I2C通信実験 照度センサー [PIC]

 結構前に amazon で購入した照度センサモジュール(GY-302)を I2C でPIC24FJに接続し動かしてみました。
 このモジュールは BH1750FVI を使用していて、データシートを見るとコマンド数も少なく簡単に動かせそうです。

 今回は ebay 価格702円の Logic Analyzer で I2C の通信をモニタしてみました。価格から推測するに saleae社製のものではなくパチモンなのでPC側のソフトは本家の Saleae Logic ではなく、pulseview を使ってみました。
 I2Cの表示に限って言えば pulseview は波形表示の下に I2C のコマンドやデータの値を表示できるので本家のソフトより見易い面もあります。(★2018/02/18 修正 本家ソフトも波形部にも通信内容を表示できます)
 でもセーブした設定状態をロードすると変になる等、不安定な部分があります。これに対して本家のソフトはこれでもかというくらい使い易さを追求し作り込まれたようなソフトに仕上がっています(すばらしい!)。

8chロジックアナライザ


 picle言語による I2C 接続は「I2C通信実験 3軸磁気センサー」で実験済みなのですんなり接続できました。
 3軸磁気センサーの実験の時は I2C のクロックとデータの波形を見て確認したりしていましたが、今回は数百円のロジックアナライザのおかげで確認が超ラクチンです^^

 接続試験のために作成した処理の概要は下記のとおりです。
  1. 1秒ウェイト後、Power On コマンド(0x01)と One Time H-Resolution Mode コマンド(0x20)を送信
  2. 計測時間(180ms)待ち
  3. 計測データを取り込み、値を表示
  4. Power Down コマンド(0x00)を送信し、I2Cのストップシーケンスを実行
  5. 上記1に戻る

 ロジックアナライザで確認した結果は次のようになります。I2Cのスタートシーケンスとストップシーケンスがともに「|」のような表示ですが、マウスカーソルをあてると状態が表示されどちらか判別できます(スタートとストップは違う記号の方が見易いのに)
★2017/02/25 追記
 I2C のスタートシーケンスとストップシーケンスが判別可能な記号で表示されるようになりましたので画像を差し替えました。いじっていると表示されたりされなかったりします・・^^;

上記1の波形


上記3の波形


上記4の波形


 実行結果のサンプルが下記です。データシートによると読込んだ値を 1.2 で割ったものが ルックス ということですが、今回は接続確認ということで読込んだ値の 1/12 の値を表示しています。途中で値が変化しているのはライトで照らしているからですw

実行結果
:run
      0 :     8 [x10 lx]      
      1 :     8 [x10 lx]
      2 :     8 [x10 lx]
      3 :     8 [x10 lx]
      4 :     8 [x10 lx]
      5 :   156 [x10 lx]
      6 :   890 [x10 lx]
      7 :   423 [x10 lx]
      8 :  1002 [x10 lx]
      9 :  1026 [x10 lx]
     10 :   222 [x10 lx]
     11 :    97 [x10 lx]
     12 :  2684 [x10 lx]
     13 :  2895 [x10 lx]
     14 :  4296 [x10 lx]
     15 :  4712 [x10 lx]
     16 :  4746 [x10 lx]
     17 :  4755 [x10 lx]
     18 :  4453 [x10 lx]
     19 :  3704 [x10 lx]
     20 :  2192 [x10 lx]
     21 :  1031 [x10 lx]
     22 :   794 [x10 lx]
     23 :   675 [x10 lx]
     24 :   614 [x10 lx]
     25 :   607 [x10 lx]
     26 :   581 [x10 lx]


 picle言語で記述したソースは次のとおりです。

I2C connect to Light Sensor(picle)
# I2C test Light Sensor(BH1750)
#  written with picle language by skyriver
#   2017/02/24 ver 0.01

var RegRcv,RegTrn,RegBrg;
var RegCon,RegStat;
var I2CRcv;

# send data to slave
#  data <- send data
#  return -> 0:no error
func I2CSnd( data ) {
    while ( RegCon[0] & $1f ) {}
    RegTrn[0] = data;
    while ( RegStat[0] & $4000 ) {}
    return = RegStat[0] & $8000;    # check nack
}

# receive data form slave
#  ack <- 0:nak, else:ack
#  I2CRcv -> receive data
#  return -> 0:no error
func I2CRcv( ack ) {
    while ( RegCon[0] & $1f ) {}
    RegCon[0] = RegCon[0] | $0008;  # enable receive
    while ( RegCon[0] & $0008 ) {}
    if ( ack ) {
        RegCon[0] = RegCon[0] & ~$0020; # set ack
    } else {
        RegCon[0] = RegCon[0] | $0020;  # set nack
    }
    RegCon[0] = RegCon[0] | $0010;  # send ack/nack
    while ( RegCon[0] & $0010 ) {}
    I2CRcv = RegRcv[0];
    return = RegStat[0] & $0040;    # check overflow
}

# start seqence and send salave adrs
#  adr_cmd <- slave_adrs << 1 | RD:1
#  return -> 0:no error
func I2CAdr( adr_cmd ) {
    RegCon[0] = RegCon[0] | 3;  # repeated start
    return = I2CSnd( adr_cmd );
}


# stop I2C sequence
proc I2CStop() {
    RegCon[0] = RegCon[0] | $0004;  # set PEN(stop)
    while ( RegCon[0] & $0004 ) {}
}


proc Init( base ) {
    var Ad1pcfg;
    Ad1pcfg = $032c;
    Ad1pcfg[0] = $ffff; # set digital mode
    RegRcv = base;
    RegTrn = base + 2;
    RegBrg = base + 4;
    RegCon = base + 6;
    RegStat = base + 8;
    RegBrg[0] = 39; # Fcy:4MHz -> I2C 100kHz
    RegCon[0] = $8000;  # enable I2C
}


proc main() {
    var CmdPowerdown, CmdPowerOn, CmdHiResoRead;
    var TimerSave;
    var adr, err, i, RdVal;

    Init( $0210 );  # I2C 2ch:$0210
    adr = $23 * 2;  # BH1750's address

    CmdPowerdown = 0;
    CmdPowerOn = 1;
    CmdHiResoRead = $20;

    I2CStop();
    err = I2CAdr( adr );
    err = err | I2CSnd( CmdPowerdown ); # set Power down
    if ( err ) {
        PrnStr_( "error !" );
        exit();
    }

    for ( i=0; i<600; i=i+1 ) {
        while ( Timer_ ) {}
        Timer_ = 100;   # set timer 1sec
        if ( I2CAdr( adr ) ) {
            PrnStr_( "adr err " );
        }
        else if ( I2CSnd( CmdPowerOn ) ) {   # Power on
            PrnStr_( "err " );
        } else {
            if ( I2CAdr( adr ) ) {
                PrnStr_( "read cmd err " );
            } else {
                err = I2CSnd( CmdHiResoRead );
                TimerSave = Timer_ - 18;
                while ( TimerSave <= Timer_) {} # wait 180ms until complete
                err = err | I2CAdr( adr | 1 );  # read command
                err = err | I2CRcv( 1 );        # read high byte
                RdVal = I2CRcv * 128;
                err = err | I2CRcv( 0 );        # read low byte
                PrnDecF_( i, 5 );
                PrnStr_( " : " );
                if ( err = 0 ) {
                    RdVal = RdVal + I2CRcv / 2;
                    RdVal = RdVal / 6;  # calc [10 lx]
                    PrnDecF_( RdVal, 5 );
                    PrnStr_( " [x10 lx]\n" );
                } else {
                    PrnStr_( "err\n" );
                }
            }
        }
        if ( I2CAdr( adr ) = 0 ) {
            err = I2CSnd( CmdPowerdown );
        }
        I2CStop();
    }
}


[ 前へ ] 連載記事 [ 次へ ]

nice!(1)  コメント(1)  トラックバック(3) 
共通テーマ:趣味・カルチャー

nice! 1

コメント 1

skyriver

 pulseview で I2C のスタートシーケンスとストップシーケンスが見た目区別つかない表示であることを書きましたが、pulseview をいじっていると判別可能な表示になることがあったので pulseview の画像を差し替えました。この辺りも不安定さがある印象です。
 拡大表示の画像はしばらくはキャッシュから取得するようで(Chromeの場合)、以前の画像が表示される場合があります(サーバ側は更新済みなんですけどね)
by skyriver (2017-02-25 18:23) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 3