目次 [ Contents ]
電子工作で簡単に無線化できるTOCOSのTWE-LITE。標準で組み込まれている「超簡単!TWE標準アプリ」ではそれぞれ4つのデジタル/アナログ入出力を扱うことが出来ます。通常ではスイッチや可変抵抗器を使って入力から通信先のピンをコントロールしますが、UART送信で直接相手ピンを操作する機能もあります。
今回はArduinoからのUART通信で直接相手側のTWE-LITE出力ピンを操作してみます。
配線図
- Arduino(3.3V駆動) * 2
- TWE-LITE * 2
- LED * 4 & 抵抗
- 子機用電源
親機にはPC&Arduinoをつないでスケッチを流し込めるようにします。
確認
単純にジャンパーワイヤを使って、親機のD IN1~4をそれぞれGNDにショートさせて子機のLEDがちゃんとつくか確認してみてください。
*D INピンの状態が優先されるので、確認後はGNDをショートさせたままにしないでください。
この点灯をArduinoにやらせます。
送信方法
ArduinoとTWE-LITEのやりとりは決められたフォーマットでキャラ型のHEXを送ります。こちらを参考にどうぞ。
フォーマット
相手のピン状態を操るためのコマンド番号は0x80です。また、今回の設定では親機から子機になるので、宛先の論理デバイスIDは0x78になります。
1番 | 2番 | 3番 | 4番 | 5番 | 6番 | 7番 | 8番 | 9番 | 10番 | 11番 |
: | 78 | 80 | 01 | 00 | 00 | FFFF | FFFF | FFFF | FFFF | X |
*表内の数字は16進数です
- ヘッダ
- 宛先ID(0x00 親機、0x01~0x64 任意のID、0x78 全ての子機)
- コマンド番号
- プロトコルバージョン(0x01 固定)
- デジタル出力ピンの状態(4ビット)
- デジタル出力ピンの変更マスク
- アナログ出力ピン1
- アナログ出力ピン2
- アナログ出力ピン3
- アナログ出力ピン4
- チェック・サム
デジタルピン出力
5番、6番のデジタルピン出力に関する設定は、各1バイト中の下位4ビットで各々の状態を表現しています。
1バイト | ||||||||
– | – | – | – | D1 | D2 | D3 | D4 | |
B | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
例えば、
- D1をつけたければ B00000001で10進法の「1」
- D4をつけたければ B00001000で10進法の「8」
- D2とD3をつけたければ B00000110で10進法の「6」
となります。
マスク
5番で変更したピン状態に対して、6番でその変更を適用するのか指定しないといけません。適用の有り無しは同様に0か1で指定します。
- D1ピンを変更したければ、5番をB00000001、6番をB00000001にします。
- 5番でB00000001としても、6番でB00000000となっていれば、ピン状態は変わりません。
- 5番がB00001111で、6番がB00001001となっていれば、D1とD4ピンだけが変更になります。
スケッチ
D1のピンを点滅させる
上記の説明を見てもらえれば、ややこしい部分は5番、6番のビット操作だけだと分かります。なので、とりあえず単純に送るフォーマットを配列で用意し、D1の状態を反転させて1秒おきに点滅するスケッチを書いてみます。
#include <SoftwareSerial.h> SoftwareSerial TWE(5, 6); // RX, TX void setup() { TWE.begin(38400); } void loop() { char data [11] = {':', '7', '8', '8', '0', '0', '1', '0', '1', '0', '1'}; static bool reverse; static unsigned long intval = millis(); if ((millis() - intval) >= 1000) { // invert pin status for each send data [8] = (reverse) ? '0' : '1'; // send UART data from Header to Digital out pins for (byte i = 0 ; i < 11 ; i++) TWE.write(data[i]); // send UART data of Analog pins for (byte i = 0 ; i < 16 ; i++) TWE.write('F'); // check sum TWE.write('X'); intval = millis(); reverse = !reverse; } }
変数“data”配列のD1ピンにあたるdata[8]を毎回反転しています。数値ではなくキャラ型の0・1なのに注意です。
ちなみに、その後のアナログ出力は最大値にしておくため0xFFを4ピン分投げ込んでいます。
TWEへの送信の関数化
今度は4つのピンを動かせるようにします。そのためTWEへの送信を関数化します。
こんな感じです。
void TWE_PIN_SEND(byte val) { const char hexer [16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; const byte hdata [6] = {7, 8, 8, 0, 0, 1}; static byte previous = 0x00001111; //send header data TWE.write(':'); for (byte i = 0 ; i < 6 ; i++) TWE.write(hexer[hdata[i]]); val &= B00001111; //--send pin status--// //Main //send higher 4 bits TWE.write(hexer[0]); //send lower 4 bits TWE.write(hexer[val]); //Mask //send higher 4 bits TWE.write(hexer[0]); //send lower 4 bits TWE.write(hexer[(val ^ previous) & B00001111]); //send analog pin data (all 'F') for (byte i = 0 ; i < 16 ; i++) TWE.write(hexer[15]); //check sum TWE.write('X'); previous = val; }
キャラ型の数字を扱いやすくするため配列“hexer”を用意します。
const char hexer [16] = {‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’}
ここに数字を投げ込めばキャラ型に変換できます。このやり口はTWE-LITEでデータをやり取りするには便利だと思うので、覚えておくといいかなと思います。
変数“previous”には前回のピン状態を仕込みます。そしてビット演算子で差分があるビットを有効にします。演算子“ ^ ” も今回のような例では有用です。
TWE.write(hexer[(val ^ previous) & B00001111]);
まとめ:Digital 4ピンの移動点灯
以上を踏まえ4つのデジタルピンに点灯消灯の動きをつけたスケッチを書きます。
ここでは端折ってしまいましたが、アナログに関しても関数をいじれば操作できると思うので、興味がある方は試してみてはいかがでしょうか。
#include <SoftwareSerial.h> SoftwareSerial TWE(5, 6); // RX, TX void setup() { TWE.begin(38400); } void loop() { static unsigned long intval = millis(); static byte d_pin; static byte times; if ((millis() - intval) >= 1000) { bool reverse = (times > 3) ? 0 : 1; d_pin = ((d_pin << 1) + reverse); TWE_PIN_SEND(d_pin); intval = millis(); times++; if (times >= 8) times = 0; } } void TWE_PIN_SEND(byte val) { const char hexer [16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; const byte hdata [6] = {7, 8, 8, 0, 0, 1}; static byte previous = 0x00001111; //send header data TWE.write(':'); for (byte i = 0 ; i < 6 ; i++) TWE.write(hexer[hdata[i]]); val &= B00001111; //--send pin status--// //Main //send higher 4 bits TWE.write(hexer[0]); //send lower 4 bits TWE.write(hexer[val]); //Mask //send higher 4 bits TWE.write(hexer[0]); //send lower 4 bits TWE.write(hexer[(val ^ previous) & B00001111]); //send analog pin data (all 'F') for (byte i = 0 ; i < 16 ; i++) TWE.write(hexer[15]); //check sum TWE.write('X'); previous = val; }