こんにちは、ENGかぴです。
ZigBeeモジュールであるトワイライト(TWELITE)を使用し、各種センサーと組み合わせることでIoTへの応用が期待できます。トワイライトの子機からデータを無線受信する親機を実装しシリアルモニターに表示する方法についてまとめました。
TWELITE DIPを2つ使用し一方を親機もう一方を子機として使用します。子機には下記記事に使用したソフトを流用して使用します。
トワイライト(TWELITE)にAD変換と無線通信を実装する
トワイライトを太陽光パネルで動作させたことやMWSTAGEの環境でソフト開発して無線通信したことなどについてまとめています。
トワイライト(TWELITE)のソフト開発と無線通信でできること
親機を実装する
親機は子機からの無線通信を受信してシリアル通信でモニターできるようにします。親機は同一のアプリケーションIDやセットとなる文字列4文字(任意でよい)によってセットとなる子機からの電文であることの判断を行います。
ACTの「BRD_APPTWELITE」を参考にしながら親機としての機能を実装していきます。具体的には子機からの無線データを受信してシリアルでデータを書き出します。BRD_APPTWELITEの詳細の説明は下記のリンクを参考にしてください。
const uint32_t APP_ID = 0x1234abcd;
const uint8_t CHANNEL = 13;
const char APP_FOURCHAR[] = "TEMP";
APP_IDとチャンネルはサンプルと同じにしています。APP_FOURCHAR[]は受信したデータに自作のアプリに埋め込んだアプリ識別のための文字列です。
子機側のソフトにおいてもAPP_FOURCHAR[]と同じ文字列を送信して親機が受信して文字列を比較して一致した場合にデータを受け付けるような処理に使用します。
the_twelite
<< TWENET::appid(APP_ID) //アプリケーションID
<< TWENET::channel(CHANNEL) //チャンネル設定
<< TWENET::rx_when_idle(); //無線データを受信するために必要
auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
nwksmpl << NWK_SIMPLE::logical_id(0x00); //0x00にすると親機設定(子機は0xFE)
the_tweliteにおいてrx_when_idle()を設定しておく必要があります。子機として送信専用で使用する場合は不要でしたが、無線データを受信する必要があるため実装します。ネットワークのlogical_idに0x00をセットすることで親機として動作します。
メイン関数(loop())内では受信待ちの処理でループするように構成します。
void loop() {
if(TickTimer.available()){
++cnt1ms;
}
while (the_twelite.receiver.available()) {
receive(); //受信したらこの関数で処理
rcvflg = true;
}
if( cnt1ms >= CNT_MAX){
cnt1ms -= CNT_MAX; //CNT_MAX=1000
ts = (ts + 1 ) % 100000; //1秒に一回更新
if(rcvflg){
rcvflg = false;
}
else{
Serial << "ts:" << int(ts) << mwx::crlf << mwx::flush;;
}
}
}
受信待ちはthe_twelite.receiver.available()で行います。受信したデータが残っていると直ちに処理するためにwhile文でパケット処理が終了するまで受信処理を行います。
データが受信するまでの期間に何も表示されないと動作しているかわかりにくいためタイムスタンプとしてtsをカウントしながらシリアルで書き込み表示しています。
tsは5桁の数値で収まるように%で余りの数としてカウントするようにしています。これは以下のように書き換えることができます。
if(++ts >= 100000){
ts = 0;
}
受信したときのループを抜けた先にタイムスタンプの表示のためシリアル書き込みがありますが、受信処理の中でシリアル書き込みを行うため2回ダブってタイプスタンプを書かないようにフラグ管理しています。
フラグ管理していても1秒以内に処理が終わる場合同じ時刻がタイプスタンプとして表示されてしまいますが、子機が複数台になったときは同時刻のタイムスタンプがありえるため許容できる範囲だと思います。
void receive() {
auto&& rx = the_twelite.receiver.read();
char fourchars[5]{}; // init all elements as default (0).
auto&& np = expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
, make_pair((uint8_t*)fourchars, 4) // 4bytes of msg
);
if (strncmp(APP_FOURCHAR, fourchars, 4)) {return; } //子機の文字ヘッダーが一致するか
expand_bytes(np,rx.get_payload().end(),adrs,vcc,temp);
}
expand_bytes()は受信したペイロード(データのパケット)を指定したバイト数に分けて受信できるため使い勝手の良いAPIです。最初に4バイト受信しているのはアプリの文字列が一致するかのチェックを行うためです。
strncmp()で親機と子機の文字列が一致した場合は同一アプリのものと判断して文字列より先のペイロードのデータを取得する処理を行います。npはポインタで読み込んだデータ分より次のデータの位置を示すポインタになっています。
これを利用して文字列以降のデータのチェックサムを行ったりデータ長のチェックを行ったりできそうです。例えば固定長としexpand_baytes()に指定する1バイト分のデータの配列を準備しておき規定回数繰り返すことでデータを取得してチェックサムの計算を行い比較できそうです。
for( i = 0; i < 10; i++){
expand_bytes(np,rx.get_payload().end(),buf[i]);
//チェックサムの計算を入れる
}
今回はチェックサムによるデータの確認は行いませんが、実装するとしたら上記のようなイメージになると思います。
PR:わからないを放置せず、あなたにあったスキルを身に着けるコツを教える テックジム 「書けるが先で、理解が後」を体験しよう!
子機を準備する
子機は下記記事で使用したソフトを流用します。
トワイライト(TWELITE)にAD変換と無線通信を実装する
変更点は消費電流を抑えるためにショートスリープを実装したことや子機のアドレスを区別するためにDIを2点追加したことです。
pinMode(PIN_DO1, OUTPUT_INIT_LOW); //BOOTをLOW
pinMode(PIN_DO2, OUTPUT_INIT_HIGH); //TEMP OFF
pinMode(PIN_DI1,INPUT_PULLUP);//アドレス用
pinMode(PIN_DI2,INPUT_PULLUP);//アドレス用
PIN_DO2は温度センサーへの電源供給を制御するために使用します。温度センサー(MCP9700A)に電源を供給し続けるとその分消費電流が増えるためAD変換する100ms前に温度センサーの電源をONするために準備しています。
void wakeup(){
if (!b_senser_started) { //スリープからのウェークアップ
b_senser_started = true;
digitalWrite(PIN_DO2,LOW);//センサーをON
napNow();//ショートナップ(100msスリープ)
}
else{
b_transmit = false;
}
}
スリープからウェークアップしたときに温度センサーへの電源供給を行いショートナップ(100ms)をすることで温度センサーのデータが取得できる状態とします。DOにシンク電流を引き込むことになりますが、温度センサーの消費電流が数uAなので問題ありません。
動作確認
子機を2台準備しアドレスに変化を与えて親機に無線通信して温度情報を表示します。
動作確認用の回路図

電源はTWE-EH-Sを使用します。子機は電源電圧とMCP9700A(温度)のデータをAD変換して無線通信します。今回は5秒間欠動作にしていますが、TWE-EH-Sに接続したバックアップ電源の消耗を抑えるために間欠動作のタイミングを長く(5分に一度)した方が良いかもしれません。
子機はアドレスを1と2で区別して親機にデータを送信したいので2台準備します。1台のDI2をGND接続しもう一台のDI1をGNDに接続することでアドレスを区別します。

動作結果

親機はトワイライターに接続したままTeraTermで表示します。MWSTAGE上でモニターできますが文字化けして表示できない現象があったためTeraTermにしています。
親機にアドレス1とアドレス2からのデータが受信できておりデータが表示されています。タイムスタンプ後の254は子機のIDである0xFEが数値化したものです。VCCは子機のトワイライトの電源をAD変換したものになるため電圧をモニタすることで電池の消耗具合が分かります。
tempは温度センサーのデータをMCP7800Aのデータシートに基づいて温度換算した値を表示しています。天気が悪く室内環境は冷房環境であり室温系を見た時24.5℃だったため計測できていることが分かりました。アドレス2の方が値が高くなっているのは窓際に配置したためです。(アドレス1は作業デスク上に配置)
ソースコード全体
ソースコードは記事作成時点において動作確認できていますが、使用しているライブラリの更新により動作が保証できなくなる可能性があります。また、ソースコードを使用したことによって生じた不利益などの一切の責任を負いかねます。参考資料としてお使いください。
リンクからZIPファイル形式のファイルをダウンロードし、任意の場所に展開していただくとテキストファイルが生成されます。
TWELITEのソースコードはMWSTAGEの環境でアクトのソースファイルにコピーすると使用できます。
動作開始直前の数回は温度の値が安定しません。平均化しているため4回分のデータが揃わなければ平均値がバラつくからです。温度データが安定してから送信する仕組みを実装してもよさそうです。
関連リンク
トワイライトを太陽光パネルで動作させたことやMWSTAGEの環境でソフト開発して無線通信したことなどについてまとめています。
トワイライト(TWELITE)のソフト開発と無線通信でできること
最後まで、読んでいただきありがとうございました。