XBeeをAPIモードで使う
前回の続きとして、APIモードへの設定変更と、APIモードを使用したデバイス状態の読み取り・センサー出力(ADCポート)の読み取りを行います。マイコンにはmbedを使っています。
APIモードの種別
前回XBeeモジュールを透過モードに設定しているため、APIモードに設定変更を行います。APIモードには2つのバリエーションがあるため、先ずはこの点を説明します。APIモードのフレーム形式は以下となります(XBeeマニュアルの抜粋)
このままでは、フレームデーター中に0x7Eが出現するとフレームの先頭を誤認識してしまいます。そのため、フレームデーター中に0x7Eが出現した際に、0x7Eを「0x7Dと0x7E xor 0x20」の2バイトに置き換えるエスケープモードが存在します。0x7D(エスケープコード)自体がフレームデーターに出現した場合は、0x7Dと0x7D xor 0x20に置き換えます。
エスケープモードにはATコマンドATAP2を発行することで遷移します。そのため、エスケープモードは、AP=2 or ATAP=2と記載されることがあります。
APIモードへの設定変更
マイコンからAPIモードの制御を行う際、Arduino用ドライバ(xbee-arduinoプロジェクト)を使用しています。まあ当たり前ですが、xbee-arduinoではエスケープモード(AP=2)での使用が前提となっています。そのため、エスケープモードへの設定変更の手順を示します。以下は透過モードCoordinatorをAP2にする手順です。
①現状の設定情報を読み出します
②Function SetをAPIに変更し、Show Defaultsボタン→ Writeボタンを押す
③このフェーズでは書き込みが始まる前にエラーで停止することが多々ありますが、デバイスをリセットしたりしてしつこくリトライします。書き込みまで進んだ場合でも、自分の環境では必ず以下のエラーダイアログが出ます(サポート外のWindows 7だからなのかも)。
④OKボタンを押した後で下側のテキスト表示を見ると、パラメーター書き込みは成功しているような感じ
⑤Enable APIをチェックしてTest/Queryを行うと、APIモード対応ファームの2170で認識しています
⑥設定パラメーター(デフォルト値)の読み出しもできたのでAPIモードで立ち上がっています。エスケープモードにするために、APパラメーターに2を設定。DH/DLはデフォルトのブロードキャストのままにしておきます(マイコンから制御する際にユニキャストアドレスを指定するので、ここではブロードキャストでも問題なし)
⑦X-CTUのUse escape charactersをチェックし、X-CTU側もエスケープモード動作にします
End Device側も同様の手順で設定します。End DeviceのDH/DLもデフォルトのDH=0/DL=0(Coordinator宛てを意味する)のままとしておきます。End Deviceでは、サンプルプログラムで使うADC3を有効にしておきます。
APIモードを使ったサンプルプログラム
サンプルプログラムを動かすマイコンとしてmbedを使いました。APIモードを動かすためのドライバですが、h.sugaさんがxbee-arduinoプロジェクトをmbedに移植して下さっているので、ありがたく利用させていただきました。
サンプルプルグラムは、mbedが繋がったXBeeにATDBコマンドを投げて電波強度(RSSI)の取得と、リモート側のXBeeにATISコマンドを投げてADCポートのサンプルデーターを取得しています。ADCの分解能は10bitで、温度センサーをつないだポートの生データーを表示しています。
何はともあれ、コードを以下に示します。全体は、mbed.orgにパブリッシュしました。xbee-arduinoはオブジェクト構造が結構複雑ですが、Arduino用のライブラリ添付のサンプルコードを見ながら使い方を覚えるのが手っ取り早そうです。
#include "mbed.h" #include "XBee.h" #include "TextLCD.h" TextLCD lcd(p25, p26, p24, p23, p22, p21); // RS, E, DB4, DB5, DB6, DB7 /*-- AT command and parameters --*/ uint8_t atISCmd[] = {'I', 'S'}; // Forces a read of all enabled digital and analog input lines uint8_t atDBCmd[] = {'D', 'B'}; // Received Signal Strength uint8_t cmdVal0[] = {0}; // Clear RSSI regisger /*-- Create instanse of Xbee object --*/ XBee xbee(p13, p14); XBeeAddress64 remoteAddress(0x0013A200, 0x406B7111); // Specify your XBee address /*-- Create instanse of Command and Response object --*/ // Remot ATIS command to read ADC value (ADC3 is enabled by X-CTU tool) RemoteAtCommandRequest remoteSampleRequest(remoteAddress, atISCmd); // Local ATDB command to read signal strength (RSSI) AtCommandRequest atDB(atDBCmd); // Local ATDB0 command to clear RSSI AtCommandRequest atDB0(atDBCmd, cmdVal0, sizeof(cmdVal0)); // Create instanse to handle command response AtCommandResponse response = AtCommandResponse(); RemoteAtCommandResponse remoteResp = RemoteAtCommandResponse(); /* Receive command response packet * If OK response recieved, return pointer to the Response Data Frame */ uint8_t* GetResponse() { // Read response if (xbee.readPacket(5000)) { // Got a response! Check if response is AT command respose if (xbee.getResponse().getApiId() == AT_COMMAND_RESPONSE) { xbee.getResponse().getAtCommandResponse(response); if ( response.getStatus() == AT_OK ) return response.getValue(); } else if (xbee.getResponse().getApiId() == REMOTE_AT_COMMAND_RESPONSE) { xbee.getResponse().getRemoteAtCommandResponse(remoteResp); if ( remoteResp.getStatus() == AT_OK ) { // Debug print printf("Response Data:"); for (int i = 0; i < remoteResp.getValueLength(); i++) printf("%02X ", remoteResp.getValue()[i]); printf("\n"); return remoteResp.getValue(); } else { printf("Remote Command Error:0x%X\n", response.getStatus()); } } } return 0; } /* Get ADC data * Data frame structure of ATIS * Offset * 0 : Number of Samples (Always 1) * 1-2 : Digital Channel Mask * 3 : Analog Channel Mask * 4-5 : Digital Samples (Omit if no DIO enabled) * 6-7 : First ADC Data */ uint16_t getAnalog(uint8_t *FrameData, int ADC) { // ADC data feild starts 4 bytes offest, if no DIO enabled uint8_t start = 4; // Contains Digital channel? if (FrameData[1] > 0 || FrameData[2] > 0) { // make room for digital i/o start+=2; } // start depends on how many ADCs before this ADC are enabled for (int i = 0; i < ADC; i++) { // Is Analog channel Enabled ? if ( (FrameData[3] >> i) & 1 ) { start+=2; } } return (uint16_t)((FrameData[start] << 8) + FrameData[start + 1]); } int main() { unsigned int loop = 0; xbee.begin(9600); lcd.printf("RSSI:"); lcd.locate(0, 1); lcd.printf("ADC :"); printf("\nStart.\n"); while (true) { uint8_t *responseVal; uint8_t rssiVal = 0; uint16_t adcVal = 0; // Send ATDB command (Read RSSI register from local Xbee) xbee.send(atDB); responseVal = GetResponse(); if ( responseVal != 0 ) rssiVal = responseVal[0]; lcd.locate(5, 0); if (rssiVal == 0) lcd.printf("No Signal"); else lcd.printf("-%ddBm ", rssiVal); // Clear RSSI register, because Xbee hold RSSI value of last received packet even after radio disconneded xbee.send(atDB0); GetResponse(); // Read ADC3 value by sending ATIS command xbee.send(remoteSampleRequest); responseVal = GetResponse(); if ( responseVal != 0 ) { adcVal = getAnalog(responseVal, 3); // Assume ADC3 is enabled } lcd.locate(5, 1); if (adcVal == 0) lcd.printf("- "); else lcd.printf("%d", adcVal); printf("Loop:%d\n", loop++); wait(1.0); } }
コードの概要は以下です:
- xbeeオブジェクトを起こす(13行目)
- xbeeに投げるコマンドやレスポンスのオブジェクトを起こす(16行目から)
- xbee.send(コマンドオブジェクト)でコマンドを送信
- xbee.readPacket()でレスポンスを受信(31行目~)
- xbee.getResponse()でレスポンスデーターを取得、AtCommandResponseオブジェクトに渡してレスポンス情報を取得する、などなど
サンプルプログラムの動作構成ですが、以下のように、XBee 3個構成で行いました。(実験中に壊したXBeeの代替とあわせて追加1個を昨日秋月さんで調達したのです)
真ん中のXBeeがCoordinator(兼Router)で、左右はEnd Deviceです。
mbedがRemoteAtCommandRequestを投げると、真ん中のRouterで左側に中継され、ADCの読み取り値がRouterノード経由で戻ってきます。
End Device間も電波が届く範囲にありますが、直接通信はしてない筈です。ZigBee規格ではEnd Deviceは必ず上位のRouter経由で通信するため、真ん中のrouterをバイパスして左右のEnd Device間が直接通信するパスはないと思っています。このあたりのルート選択の概念やAODV (Ad-hoc On-demand Distance Vector) Routingについては別途お勉強して実験してみたいと思います。リンクコスト(品質)に基づくDistance Vector型の最適ルート選択とか、IPのルーティングと通じるところがあり、通信屋の自分には面白いエリアです。
参考情報
« XBeeを使ってみる | トップページ | LPCXpresso LPC1769の120MHzクロック設定 »
「mbed」カテゴリの記事
- mbed TY51822r3でmbed OSを使う(2016.04.16)
- mbed OSでLチカ(2015.11.22)
- 各種mbedのベンチマークテスト(2014.08.31)
- iPhoneからmbedをBluetooth LE (BTLE)で制御する(2013.02.11)
- Debug printf用の可変長引数マクロ(2011.04.29)
「XBee」カテゴリの記事
- XBee APIモードライブラリのLPCXpressoへの移植(2011.10.09)
- XBeeをAPIモードで使う(2010.12.12)
- XBeeを使ってみる(2010.12.11)
コメント
この記事へのコメントは終了しました。
この記事を見て、大変感銘を受け、失礼とは思いましたが、再現テストをさせて頂きました。 その際、このurlを使わせて頂きましたが、もし御気にめされない場合、そのようにご連絡をお願い致します。記事は削除いたします。
宜しくお願い致します。
投稿: 赤須 | 2014年8月21日 (木) 15時32分
赤須さん;
古い記事の追加検証ありがとうございました。
転記は問題ございません。
投稿: Todotani | 2014年8月21日 (木) 20時03分
はじめまして。当方、大学の卒業論文で車間通信を研究しています。車間通信の一つの方法としてZigBeeを検討し、この記事を参考にさせていただきました。この場をお借りして感謝申し上げます。
投稿: mikio | 2015年2月 1日 (日) 14時03分