マイコン向け XBee APIコマンドモード通信プログラムの開発

About XBee API Transceiver Application Program for Microcomputer

森下功啓製作所 ONLINE

[編集方針]
このページでは、基本的に今まで有線通信を行って来たマイコンの通信路を無線に置き換えるためのHOW TOを書いていきたいと思います。 特に、通信距離の長くて便利なZigBeeの一種であるXBeeの制御方法について解説を行います。 私の手持ちがシリーズ1ですので、DigiMeshに関する記述が中心になります。 ご了承ください。
また、このページに誤りを見つけられましたらぜひご連絡下さい。 宜しくお願い致します。
[2013/5/4 更新]新しいライブラリを公開しました。


1. ここで公開するプログラムの開発目的について

ここで公開するプログラムは、「バイナリで大量に通信したい」とか「メッシュネットワークで通信したい」という目的を満たすために開発しています。 従って、バイナリでも"+++"に該当するバイナリは存在しない(ATコマンドモードだと、"+++"で設定モードに入る)とか、1対1でしか通信しないという場合には、役に立たないプログラムです。 このプログラムが力を発揮するのは、送信先が複数ある場合や素早く送信元へ返信する場合や大量の予測不可能なバイナリデータを送信する場合に限られます。 別ページで公開しているGPS受信機の受信データ解析プログラム同様、「インクルードしたらすぐに使える」を目標に開発しています。

海外で公開されているプログラムは専用関数に置換する必要があったり重かったりして気に入りませんでした。 ならば自分で作ってしまえという訳です。 有線でのシリアル通信が実現できている環境を、既存のコマンド処理システムを崩さずに、XBeeによる無線通信へ移行可能なプログラムを目指しています。


2. XBee用API通信プログラムのダウンロード

使用言語:C
最新版の開発環境:AVR studio 6.1(ただし、どのコンパイラでも動作するはずです)
ターゲットマイコン:何でも良い
対応機種:XBee シリーズ1
対応ファームウェア:DigiMesh

DigiMeshをターゲットにしたマイコン用通信制御プログラムです。 シリアル通信制御プログラムの下にこのヘッダファイルをインクルードすることでXBeeと通信を行う事が出来ます。 このプログラムはXBeeデフォルトのAT通信モードとDigiMesh API通信モードの両方に対応しています。


XBeeのハードウェア設定

本プログラムを実行するためには、XBeeの設定が下記の要件を満たす必要が有ります。


プログラムのダウンロード
リリース日 プログラムパッケージ 更新内容
2013/5/4 XBee_control6.3.zip 実に2年ぶりの更新です。 更新が終わったと書きながら、大幅に更新してしまいましたw。 インターフェイス(関数の呼び出し方)は変わりませんが、ソースコードの実装を色々と変えました。 開発環境をAtmel Studio 6.1に変更して動作確認済みです。
  • 送信と受信に関して、現時点で可能な限りファイルを分離
  • ↑の効果で、こちらで用意したシリアル送受信関数を利用しなくとも通信できるようになった
  • 複数のノードからの受信を処理・管理するために、NodeManagerを追加
  • NodeManagerをインクルードすると、受信パケット数が分かるようになった
  • NodeManagerをインクルードすると、1パケット分のデータをきっちり取れるようになった
  • NodeManagerをインクルードすると、周囲にいるノードのアドレスを収集できるようになった
  • NodeManagerをインクルードすると、数パケットを受信している間、逐一監視や処理をしなくても他のことをやれるようになった
  • (↑この辺を実装中、割り込み対応を止めたくなった。)
  • ATコマンドレスポンスの待ちにタイムアウトを設置
  • 受信データサイズ(byte)を返す関数を整備
  • 特定のノードに絞った受信ができるような仕組みを導入
  • ファイルの文字コードをUTF8へ変更
以後の開発はC++版へ移ります。 といっても、C++だと既にArduino用のライブラリとかあるんですよね。 やることと言ったらこのCライブラリと同様に使える様にラッパーを用意するのと、シリアル関係の処理を自分のAVRマイコン用に書き直したクラスやそのインターフェイスを用意する位か…? 後、ノードマネージャは必須だからこれを移植・・・といったところでしょうか。 なお、プログラムの公開場所はここに加えて、GitHubを利用したいと思います。 もしコラボして開発したいという方がいれば宜しくお願いします。

最近になってArduino用に書かれたAPIをじっくり読んだのですが、文字列解析の部分はほぼ同じ構造になっていました。 やっぱり似るもんですね。 ところで、私のプログラムは割り込み処理に対応するために若干コードが肥大気味です。 パケットが貯まるような中程度の負荷状況ではRAMの消費量が最小で済むと思いますが、最近になってRAMの消費量が気にならないサイズのマイコンを使うようになったので悩みどころです。 それに、以前は動作速度を気にしてパラメータを直接叩いたいましたが、コードの見通しが悪くなるのと速度も気にならなくなったので関数で情報を渡すようにしました。 スタックメモリが気にならなければそれでいいわけです。 うーん。
2011/5/3 XBee_control6.1.zip CTS対応部分で論理が逆だったバグを修正しました。
また、CTSがHighの間はマイコンから新たなシリアルデータを送らないように変更しました。
CTSに関しては、IOポートを#defineで宣言してあれば有効になります。

CTSを有効にすることで送信ロスが0になることを確認済みです。

*開発環境が(AVR studio 4 + WinAVR)なのはここまでです。
2011/4/26 XBee_control6.0.zip APIコマンドモードにおける、ATコマンドの送出・ATコマンドレスポンスへの対応を実現しました。
現在実装済みのコマンドは受信信号強度(RSSI)の取得メソッドのみです。
ATコマンド送信・取得のための下地は用意していますのでどんなメソッドでも追加の実装が小さな資源で実現可能です。
割り込みを使用するには、XBee.hヘッダ,UARTヘッダ,XBee_control6.0.hの順でインクルードした上で、UART受信割り込み関数内に以下を宣言してください。
#ifdef SCI_RX_INTERRUPT
SCI_RX_INTERRUPT
#endif

XBee制御コード内でリングバッファを設けましたので、制御側からの見かけ上はシリアルのバッファにアクセスしている様に見えます。 また、割り込み処理を使うと、受信パケットは全て勝手に処理されます。 割り込みを使用しない場合は、バッファにデータがあるかチェックを行う際に処理されます。

今回のアップグレードによって、個人的に計画していた全てのXBeeに関する基本メソッドは実装し終わりました。 今後はバグの修正などのメンテナンスしか行わない予定です。 本プログラムの応用に関しては別ページを設けて続けていきたいと思います。
これで、今までソースコード内に書いていたXBee固有関数を減らしてようやく汎用性を確保できます。
2011/4/22 XBee_control5.0.zip Transmit Status解析・CTSによる出力抑制・受信データの割り込み処理の3つに対応しました。
使い方に関しては5月下旬までに掲載予定です。

次回、ATコマンドとその応答パケットの解析機能を搭載する予定です。
[注意]現時点ではRTSへ対応する予定はありません。
2011/4/18 XBee_control4.1.zip AP=2でのAPI通信モードでのバグを修正しました。
テスト用の文字列を格納したテキストファイルを同梱しています。
2011/4/17 XBee_control4.0.zip AP=2でのAPI通信モードに対応しました。
今まではAPIモードで初期化する際に“COM_API_MODE”を引数で渡していましたが、“API_WITHOUT_ESCAPES”を渡すように変更しています。
また、AP=2で通信を行う場合は“API_WITH_ESCAPES”、AP=0(ATコマンド(透過)モード)は“API_OFF”としています。
AP=2へ対応できたことでAPIモードにおけるバイナリ受信が可能になり、さらに不正規データ入力に対してXBeeが強くなりました。
コードサイズもほとんど膨れていませんので、これまでのコードを使用している方は更新されることをお勧めします。

これまで気が付かなかったのですが、AVR以外のマイコンを使用する際に“string_personal5.5.h”をインクルードしていなかった不具合も解消しました。
次回、Transmit Status応答の解析機能を搭載する予定です。
2011/4/14 XBee_control3.1.zip ATコマンドモードを指定した場合における、送信が上手く行かないバグを修正しました。
また、ATモード時で出力文字列中に'\n'を発見した場合に'\r'を追加で送信するように変更しました。
同梱文字列ヘッダファイルも更新しています。

最近、開発プラットフォームがよりメモリの多いATmega1284Pに移りました。
プログラムメモリ容量の心配がなくなっりましたので、AP==2に対しても対応したいと思います。
2010/11/17 XBee_control3.0.zip やっと、送信・受信ともに稼働するようになりました。 と云う訳でver3.0正式リリースとします。
受信は、以下の様に行います。
if(rs_rx_buff())c = rs_getc();// rs_getc()単体だと、受信データが無ければヌルが返ります。
又は、
if(rs_rx_buff())(void)rs_gets(buff);// この関数はバッファオーバーランを観測しない。現在の所、未読の受信データ全てが格納されます。
[注意]現時点ではCTSやRTSに未対応です。 CTSについては使用するソフト側で対応する様にして下さい。
[2010/11/20追記]プログラムの公開について研究を先越されたらどうすんだとコメントを頂きましたが、 私としては環境計測による生態系保護が出来ると本気で考えていますので構いません。 容易に越せるとは思えませんし。
[2010/11/26追記]初期化時にATコマンドモードに設定すると、XBeeがATコマンドモードであっても、通信が正常に行えない様です。 このバグについては次回のアップロードで修正します。
2010/11/15 XBee_control3.0beta3.zip 11/11にアップした様に、rs_printf()にバッファオーバーラン防止用のサイズ制限を掛けました。 初期化の仕方は全く変わりません。 ただし、AVRマイコンを使用する旨の宣言を使ってROMRAMを節約する場合、PSTRマクロを使うので相変わらずバッファオーバーランの危険性が有ります。 この場合、例えばrs_printf("test message = %s.\n", str);であれば"test message = %s.\n"の総文字数+1(ヌル文字)文を見込んだバッファサイズを初期化関数の第2バッファに渡す必要が有ります。 その他のマイコンで有れば全く問題ないはずです。
[注意]現時点ではCTSやRTSにも未対応です。 暫くはCTSについては使用するソフト側で対応する様にして下さい。 未対応のままと云う事もあり得ます。
2010/11/11 XBee_control3.0beta2.lzh 送信に関して、若干関数構造が変わったため実際にマイコンで動作確認を行いました。
今回はputc(), puts(), putsb()に加え、簡易printf()にも対応しました。 今回のアップデートで送信に関しては、ほぼ完成と云って良いと思います。
[注意]現時点ではprintf()で使用される関数にバッファオーバーラン対策が取られていません。 近いうちに対策を施す予定ですので、それまでは大きめのバッファを初期化時に渡して下さい。 また、CTSやRTSにも未対応です。 暫くはCTSについては使用するソフト側で対応する様にして下さい。
2010/11/7 XBee_control3.0beta.h 初公開。
普通の文字列送信、バイナリ送信に対応しています。 受信処理に関してはアルゴリズムを模索中であり、限定的な使い方しかできません。
と云う訳でβバージョンをリリースします。


3. プログラム解説

3.1 プログラムの基本構造

本プログラムはマイコンによる有線シリアル通信をXBeeを使った無線通信に切り替えを実現するための物です。 通常の有線通信では図2.1.1に示す様に、puts()関数が呼び出されると配列の先頭アドレスが制御関数に渡され、 制御関数はヌルを検出するまでリングバッファにデータを書き込みます。 次に、開始された割り込み処理で全ての未送信データが無くなるまで送信動作が続きます。

一方、XBeeを使った通信は図2.1.2の様になります。 puts()関数はコンパイル時にXBee制御用のヘッダによってXBee_sent()関数に置換されます。 そのため先ずXBee_sent()関数が呼び出されます。 XBee_sent()関数は送る必要のあるデータ量を計量した上でデータ列を専用のパケットに加工してrs_putc()を呼び出すことで送信します。

有線のシリアル通信のイメージ

図3.1.1 有線のシリアル通信のイメージ

XBeeを使った通信のイメージ

図3.1.2 XBeeを使った通信のイメージ

3.2 プログラムの使い方 初期化編

本プログラムの実装例を図3.3.1に示します。 使い方はシリアル通信ヘッダの下にXBee_control.hファイルをインクルードして初期化するだけといたって簡単です。 初期化関数の詳細な使い方はソースコードの説明を読んで頂ければ分かります。 引数は、送信先のアドレス(上下で合わせて64bit)・ネットワークアドレス・ブロードキャスト半径・送信モード(ブロードキャスト/ユニキャスト)・通信モード(AT/API)・送信に使用するバッファアドレス・そのバッファのサイズで構成されています。 送信に使用されるバッファについては、printf関数が若干複雑なため2つ渡す必要が有ります。 図3.3.2の様にAVRマイコンを使用していると宣言しないならば、2つのアドレスは同じで構いません。 さらに、printfを使用しないならばダミーアドレスを渡しても構いません。

3.3 プログラムの使い方 送信編

図3.3.1のサンプルでは、XBeeモジュールを使って通常のシリアル通信を使うコード例と、API通信モードで通信を行うコード例の2通りの方法について示しています。 これを実際に動作させると、XBeeのAPI通信設定がONになっているかOFFになっているかで正常な通信が行えるコードが切り替わるはずです。

なお、シリアル通信プログラムは以下の関数を含むものとします。 シリアル通信関係の関数名はユーザーによって異なると思いますのでrs_putc()等の関数名は、このプログラムを使用する各人で調整して下さい。 ただし、全てのシリアル出力関数は結局XBeeの制御関数に置換されるので、最低限必要な関数はputc()とgetc()とrs_rx_buff()となっています。 受信データの初期化関数であるrs_rx_purge()がないとコンパイラに怒られますので、無ければダミーで良いですので用意してください。

     1 :	#include <micon.h>                      // マイコン独自のヘッダファイルをインクルード。ここでシリアル関係関数のプロトタイプを宣言の事。 
     2 :	#include "uart.h"                       // シリアル関係のプログラム。このプログラム利用者の方で用意して下さい。
     3 :	#include "XBee_control4.0.h"            // XBeeで通信するためのヘッダファイル
     4 :	
     5 :	// 各種定数の定義
     6 :	#define NETWORK_ADD 0x3301u             // XBeeのネットワークアドレス
     7 :	#define BROADCAST_R 2                   // ブロードキャスト半径(メッセージをリレーさせる数)
     8 :	
     9 :	int main(void){
    10 :	    char  tx_buff[100];                 // XBeeでの送信に使用する。サイズは十分大きく取って下さい。
    11 :	    char  temp[5];                      // テスト用のバッファ
    12 :	    int   i;
    13 :	
    14 :	    /* 先ずは普通に通信するモードでの送信…XBeeの設定を[API OFF]にして送信します */
    15 :	    (void)XBee_init(BROADCAST_ADDRESS_MSB, BROADCAST_ADDRESS_LSB, NETWORK_ADD, BROADCAST_R, BROADCAST_TRANSMIT, API_OFF, tx_buff, sizeof(tx_buff), tx_buff, sizeof(tx_buff));// XBeeの初期化
    16 :	    // 送信のサンプルメッセージ
    17 :	    rs_puts("This is Broadcast sending.\n");
    18 :	    for(i = 0;i < 5;i++)rs_printf("count = %d.\n", i);
    19 :	    temp[0] = 0x01;                     // 普通の通信モードでは、バイナリの通信は保証されません
    20 :	    temp[1] = 0x02;
    21 :	    temp[2] = 0x03;
    22 :	    temp[3] = 0x04;
    23 :	    temp[4] = 0x05;
    24 :	    rs_putsb(temp, sizeof(temp);        // バイナリデータの送信について成功の保証はないがやってみる
    25 :	    rs_putc(0x0a);                      // 改行コード
    26 :	    
    27 :	    /* 次はAPIモードでの送信…XBeeの設定を[AP(API Enable]=2にしていれば正常に送信されます */
    28 :	    (void)XBee_init(BROADCAST_ADDRESS_MSB, BROADCAST_ADDRESS_LSB, NETWORK_ADD, BROADCAST_R, BROADCAST_TRANSMIT, API_WITH_ESCAPES, tx_buff, sizeof(tx_buff), tx_buff, sizeof(tx_buff));// XBeeの初期化
    29 :	    // 送信のサンプルメッセージ
    30 :	    rs_puts("This is Broadcast sending.\n");
    31 :	    for(i = 0;i < 5;i++)rs_printf("count = %d.\n", i);
    32 :	    temp[0] = 0x01;
    33 :	    temp[1] = 0x02;
    34 :	    temp[2] = 0x03;
    35 :	    temp[3] = 0x04;
    36 :	    temp[4] = 0x05;
    37 :	    rs_putsb(temp, sizeof(temp);        // バイナリデータ送信
    38 :	    rs_putc(0x0a);                      // 改行コード
    39 :	
    40 :	
    41 :	    for(;;);                            // AVRではこれを付けるとコンパイルサイズが小さくなるらしい 
    42 :	}
			

図3.3.1 プログラムの使用例

なお、制御に使用するマイコンがAVRシリーズでコンパイラにWinAVR + AVR studioを使用しているなら、図3.3.2の様に使用マイコンを宣言することをお勧めします。 こうすることでAVR用にチューニングされ、消費RAM量を減らすことが出来ます。 ただし、図2.2.3に示す様に初期化時の引数が若干異なります。 printf()に対応するために第2のバッファを宣言してそのポインタを渡してやる必要が有ります。 私はグローバル変数を宣言することで全関数からそのバッファを共有することにしています。

プログラムのAVRバージョン

図3.3.2 AVRマイコンを使用しているなら、上記の様にプログラムの先頭にマイコンの種類を指定するとRAMの使用量を減らすことが出来る

AVRバージョンでの変更点

図3.3.3 ただし、初期化時に第2のバッファを渡す必要があります

3.4 プログラムの使い方 受信編

rs_getc()やrs_gets()を使って受信可能です。 rs_getc()は受信データがなければnullを返す仕様にしています。 予めrs_rx_buff()を使用して受信データが存在するかを確認してからアクセスする方法を推奨します。 例えば、“if(rs_rx_buff())c = rs_getc();”です。 ところで、XBeeを使用していない時と同様に、CPUクロックを極端に落としている場合や受信データの処理に手間取りすぎてバッファの読み込みが遅れると正常なデータの読み出しは期待できません。 前回の受信処理から時間が経ってしまった場合はrs_rx_purge()を呼び出してバッファを初期化してください。


4. ホップ通信のテスト

2010年に熊本大学で始まった全学無線LAN(黒髪南キャンパス)のおかげでZigBeeの使える帯域が全て潰れてしまいました。 お陰で前年までは隣接する白川まで行っても通信が出来ていたのですが今では50mがやっとです。 この様に悪化した通信環境を使用してホップ通信の試験を行いたいと思います。 試験日は現在の所、未定です。


参考資料

リンク集を参照して下さい。
inserted by FC2 system