トワイライト(TWELITE)で通信先を選択する

組み込みエンジニア

こんにちは、ENGかぴです。

トワイライト(TWELITE)でMWSTAGEのライブラリであるNWK_SIMPLEを使用すると通信先を選択した無線通信ができます。親機と論理IDが異なる2つの子機を使ってブロードキャスト通信と個別の送信を行い動作確認を行いました。

トワイライトを太陽光パネルで動作させたことやMWSTAGEの環境でソフト開発して無線通信したことなどについてまとめています。

トワイライト(TWELITE)のソフト開発と無線通信でできること

共通の設定事項

トワイライトの通信先のイメージ
トワイライトの通信先のイメージ

モノワイヤレス社が提供しているNWK_SIMPLEのライブラリを使用することで通信先を指定した無線通信ができます。親局の論理IDは0x00になりますが、子機は0x01~0xEFまでの指定することができます。詳細は下記リンクを参考にしてください。

モノワイヤレス社ーNWK_SIMPLE

今回は論理IDを区別した無線通信と子機を対象としたブロードキャスト通信(0xFE)の動作についてまとめています。親機と子機でアプリケーションID・チャンネル番号・アプリ識別のための文字列を共通にする必要があります。

const uint32_t APP_ID = 0x1234abcd; // application ID
const uint8_t CHANNEL = 13; // channel
const char APP_CHAR[] = "COM";

TWENETに上記で定数宣言しているAPP_IDとCHANNELを指定して設定します。

the_twelite
    << TWENET::appid(APP_ID) //アプリケーションID
    << TWENET::channel(CHANNEL) //チャンネル設定
    << TWENET::rx_when_idle(); //無線通信を受信する場合は実装

無線通信を受信する場合はrx_when_idle()を実装する必要があります。子機は親機からの受信が必要なのでrx_when_idle()を実装する必要がありますが、親機で送信専用にする場合は実装の必要はありません。

すき間時間で資格をゲット【STUDYing(スタディング)】

親機を実装する

auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
       nwksmpl << NWK_SIMPLE::logical_id(0x00);

TWENETライブラリのnetwork関数を使用して論理IDの設定を行います。ネットワークのlogical_idに0x00をセットすることで親機として動作します。

MWX_APIRET transmit(void) {
    uint8_t txadrs;
    
    //送信先を選択する処理(省略)
    if (auto&& pkt = the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
	pkt << tx_addr(txadrs)  //送信先を指定
            << tx_retry(0x3) 
	    << tx_packet_delay(0,0,2);

        pack_bytes(pkt.get_payload(), make_pair(APP_CHAR, 3));//ヘッダー
        pack_bytes(pkt.get_payload(),do_out); //do_outをパッケージ化する

	return pkt.transmit(); //パケットを送信
    }
}

無線でデータを送信するためにはデータをペイロードに格納しネットワークオブジェクトのthe_twelite.network.use<MWK_SIMPLE>()のtransmit()関数を発行します。

tx_addr()に送信先の子機の論理IDを指定します。子機全体にブロードキャスト通信を行う場合は0xFEを指定します。tx_retryは送信失敗した時のリトライ回数です。

tx_packet_delay()の第1引数は送信開始までの最低待ち時間、第2引数が最長待ち時間です。2つとも0を指定しているので条件とタイミング次第で直ちに送信します。第3引数は再送間隔で最初のパケットを送って失敗した場合2ms間隔で再送を行います。

直ちに送信する場合で再送指定しない場合はtx_process_immediate()による指定も可能です。

送信設定後はペイロードに自分が送りたいデータを格納します。ペイロードの準備が完了したら。ネットワークオブジェクトのtransmit()関数で通信がスタートします。

子機を実装する

auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
       nwksmpl << NWK_SIMPLE::logical_id(0x01);

TWENETライブラリのnetwork関数を使用して論理IDの設定を行います。ネットワークのlogical_idに0x01~0xEFもしくはFE(IDの区別がない)をセットすることで子機として動作します。

void receive() {
    char chk[4];
    uint8_t set;

    auto&& rx = the_twelite.receiver.read();
    auto&& np = expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
		,make_pair(chk,3)); //文字列分を取得
		
    if( strncmp(chk, APP_CHAR, 3)){ return; } //文字列を判定
        np = expand_bytes(np,rx.get_payload().end(),set ); //残りのデータを取得
}

expand_bytes()は受信したペイロード(データのパケット)を指定したバイト数に分けて受信できるため使い勝手の良いAPIです。最初に3バイト受信しているのはアプリの文字列が一致するかのチェックを行うためです。

strncmp()で親機と子機の文字列が一致した場合は同一アプリのものと判断して文字列より先のペイロードのデータを取得する処理を行います。npはポインタで読み込んだデータ分より次のデータの位置を示すポインタになっています。例では変数であるsetに読み出したデータを格納しています。

動作確認

動作確認用の回路図
動作確認用の回路図

親機はSW1を押すと子機に対して無線通信を行います。下表のように親機の15、16をGNDに接続するパターンで送信先を切り替えています。子機は親機からの無線通信を受けてLEDを点灯/消灯します。

DOのパターン DO(15):DO(16)子機の送信先
LOW:LOW0xFE
HIGH:LOW0x01
LOW:HIGH0x02
親機の送信先切り替え

親機の送信先を0xFEにして送信すると子機(論理ID:0x01)と子機(論理ID:0x02)が動作することを確認しました。送信先を0x01に切り替えると子機(論理ID:0x01)のみLEDが点灯/消灯することが確認できました。同様に送信先を0x02に切り替えると子機(論理ID:0x02)のみのLEDが点灯/消灯することが確認できました。

今回はACTを自作して送信先を切り替えて動作確認しましたが、標準アプリやシリアル通信アプリにおいては動作を確認してみるとブロードキャスト通信になっているようです。

ソースコード全体

以下のソースコードはコンパイルして動作確認をしております。コメントなど細かな部分で間違っていたりやライブラリの更新などにより動作しなくなったりする可能性があります。参考としてお使いいただければと思います。

親機のソースコード:

#include <TWELITE>
#include <NWK_SIMPLE>

#define CNG_ID
#define TIME_UP 0
#define TIME_OFF -1
#define ZIG_WAIT_MAX 100

const uint8_t DI_SW = mwx::PIN_DIGITAL::DIO12;
const uint8_t DI_MD0 = mwx::PIN_DIGITAL::DIO15;
const uint8_t DI_MD1 = mwx::PIN_DIGITAL::DIO16;
const uint32_t APP_ID = 0x1234abcd; // application ID
const uint8_t CHANNEL = 13; // channel
const char APP_CHAR[] = "COM";

int16_t timzigwait = TIME_OFF;
uint8_t do_out;
/*** function prototype */
MWX_APIRET transmit(void);

/*** the setup procedure (called on boot) */
void setup() {

    pinMode(DI_SW,INPUT_PULLUP);
    pinMode(DI_MD0,INPUT_PULLUP);
    pinMode(DI_MD1,INPUT_PULLUP);

    the_twelite
	<< TWENET::appid(APP_ID)    
	<< TWENET::channel(CHANNEL) 
	<< TWENET::rx_when_idle();

    auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
    nwksmpl << NWK_SIMPLE::logical_id(0x00);
    the_twelite.begin(); // start twelite!
}

/*** the loop procedure (called every event) */
void loop() {

    if( TickTimer.available()){
        if(timzigwait > TIME_UP){
            --timzigwait;
        }
    }

    if( timzigwait == TIME_UP ){
        timzigwait = TIME_OFF;
        transmit();
    }

    if( digitalRead(DI_SW) == LOW ){
	timzigwait = ZIG_WAIT_MAX;
    }
}
/* transmit a packet */
MWX_APIRET transmit(void) {
    uint8_t txadrs;

    if(digitalRead(DI_MD0) == LOW && digitalRead(DI_MD1) == LOW ){
	txadrs = 0xFE;
    }
    else if( digitalRead(DI_MD0) == HIGH && digitalRead(DI_MD1) == LOW){
	txadrs = 0x01;
    }
    else if( digitalRead(DI_MD0) == LOW && digitalRead(DI_MD1) == HIGH){
	txadrs = 0x02;
    }

    if (auto&& pkt = the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
	pkt << tx_addr(txadrs)  
            << tx_retry(0x3) 
	    << tx_packet_delay(0,0,2);
 
        if( do_out){
	    do_out = 0;
	}
	else{
            do_out = 1;
	}

        pack_bytes(pkt.get_payload(), make_pair(APP_CHAR, 3));//ヘッダー
        pack_bytes(pkt.get_payload(),do_out);
		
	return pkt.transmit();
    }
    return MWX_APIRET(false, 0);
}

子機のソースコード:

#include <TWELITE>
#include <NWK_SIMPLE>

//#define CNG_ID

const uint8_t DO_COM = mwx::PIN_DIGITAL::DIO12;
const uint32_t APP_ID = 0x1234abcd; // application ID
const uint8_t CHANNEL = 13; // channel

const uint8_t LID
#ifdef CNG_ID
= 0x01
#else
= 0x02
#endif
;

const char APP_CHAR[] = "COM";

void receive();

/*** the setup procedure (called on boot) */
void setup() {

    pinMode(DO_COM,OUTPUT);

    the_twelite
	<< TWENET::appid(APP_ID)    
	<< TWENET::channel(CHANNEL) 
	<< TWENET::rx_when_idle();

    auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
    nwksmpl << NWK_SIMPLE::logical_id(LID);
    the_twelite.begin(); // start twelite!
}

/*** the loop procedure (called every event) */
void loop() {

    while (the_twelite.receiver.available()) {
	receive();
    }
}
/* 無線通信を受信して処理する */
void receive() {
    char chk[4];
    uint8_t set;

    auto&& rx = the_twelite.receiver.read();
    auto&& np = expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
		,make_pair(chk,3)); 
		
    if( strncmp(chk, APP_CHAR, 3)){ return; } // check header
        np = expand_bytes(np,rx.get_payload().end(),set );

    if( set == 1){
        digitalWrite(DO_COM,HIGH);
    }
    else{
        digitalWrite(DO_COM,LOW);
    }
}

関連リンク

トワイライトを太陽光パネルで動作させたことやMWSTAGEの環境でソフト開発して無線通信したことなどについてまとめています。

トワイライト(TWELITE)のソフト開発と無線通信でできること

テックキャンプ エンジニア転職 無料カウンセリング

最後まで、読んでいただきありがとうございました。

タイトルとURLをコピーしました