カテゴリー「XBee」の記事

XBee APIモードライブラリのLPCXpressoへの移植

XBeeをAPIモードで使うで紹介したmbed用ライブラリ(オリジナルはArduino用で、Suga koubouさんがmbed用に移植)をLPCXpressoに載せてみました。

オリジナルコードはC++ですが、LPCXpresso IDEでC++のプロジェクトを作成してビルドすることができました。表示部分はMARY OLED基板を使っています。5月にポストした「LPCXpresso LPC1769にMARY拡張基板を乗せる」では、XBeeを載せただけのハリボテ写真を掲載していたのですが、やっと動かすことができました。 

   
LPCXpressoでのC++プロジェクトのビルド

LPCXpresso IDEの新規プロジェクト作成ウイザード(New Project)ではC++プロジェクトが作成できませんが、以下のブログを参考にして、ファイルのコピーやプロジェクトプロパティの設定を行うことによってC++コードのビルドができました。 

マイコン風雲録:LPCXpressoで「C++プロジェクト」を作る方法

私のビルド環境では、LPCXpresso v4.1.0のデフォルトに従って、CMSIS v2をライブラリプロジェクトとして参照していますが、CMSISプロジェクトの設定はREDLIBのままで問題ありませんでした(C++プロジェクト側だけをNEWLIBに変える)。  

   

XBee APIモードライブラリの移植 

主要な変更点は、以下の2つです:  

  • mbed版では、SerialクラスとTimerクラスを使っているため、この部分を自作のクラス(実装は最低限の手抜き)で置き換えています。mbed版はXbeeクラスのコンストラクターにシリアルポートのピン番号を指定しますが、今回の実装はUARTの番号(0~2)を指定します。      
  • オリジナルは、XBee.hで送信ステータスとして”SUCCESS”を#define定義しているのですが、CMSISのlpc_types.hに同じ名前のenum定義があるせいか、lpc_types.hでコンパイルエラーが発生してどうしても解決できなかったため、XBee.h側を”OK”に変更しています。   
ソースコードは以下です(スタートアップコード、や表示用に使ったMARYのコードは再配布が微妙なので含みません)。 

XBee_LPCxpresso.zip

       
サンプルコード 

リモート側(End Device)のXBeeにコマンドを送って、ADC3の読み取りと、DIO1(Digital Outに設定)のトグルによるLチカを行うコードを作ってみました。

LPCXpresso-_XBee

   
#include "XBee.h"
extern "C" {
	#include "oled.h"
	#include "systick.h"
}

/*-- AT command and parameters --*/
uint8_t atISCmd[] = {'I', 'S'};      // Forces a read of all enabled digital and analog input lines
uint8_t atD1Cmd[] = {'D', '1'};		 // DIO1 control
uint8_t atDBCmd[] = {'D', 'B'};      // Received Signal Strength
uint8_t cmdVal0[] = {0};             // Clear RSSI register
uint8_t cmdVal4[] = {4};			 // Digital output, low
uint8_t cmdVal5[] = {5};			 // Digital output, High

/*-- Create instance of Xbee object --*/
XBee xbee(2);
XBeeAddress64 remoteAddress(0x0013A200, 0x406B7111);    // Specify your XBee address

/*-- Create instance of Command and Response object --*/
// Remote ATIS command to read ADC value (ADC3 is enabled by X-CTU tool)
RemoteAtCommandRequest remoteSampleRequest(remoteAddress, atISCmd);
// Remote ATD1 command to turn DIO1 low/high
RemoteAtCommandRequest remoteDIO1_Low(remoteAddress, atD1Cmd, cmdVal4, sizeof(cmdVal4));
RemoteAtCommandRequest remoteDIO1_High(remoteAddress, atD1Cmd, cmdVal5, sizeof(cmdVal5));

// 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(1000)) {
        // 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 ) {
                return remoteResp.getValue();
            }
        }
    }

    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;
    Timer t;

    xbee.begin(9600);

    Init_SysTick(10);   // Set systick interval to 10ms
    Init_OLED();

    OLED_printf_Font(OLED_FONT_SMALL);
    OLED_Clear_Screen(OLED_BLK);

    OLED_printf_Position(0, 0);
    OLED_printf_Color(OLED_GRN, OLED_BLK);
    OLED_printf("RSSI:");
    OLED_printf_Position(0, 1);
    OLED_printf_Color(OLED_WHT, OLED_BLK);
    OLED_printf("ADC :");

    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];
        OLED_printf_Position(5, 0);
        OLED_printf_Color(OLED_GRN, OLED_BLK);
        if (rssiVal == 0)
            OLED_printf("No Signal");
        else
            OLED_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
        }
        OLED_printf_Position(5, 1);
        OLED_printf_Color(OLED_WHT, OLED_BLK);
        if (adcVal == 0)
            OLED_printf("-     ");
        else
            OLED_printf("%x   ", adcVal);

       // Turn DIO1 high/low
       if (loop % 2 == 0) {
    	   xbee.send(remoteDIO1_Low);
       } else {
    	   xbee.send(remoteDIO1_High);
       }
       GetResponse();

       t.start();
       while (t.read_ms() < 1000);
       t.stop();

       loop++;
    }
}

MARY基板用OLEDモジュール(MARY-OB)のライブラリのヘッダファイルを3~4行目でインクルードしていますが、MARY-OBのライブラリはCのコードであるため、extern “C”宣言でくくってやる必要があります。

extern “C”って、意味がよく分かっていなかったのですが、C++のコードからCの関数を呼び出すために、以下の関数はCのだよとC++コンパイラに教えてあげるための記述なんですね。extern “C”なしでは、リンクでundefined referenceエラーが出て、その対処を調べる過程で始めて意味が分かりました。ヤッパリ習うより実践かな。

 

追記

10月8日(土)に@shintamainjpさん主催の「LPCXpresso横浜お楽しみ部会」に参加しました。ネタ切れのおり、MARY拡張基盤を持ち込んでXBeeライブラリの動作を目指したのですが、時間内では動作せず。問題は移植コードでなくXBeeの設定誤りというトホホな内容・・ファームを更新した際に設定内容が初期化されてScan Channelの設定が両端でずれていたことあたりが原因みたいです。とは言え、プロフェッショナルな皆さんとお話ができ、終了後の飲み会も含めて楽く有意義なひと時が過ごせました。

XBeeをAPIモードで使う

前回の続きとして、APIモードへの設定変更と、APIモードを使用したデバイス状態の読み取り・センサー出力(ADCポート)の読み取りを行います。マイコンにはmbedを使っています。


APIモードの種別

前回XBeeモジュールを透過モードに設定しているため、APIモードに設定変更を行います。APIモードには2つのバリエーションがあるため、先ずはこの点を説明します。APIモードのフレーム形式は以下となります(XBeeマニュアルの抜粋)

ApiFrame

このままでは、フレームデーター中に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にする手順です。

①現状の設定情報を読み出します

01_CurrentConfig

 

②Function SetをAPIに変更し、Show Defaultsボタン→ Writeボタンを押す

02_WriteAPImodeDefault

 

③このフェーズでは書き込みが始まる前にエラーで停止することが多々ありますが、デバイスをリセットしたりしてしつこくリトライします。書き込みまで進んだ場合でも、自分の環境では必ず以下のエラーダイアログが出ます(サポート外のWindows 7だからなのかも)。

03_ErrorIndication

 

④OKボタンを押した後で下側のテキスト表示を見ると、パラメーター書き込みは成功しているような感じ

04_ErrorButFwWiteComplete

 

⑤Enable APIをチェックしてTest/Queryを行うと、APIモード対応ファームの2170で認識しています

05_ApiModeEnabled

 

⑥設定パラメーター(デフォルト値)の読み出しもできたのでAPIモードで立ち上がっています。エスケープモードにするために、APパラメーターに2を設定。DH/DLはデフォルトのブロードキャストのままにしておきます(マイコンから制御する際にユニキャストアドレスを指定するので、ここではブロードキャストでも問題なし)

06_SetAPI2

 

⑦X-CTUのUse escape charactersをチェックし、X-CTU側もエスケープモード動作にします

07_X-CTU_AP2mode


End Device側も同様の手順で設定します。End DeviceのDH/DLもデフォルトのDH=0/DL=0(Coordinator宛てを意味する)のままとしておきます。End Deviceでは、サンプルプログラムで使うADC3を有効にしておきます。

08_Adc3Cofnig

 

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個を昨日秋月さんで調達したのです)

SampleProgramRun

真ん中の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を使ってみる

MTM06でスイッチサイエンスさんからXBeeを購入しました。前から使ってみたいと思っていたのですが、面白い応用例が思いつかず(電力モニターとか先例があるし)先送りになっていました。「とにかく使ってみるぜ」といじり始めると、すごく機能があり奥が深いです。そのため、設定面では結構ハマってノウハウもたまりました。

XBeeの基本設定については多くの方がブログで解説していますが、最新のZB型(ZigBee対応)でAPIモードを使った設定例はあまりなかったので、この点について記載します。今回は、XBeeモジュールの種別・基本動作の解説とループバックテストを行うまでの基本設定について記載します。


XBeeモジュールの種別

2010年12月時点でスイッチサイエンスさんから購入できるXBeeモジュールには大きく分けて以下の4種類があります。

モジュール名 特徴
XBee ZB (XB24-Z7) ZigBee規格準拠の短距離版(低出力型)
Point-to-Point, Point-to-Multipoint、Mesh通信が可能
XBee-Pro ZB (XBP24-Z7) ZigBee規格準拠の長距離版(高出力型)
XBee (XB24-A) XBee独自規格の短距離版
ZigBeeと共通の無線規格(IEEE802.15.4)上に独自の上位ネットワークプロトコルを載せている。Point-to-Point, Point-to-Multipoint通信が可能
XBee-Pro (XBP24-A) XBee独自規格の長距離版

上記の各バリエーションに対して、アンテナの種別として、1)チップアンテナ、2)ワイヤーアンテナ、3)U.FLコネクタ(外付けアンテナ)の3種があり、合計4 x 3 = 12種類があります。

XBee ZB(ZigBee対応) or XBeeの選択は悩むところですが、Mesh通信(Routerノードを介したマルチホップ中継や、Routerノード故障時に通信経路の再構築=迂回が可能)を試してみたく、ZBモジュールを購入しました。現状はモジュールが2個しかないため、Point-to-Point(1対1)通信になってしまい、Meshネットワークは作れないのですが・・

私が買ったのは、ZBモジュールのチップアンテナ版(XB24-Z7CIT-004)とワイヤーアンテナ版(XB24-Z7WIT-004)です。


シリアルインターフェースの種別

XBee ZBはシリアルインタフェースを使用してホストMCUと通信を行いますが、以下に示す2つのインターフェースに対応しています。

インターフェース種別 概要
透過モード (Transparent Operation) ホストからのデーターを無線リンクに透過するモデムとして動作。
XBeeモジュールの設定はATコマンドで行う。無線リンクを挟んだリモート(遠方)側のXBeeモジュールは操作できない
APIモード (API Operation) ホスト-XBee間でデーターおよびコマンドをAPIフレームでやりとりする。フレームの組み立て・解析処理が必要となるが、リモート側モジュールへのコマンド送信や送達確認などの高度な使い方が可能

透過モード・APIモードをシーケンス図的に描くと以下のようになります。

XBeeOperationMode

■透過モードはいわゆるATモデム(懐かしい!)と同様の動作になります

■APIモードの動作は以下となります

  • 送信データは、APIフレーム形式ででXBeeモジュールに渡します。リモート側で受信したデータもAPIフレーム形式でシリアル回線に出てきます
  • デバイス設定はATコマンドをAPIフレームに入れてXBeeモジュールに送ります。APIフレームには任意の宛先アドレスを設定できるため、リモート側(遠方)のXBeeモジュールを操作することも可能。この機能を使って、リモートモジュールのGPIOをたたいたり、ADCに接続したセンサーの出力を読み取ることができます
  • リモート側モジュールのADCデーターを周期的に送信するように設定した場合、サンプルデータをAPIフレーム形式で送信

先ずは、ループバック試験による動作確認を行うために、透過モードの設定を行います。その後に、APIモードに設定を変更し、リモート側モジュールのGPIOを使ったLチカ(リモートLチカ)やADCポートに接続したセンサーデーターの読み取り(リモートセンシング)を行うことにします。

デバイス種別

XBee ZBモジュールが準拠するZigBee規格では、以下に示す3つのデバイス種別が存在します。

デバイス種別 概要
Coordinator ネットワークID(PAN ID)の広報や無線CHの選択を行うノードで、ZigBeeネットワーク内に必ず1つ必要。ネットワークの立ち上げ後はRouter動作を行う。常時オンでスリープしない。
Router Device間のデーター中継を行う。End Deviceとしての動作も可能。
End Deviceがスリープ中の場合、一時的に受信データーをバッファリングする。常時オンでスリープしない
End Device 末端の端末。中継機能を持たない代わりに、送受信データーが一定時間ない場合はスリープ状態になり消費電力を節減する。そのため、電池で長時間の動作が可能

XBeeの実験を行うためには、最低2個のモジュールが必要ですが、上記の要件から、1個はCoordinatorに設定する必要があります。もう一つは、RouterもしくはEnd Deviceに設定する必要がありますが、今回はEnd Deviceにしています。ZigBeeならではスリープ状態の実験もしたいためですが、設定開始時にデバイスがスリープしているとエラーになる場合があるため注意が必要です(その場合は再度やり直し)。Routerにしておけば常時オンのため、このような問題に遭遇することはなくなります。


設定の準備

XBee ZBの設定には、販売元のDigiが提供するX-CTUと呼ばれる設定ツールを使用します。X-CTUはWindows XP用で、Windows Vista/7はサポートリストにはないのですが、Windows 7でも動いています。ただ、動作モードの変更を行う際にX-CTUが固まることがあるのですが、Windows 7だと強制終了ができず、ログオフが必要になる場合がありました。

X-CTUを使って設定を行うためには、XBee ZBモジュールとPCをシリアル接続する必要があります。PCとの接続には、XBeeのソケットとUSB・シリアル変換チップを乗っけたXBeeエクスプローラUSB(写真左)あたりを使うのがお手軽です。X-CTUで設定中にリセットを要求されることが度々あるため、リセットボタンを追加してあります。

もしくは、スイッチサイエンスさんの2.5mmピッチへの変換基板(写真右)と秋月さんのFT232RLをブレッドボード上で配線する方法もあります。両方を試してみたのですが、XBeeエクスプローラーを使った方が若干動作が安定するように思います。そのため、設定はXBeeエクスプローラーで行うことを前提にします。

XBeeExplorer

変換基板+FT232RLで設定を行う場合は、FT232RLのジャンパー2をオープンにしてXBeeモジュールとFT232RLの電源を共通にする必要があります。当初は、FT232RLの電源はPCのUSB側から取っていたのですが、この場合電源が分かれてしまい、XBeeの電源が落ちているがFT232RLの電源が入っておりシリアル回線にHighが出力される可能性があります。XBeeにしてみると電源電圧(電源切っているので0V)より高い電圧がI/Oに加わるので、最悪ラッチアップを起こしかねない使い方だと思い修正しました。原因は分からないのですが、XBeeモジュールを1個壊してこの点に気がついた次第。これも授業料かな・・


透過モードの基本設定

X-CTUをインストールして起動します。初回起動時は最新ファームウェアをダウンロードするかと聞かれるのでダウンロードしておきます。 PC Settingsのタブにて、Test/Queryボタンを押すと、modem typeの確認ができます。modem typeがXB24-Bと表示されますがこれはX-CTUのバグのようで、XB24-ZBが正解です。

ModemQueryOk

Test/Queryを行う際には、XBee ZBモジュールの設定(透過 or APIモードのどちらか)とX-CTUの設定が一致している必要があります。上の画面では、X-CTUは透過モードです(Enable APIのチェックが外れた状態)。正しくmodem typeが読み取れているということは、XBee ZBモジュールも透過モードで動いているということになります(出荷時は透過モード)。もし、以下のようにmodem typeが正しく読み取れなかった場合は、X-CTUとXBeeモジュールの動作モードが合ってないことが考えられます。

ModemQueryNG

上記の表示となった場合、先ずは何回かリトライします(リセット+リトライも実施)。それでもダメな場合は、Enable APIをチェックして再度Test/Queryを行います。正しい表示が得られた場合はXBee ZBモジュールがAPIモードで動いていることになります。

Modem Configurationタブに移動して、以下の設定を行います:

  • Modem XBEE: XB24-ZB
  • Function Set: ZIGBEE CORDINATOR AT(透過モード)
  • Version(最新:執筆時点は2070)
  • Show Defaultsボタンを押して、デフォルトパラメーターを表示
  • Always update firmwareをチェック

Writeボタンを押して、Coordinator対応ファームウェアの書き込みを行います。以下のダイアログボックスが出現したら、リセットボタンを押してモジュールをリセットします。

RestRequest

続いて、ネットワーク関係の情報を設定します。

  • PAN ID: 0以外の適当な値を設定(0はCoordinatorが空きIDをスキャンして自動設定。0以外の値を設定した場合は手動設定となります。手動設定の場合は、ネットワーク内のデバイス全てに同一のPAN IDを設定します)
  • DH/DL: End Deviceのアドレス(裏面のシリアル番号)を設定。DH=0, DL=FFFFはブロードキャストアドレスですが、ZBモジュールでブロードキャストを行うと、使用に耐えない程遅いです。そのため、ここではループバックテスト用に、End Deviceのアドレスを設定します。次のステップでAPIモードを設定すると通信毎にホストMCUから宛先アドレスを指定できるため、複数デバイスをポーリングするような処理も問題なく行えます
  • SH/SL: 自身のアドレス(=シリアル番号)が表示されています(この値は変更できません)

Writeボタンを押してパラメーターを書き込み。書き込みに成功したら、Readボタンを押して設定を確認します。

End Deviceについても、同様にZIGBEE END DEVICE ATのファームを書き込んで設定を行います。PAN IDについてはCoordinatorと同じ値。DH/DLはCoordinatorのSH/SL(シリアル番号)を設定します。


ループバックテスト

ループバックテストを行うためにはリモート側のXBeeも動作できるようにする必要があります。そこで、スイッチサイエンスさんのピッチ変換基板を使ってブレッドボードに搭載できるようにしました。

この基板は、On/AssociateピンとLED間の配線パターンが引いてあり、抵抗とLEDを追加することによってモジュールの状態をLED表示することが可能です。抵抗は、スルーホールが1/6W抵抗サイズのところに手持ちの1/4W抵抗を押し込んだので部品がはみ出していますがその点はご愛嬌。また、抵抗は消費電流を抑えるために1KΩを使用しています。緑のLEDはデータシートを見るとVf = 3.3Vなので、3.3V電源のXBeeでは本来使えないのですが、ちゃんと光ってます・・このあたりは手持ち部品を使っているので・・

XbeeRemote2

XBee ZBモジュールの結線は以下の通りです。

ピン番号(名称) 接続先
1(Vcc) 3.3V電源
2(Dout) 3(Din) - Loop back
3(Din) 2(Dout)
5(Reset) SWを介してGNDに接続(写真は未実装)
6(RSSI) LEDを接続すると無線リンクが繋がった際にLEDが点灯します。
10(GND) GND

やっとループバックテストに到達です。PCとXBeeエクスプローラーを接続し、X-CTUのRange Testタブを開きStartボタンを押すとテストパターンが送信されループバックが始まります。ループバックを開始した直後は無線リンクがUPしていないためBadのカウントが上がる場合がありますが、RSSI LEDが点灯したあたりからデーターが流れ始めます。

LoopBackTest


おわりに

XBee ZBは設定が難関かもしれません。デバイス種別や動作モードの変更を行うとかなりの確率でX-CTUがエラーを吐きます。自分の環境で発生したエラーと回避方法を書きましたが、使用環境によってエラーの出方が異なるかもしれません。その場合は、X-CTUとXBee本体の動作モードを合わせる、たまにXBeeをリセットし活入れしながらリトライする点を意識して、色んな組み合わせを試してみるしかないかと思います。Point-to-Pointでの使用であれば、XBeeモジュールの方が設定が簡単で使いやすいかも(使っていないのでなんとも言えませんが)。

次回は、設定をAPIモードに変えてホストMCUからの制御方法について記載します。


参考資料

2023年6月
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30  
無料ブログはココログ