目次 [ Contents ]
TOCOSから販売されている「TWE-LITE」は無線技術ゼロ、電子工作初心者でも簡単に導入できる仕様になっています。そのメリットは
・ 配線だけで無線装置を構築できる。
・ 隣の部屋くらいなら壁があっても難なく届く。状況しだいでは1kmでも大丈夫(らしい)
・ 省電力。設定次第では長期間持たせることができる。
・ 電波法に準拠しているので、安心して使える。
接続例にあるスイッチ&LEDだけでその簡単さが分かると思います。
基本操作:スイッチでLEDを遠隔で操作
TWE-LITEを2台用意して上のイラストどおりにそれぞれ接続します。
親機のスイッチを押せば子機のLEDが光ります。
注意点
○アナログ入力を使わない場合定電圧にしておかないと不安定になる。
○IO操作には親子関係が必要。イラストではオレンジのGND結線が設定に当たります。
○D-out 1から電圧が出てLEDへ、と考えたいとこですが、TWE-LITEでは逆になります。つまり (子機)電圧→LED→D-out 1~(無線)~D-in 1→スイッチ→GND(親機)
という流れに。
こんな配線だけでLEDのON/OFFリモコンができるようになります。トランジスタやリレーを併用すれば、何でもワイヤレス装置にすることも。他にもI2C、UART通信ピンも用意されていたり、別途ライターを用意すれば他のアプリに書き換えて、それぞれの機能に特化した装置に変更することも可能だそうです。
便利ですよね。
で、ここからが本題ですが、説明では最初から入っている標準アプリだけでUART通信出来るって書いてあるんですけど、どうやるのかな、と。
UARTはArduinoで言うSerialです。つまり、通常IDEのシリアルモニタでPCとやりとりしているのを無線で結べたら便利ですよね。
ということで、ArduinoでTWE-LITEのUART受信を行ってみます。
TWE-LILTEパケットの受信
TWE-LITE標準アプリの仕様
TOCOSの説明では、
相手端末の状態通知を受けた時にはUARTシリアルにもその情報が常に出力されます。データはポートの値が変化した場合と定期的(約1秒周期)に送受信されます。
と記しています。つまり何もしなくてもTWE-LITE同士はやりとりしていることになります。これをArduinoで拾ってみます。
先ほどの構成にArduinoを付け足します。
UART受信するための配線
注意点
○ArduinoのSowfwareSerialを使いD5ピンへTWE-LITEのUARTを受信、それを通常のSerialでIDEシリアルモニタに表示。
○ArduinoUNOは5V駆動ですがTWE-LITEは3.6V内で動作します。つまり、そのまま相互通信しようとすると、TWE-LITEに過負荷をかけ壊します。今回は受信だけなので、動くかもしれませんが、正確にはロジックレベル変換・レベルシフトしてRXに接続するか、Pro miniみたいな3Vで動く機体を用意することをオススメします。
○SoftwareSerial受信→シリアルモニタにSerial.print だと、結構時間がかかるようなので、Arduinoの種類によっては取りこぼしが出てくるみたいです。なので、TWE-LITEの通信ボーレートを通常の115200ではなく38400にします。イラストではピンクのGND結線がその設定に当たります。
基本スケッチ
#include <SoftwareSerial.h> SoftwareSerial TWE(5, 6); // RX, TX #define LED 13 void setup() { TWE.begin(38400); Serial.begin(38400); pinMode(LED, OUTPUT); } void loop() { char recv = 0; while (TWE.available()) { digitalWrite(LED, HIGH); recv = TWE.read(); Serial.print(recv); } digitalWrite(LED, LOW); }
LEDはArduino本体に埋め込まれている13ピンLEDのことです。受信がある間点灯するようにしています。 単純にこれで1秒ごとに送信している親機のステータスが見れるようになります。また、D-in 1に接続したLEDスイッチをON/OFFしてもそのステータス変化が受信されます。
変数recvをキャラクター型にしているので、Serial.printでは文字コード変換されたものが表示されます。また、最後入っている改行コードも認識されて勝手に改行してくれてます。 ただ、単純に数値を見たいだけならこれで充分なんですが、文字列なので、これをそのまま整数値として扱う云々は出来ません。 試しに変数recvの型をbyte にします。
#include <SoftwareSerial.h> SoftwareSerial TWE(5, 6); // RX, TX #define LED 13 void setup() { TWE.begin(38400); Serial.begin(38400); pinMode(LED, OUTPUT); } void loop() { byte recv = 0; while (TWE.available()) { digitalWrite(LED, HIGH); recv = TWE.read(); Serial.print(recv); Serial.print(" "); } if (recv == 10) Serial.println(); digitalWrite(LED, LOW); }
10進法の羅列になります。改行もされないのでずっと右に向かって表示されていきます。
TWE-LITEのパケットを扱える数値として受信する
TWE-LITEのURAT通信にはルールがあります。
- パケットの最初は「:」。
- キャラクター型で表現した16進数でやりとりする
- チェックサムをいれる
- 最後に改行コードを入れる CRLF(0x0d 0x0a)
上のシリアルモニタに表示されている数字はパッと見、訳わかんないですが、ASCIIコード表で照らし合わせると、
- 58(10進法) = 「:」、
- 48(10進法) = 「0」
ってことが分かります。そして最後の13、10はCR、LFに当たるんだな、と。 ってことをふまえスケッチを少し書き直します。
#include <SoftwareSerial.h> SoftwareSerial TWE(5, 6); // RX, TX #define LED 13 void setup() { TWE.begin(38400); Serial.begin(38400); pinMode(LED, OUTPUT); } void loop() { byte recv = 0; while (TWE.available()) { digitalWrite(LED, HIGH); recv = TWE.read(); Serial.print(recv); Serial.print(" "); } if (recv == 10) Serial.println(); digitalWrite(LED, LOW); }
23行目で1バイトの受信ごとにスペースを開け、26行目では(最後の)受信バイトが「10(10進数)」だったら改行(Serial.println)させてます。
見やすくなりました。 今のスケッチだと変数recvは拾った値を1バイトごとに上書きしてしまっているので、1回の受信で拾ったパケットはとりあえず全部保持できるようスケッチを書き直します。
#include <SoftwareSerial.h> SoftwareSerial TWE(5, 6); // RX, TX #define LED 13 void setup() { TWE.begin(38400); Serial.begin(38400); pinMode(LED, OUTPUT); } void loop() { byte recv [60] = {}; byte count = 0; while (TWE.available()) { digitalWrite(LED, HIGH); recv [count] = TWE.read(); count++; } if (count > 0) { for (byte i = 0 ; i < count ; i++) { Serial.print(recv[i]); Serial.print(" "); } Serial.println(); } digitalWrite(LED, LOW); }
受信したデータを入れる変数recvを配列にし、個数数える変数countを用意して1バイト受信するごとにcountを繰り上げ。パケット受信が終了した後、最終的なcount分だけrecv配列内の数値をSerial.printします。if (count>0)はLoopを繰り返す中で受信があったときだけ改行するためのものです。
見た目上はさっきと変わらないですが、受信したパケットを1バイトずつ扱えるようになりました。 これを最終的に実際の10進法の数値へ変換します。
文字列の数字を整数値に変換する
キャラ型の「0」は整数としては「48」、キャラ型の「1」は整数「49」という風になっているので、’0’を引き算することでシフトさせることができます。たとえば、変数recvに入った文字が5(53)なら recv = recv – ‘0’; → recv = 53 – 48; となり結果5が代入される形になります。16進数なのでA-Fは別腹にして、’A’を引き算すれば、これも数値を得られます。この方法でrecv内の文字コードを実際の整数に変換するスケッチにします。
#include <SoftwareSerial.h> SoftwareSerial TWE(5, 6); // RX, TX #define LED 13 void setup() { TWE.begin(38400); Serial.begin(38400); pinMode(LED, OUTPUT); } void loop() { byte recv [60] = {}; byte count = 0; while (TWE.available()) { digitalWrite(LED, HIGH); recv [count] = TWE.read(); count++; } if (count > 0) { byte space [] = {1, 3, 5, 7, 9, 11, 19, 21, 25, 27, 31, 33, 35, 37, 47, 49}; byte add = 0; for (byte i = 0 ; i < count ; i++) { if (i == space[add]) { Serial.print(" "); add++; } if (recv[i] == ':') { Serial.print(':'); } else if (recv[i] == 13) { Serial.print(13, HEX); } else if (recv[i] == 10) { Serial.println(10, HEX); } else { if (recv[i] <= '9') recv[i] = recv[i] - '0'; else if (recv[i] <= 'F') recv[i] = recv[i] - 'A' + 10; Serial.print(recv[i], HEX); } } } digitalWrite(LED, LOW); }
「:」と改行コードである「13」「10」は別枠として、他は上の方法で数値に置き換えています。
ついでにデータの区切りでスペースも入れてみました。
本当はこの半バイト状態を一括りにしていくべきなんでしょうが、全部を個別セグメントにまとめていくとそこそこのスケッチになりそうなので、後は欲しいデータがあれば自分でまとめましょう、という結果にします。
HEXについての記事も書いたので合わせて参考にしてください(16/10/14 追記)
TWE-LITEパケットの内訳
最後にそれぞれのデータの意味しているものを書いておきます。
- 送信元の論理デバイスID
- コマンド番号
- パケット識別子
- プロトコルバージョン
- 受信電波品質
- 相手の個体識別番号
- 宛先端末の論理デバイスID
- タイムスタンプ
- 中継フラグ
- 電源電圧
- 未使用
- デジタル入力の値
- デジタル入力の変更状態
- アナログ入力の値と補正値
- チェック・サム
TWE-LITEによるUART送信についても書いてみました(2016/10/21 追記)