この記事ではリモートセンサー用CPU ボードに I2C接続の温度センサー (TMP102)を接続する例を紹介します。
ここでは Digi International 製の X-CTU プログラムを使用して、XBee API フレーム中に CPU ボードを操作するためのコマンドを格納してリモートから I2C バスを操作します。X-CTU の起動から、CPU ボードに搭載している XBee-ZB(End Device またはRouter)をデバイス一覧に表示するまでの操作については、こちらの記事で詳しく紹介していますので合わせてご覧ください。CPU ボードについてはこちらのリンクから回路図や組み立て方を紹介しています。
リモートCPU ボードに I2C センサーを接続したときの様子です。
人感(IR)センサーやI2C-LCD モジュール、CDS なども接続されていて、これらも同様にリモートからデータ値の取得や操作が可能です。今回は TMP102 温度センサ(ブレッドボード中の赤い基板) のみを操作しています。配線部分を拡大した写真をご覧ください。
Coordinator が動作している PC で X-CTU プログラムを実行して、リモートCPU ボード上のXBee-ZB を表示した様子です。
Node1 が リモートCPU ボードに接続している XBee-ZB です。Node1 は ZigBee End device として動作しています。
ここで、Coordinator からリモートCPU ボードに対して I2C バスを操作するコマンドを送信します。コマンド文字列をRFデータに格納して、Node1に対して API Frame Type 0×10 を使用して送信します。
以下が、X-CTU プログラムの API frame generator で API Frame Type 0×10 のデータを作成している様子です。
64bit dest. address 部分に Node1 の 64bit アドレスを指定します。RF data 部分の ASCII タブの入力欄に記述している以下の文字列がリモートCPU で実行するコマンド(TDCPコマンド)になります。
“$$$123,i2c_write,48,00,2″
RF データの内容が、”$$$xxxxx” から始まる場合には(xxxxx は任意の5文字以内の英数字)、CPU ボードが “$$$xxxxx,” 以降の部分をコマンドとして実行します。ここで指定した i2c_write コマンドでは 0×48 のi2c slave デバイスに対して、最初に 0×00を書き込んだ後 repeated start read で2 バイトのデータを読み込みます。このコマンドではTMP102 の 内部レジスタアドレス(0×00) から2バイトの温度データを取得しています。
リモートCPUボードで実行するTDCPコマンドの詳細についてはこちらのマニュアルを参考にしてください。
実行結果は、リクエストコマンドの RF データを送信してきた XBee-ZB デバイスに対して、リモートCPU ボードに接続した XBee-ZB から送信されます。送信するときには、Coordinatorから送信した時と同様の 0×10 の API Frame type を使用しています。
リモートCPU ボードで実行したコマンドの結果を格納した RF データ中には、リクエストコマンドの先頭に付けられていたのと同じ $$$xxxxx 文字列を先頭に付けています。リモートコマンドのリクエスト側でこの文字列を利用すると、別のCPU ボードに対する複数のリモートコマンドを同時に処理できるようになります。
Coordinator で上記で作成した API Frame 0×10 を送信したときの様子は以下になります。
Frames log 欄に送受信の結果が表示されています。
“Transmit request” は、リモートCPU ボードに対するコマンドが格納された 0×10 Frame type の送信を行ったときのログです。ここでは送信に成功して、Coordinator XBee-ZB デバイスは続けて2つのフレームを受信しているのを確認できます。
最初の受信フレーム “Transmit status” はCPU ボードに接続した XBee-ZB(Node1)に対して RF データの送信が完了したことを知らせています。
つぎに受信したフレーム “Receive Packet” はリモートCPU ボードから送られてきたリモートコマンドの実行結果が格納された RF データになります。”Receive Packet”中の “received data” (RF データ)は以下のバイト列になっていることが判ります。
(データは全て16進数)
24 24 24 31 32 33 2C 31 2C 30 43 42 30
これを ASCII 文字列に直すと
$$$123,1,0CB0
になります。”$$$123″ がリクエスト時に指定した文字列と一致していますので、このフレームが i2c_write コマンドの実行結果が格納されているパケットであることがわかります。カンマで区切られた次の “1″ はCPU ボードで実行した i2c_write コマンドが成功したことを示します。”0″ の場合は実行時エラーが発生したことを示します。次の “0CB0″ は 0x0C, 0xB0の2バイトデータを示しています。これが i2c_write コマンドの実行結果になります。今回はこれが TMP102 から取得した温度データになります。
これを温度に換算してみます。0x0CB = 203 なので
203 * 0.0625 = 12.6(℃) になります。
通常はCoordinator からはプログラム経由で API フレームを作成しますが、今回はあえて手動で実行させてみました。DeviceServer を使用すると下記のように簡単に Web API経由でWeb ブラウザ中のJavaScript やクラウド環境、スマートフォンなどから簡単に温度を取得することができます。
Webブラウザから以下の様な URL を指定してアクセス(HTTP GET)します。
Web API で取得した JSON データ中の “temperature”:”13.38″ に温度データが格納されています。session パラメータにはDeviceServer に予め認証を省略するために作成したセッショントークンを指定しています。nameパラメータで指定している Lua スクリプト”ZB/DEVICE/TMP102_READ” の内容は下記になります。
file_id = "TMP102_READ" --[[ ******************************************************************* I2C に接続した 温度センサー(TMP102) の値を取得する リクエストパラメータ --------------------------------------------------------------------------------- キー値 値 値の例 --------------------------------------------------------------------------------- device XBee-ZB デバイス64ビットアドレスまたは NodeIdentifier "Node1" --------------------------------------------------------------------------------- リターンパラメータ --------------------------------------------------------------------------------- キー値 値 値の例 --------------------------------------------------------------------------------- "temperature" センサーから取得した摂氏温度 "12.50" "-25.00" --------------------------------------------------------------------------------- ******************************************************************* ]] local slave_addr = "48" ------------------------- -- パラメータチェック ------------------------- if not (g_params["device"]) then log_msg("parameter error",file_id) error() end ---------------------------------------- -- 12 bit 幅の2の補数を符号付整数に変換 ---------------------------------------- function calc_2comp(val) if(bit_and(val,0x800) ~= 0) then return -1 * (bit_and(bit_not(val),0xfff) + 1) else return val end end ----------------------------------------------------------------------- -- TMP102温度レジスタの値を取得する -- pointer register 0x00 をセットした後、2 バイトのレジスタ値を取得する ----------------------------------------------------------------------- stat,result = zb_tdcp_safe_retry(g_params["device"],"i2c_write," .. slave_addr .. ",00,2") if not stat then error() end --------------------------------------- -- 温度レジスタ値から摂氏温度を計算する --------------------------------------- local reg = {} reg = hex_to_tbl(result[3]) local temp_int = bit_lshift(reg[1],4) + bit_rshift(reg[2],4) local temperature = 0.0625 * calc_2comp(temp_int) script_result(g_taskid,"temperature",string.format("%4.2f",temperature))
I2C 操作で取得したデータから温度への変換等も、Lua スクリプト中でサーバー側で実行しています。