#!/usr/bin/env python # coding: utf-8 # オリジナルの作成:2014/11/16 # # 0D-LPC810でI2Cデバイスの値を取得する # 勉強会の参加者で、I2Cのデバイスを使ってパソコンにデータを送る小さなアダプターあると便利という ご意見があり、LPC810を使って試してみようと思います。 # # ここで、紹介しているプログラムは、Githubにlbed/LBED_LPC810から取得できます。 # # - https://github.com/take-pwave/lbed # ## LPC810を使ったI2Cデバイスのシリアル読み込みプログラム # サンプリングレートが1秒間に1回程度なので、パソコンへはGPIOを使ったソフトシリアルで通信します。 # # LPC810の5番ピンをソフトシリアルの送信用に使用します。 LM73を使って温度センサーの値をシリアルに送信ガジェットをブレッドボードに組みました。 # # # ## 変なエラー # どうもI2Cデバイスからの応答が2回目以降表示されない、奇妙なバグが発生しました。 # # こんな時には、プロトコルアナライザとして購入しておいたLabToolの出番です。 # # ### LabToolでデバッグ # ターゲットデバイスとLabToolの結線を以下に示します。 # # ここでは、D1, D2にSDA, SCLを接続しました。 # # | LabTool | LPC810 | # |---|---| # | D1: 茶 | 8: SDA | # | D2: 赤 | 2: SCL | # # LabToolを起動し、Newを選択する。 # Add Signalをクリックし、D1, D2をチェックし、Analyzers:でI2C Analyzerを選択する。 # # # # I2C AnalyzerでSDAにD1, SCLにD2を選択し、Synchronize: Triggerを選択する # # # ### Analyzerの結果 # デバッガでI2C関連の関数でブレークポイントをセットし、 # # - 初期化 # - 1回目の読み込み # - 2回目の読み込み # # をアナライザーに掛けてみると以下のようになりました。 # # 初期化は、プログラム通りの動きを確認 # # - 0x4CのアドレスにData 0x04, 0x60を書き込み # - 0x4CのアドレスにData 0x00を書き込む # # # # 1回目の読み込みでは、 # # - 0x4Cのアドレスに0x00を送ると # - 0x4Cのアドレスから0x0b, 0x64が返される # # # # 一方2回目の読み込みでは、 # # 0x4Cのアドレスに0x10を送って、ここで止まっている。 # # # ### 障害の原因 # これまで何回も使っていたLM73::readメソッドにバグがあることが判明しました。 送信用のコマンド0x00をセットするのを忘れていた。 # # ```C++ # int LM73::read() # { # char cmd[2]; # // cmdの1バイト目を0をセットし忘れている。2014/11/16発見 # cmd[0] = 0; # i2c.read( LM73_ADDR, cmd, 2); // Send command string # int int_val = cmd[0] <<1 | cmd[1]>>7; # int ceil_val = ((cmd[1] & 0x7f)*200) >>8; # return (int_val*10 + ceil_val/10); # } # ``` # # ### 完成したI2Cからシリアルへの送信プログラム # LPC810では、float型を使用すると急にプログラムサイズが大きくなるため、 温度センサーLM73の戻り値を小数点1桁までの温度を整数とする値に変更しました。 # # 以下にI2Cから読み込んだ値をシリアルに送信するプログラムを示します。 このプログラムは、I2CデバイスLM73から値を読み取り、シリアルに4800ボーで送信する 簡単なものです。 # # ```C++ # #include "lbed.h" # #include "SoftSerialTxOnly.h" # #include "LPC8xx.h" # # // 4800bps # #define SERIAL_TIME_PER_BIT1 105 # #define SERIAL_TIME_PER_BIT2 104 # # SoftSerialTxOnly::SoftSerialTxOnly(PinName pin) : _out(pin) { # # } # # int SoftSerialTxOnly::_putc(int value) { # uint8_t data = value; # _out = 0; # wait_us(SERIAL_TIME_PER_BIT1); # # uint8_t i; # for (int cnt = 0, i=0x01; cnt < 8; i<<=1, cnt++) { # if (data & i) # _out = 1; # else # _out = 0; # wait_us(SERIAL_TIME_PER_BIT2); # } # _out = 1; # wait_us(SERIAL_TIME_PER_BIT1); # # return value; # } # メインのプログラムは、以下の通りです。 # # /* # SoftSerialTxOnly # I2CデバイスLM73から値を読み取り、シリアルに4800ボーで送信する # */ # # #ifdef __USE_CMSIS # #include "LPC8xx.h" # #endif # # #include # # #include "lbed.h" # #include "SoftSerialTxOnly.h" # #include "LM73.h" # # int main(void) { # // lbedライブラリの初期化 # lbed_setup(); # /* I2C用スイッチマトリックスの設定 */ # I2C_SwitchMatrix_Init(); # # // 8番ピンSDA, 2番ピンSCL # LM73lm73(P8, P2); # // 5番ピンをURARTのRxに接続 # SoftSerialTxOnly pc(P5); # pc.println("Hello World\n"); # while(1) { # pc.print("temp="); # //pc.print(lm73.read(), 2); # // floatを使うとサイズオーバーになるので、0.1度までを整数で出力 # int v = lm73.read(); # pc.print(v, DEC); # pc.println(); # wait_ms(1000);// 1秒待つ # } # return 0 ; # } # ``` # In[ ]: