はじめに
テクノべインズで開発したスイッチセンサーを使用してWSD002A-J、LEDN41、レシートプリンタを操作してみました。今回はスイッチセンサーのご紹介とスイッチセンサーから機器を操作する方法についてご説明いたします。
スイッチセンサーとは
スイッチセンサーは、スイッチを押した時またはスイッチを押した状態から放した時に「スイッチデータ」(&から始まる文字列)をシリアル通信でコントローラ(マイコン、PC、サーバ等)に送信するスイッチです。「スイッチデータ」はスイッチの動作モードにより異なります。 例えば、スイッチの動作モードが 「P」 の場合、スイッチを押すと、「&P011」をコントローラに送信します。スイッチの動作モードが 「R」 の場合、スイッチを押した状態から放すと、「&R010」をコントローラに送信します。他には、スイッチを押す度にカウントアップ、カウントダウンデータを送信するモード、スイッチの押下状態を一定間隔でコントローラに送信するモードなどもあります。
スイッチセンサーはコマンドも装備しています。コマンドを使用してコントローラからスイッチセンサーの情報を取得、設定変更を行います。例えばスイッチの動作モードをBに変更したい場合、コントローラはコマンド「$M01B」をスイッチセンサーに送信します。正常に動作モードが変更されるとスイッチセンサーは応答文字列「#M」をコントローラに返します。
スイッチセンサーはマイコン、PC、サーバなど様々なコントローラと接続できるので、スイッチ動作と連動させたアプリケーションやシステムを構築することが可能です。
スイッチセンサーはシリアル通信でデータの送受信を行うので、スイッチセンサーに付属のセンサー通信モジュールをPCに接続、TeraTerm等のターミナルソフトで簡単にPCから動作確認を行うことができます。また、弊社のWindows PC用ユーティリティソフト「SendToSensor」をご利用いただくとコマンドの実行や各コマンドのヘルプも確認することができます。
スイッチセンサー利用例
スイッチセンサーの利用例として、スイッチセンサーとWi-Fiを内蔵するマイコンESP32-DevKitCをシリアル接続、スイッチセンサーからESP32経由で弊社製品を操作したいと思います。
使用したもの
やりたいこと
手順
スイッチセンサーとESP32を接続
まず、スイッチセンサーとESP32-DevKitCをシリアル接続します。4極オーディオジャック変換を使用します。 センサーのシリアルコネクタの仕様はこちらをご参照下さい。ESP32-DevKitCの IO16 をRX、IO17 をTXとします。スイッチセンサーのボーレートは 38400 固定です。
シリアル接続とスイッチセンサー初期設定
ESP32 Arduino のスケッチでは setup 関数内で Serial2 を利用して ESP32-DevKitC とスイッチセンサー間のシリアル通信を行います。デバッグ用は Serial を使用します。
// ESP32とスイッチセンサー間のシリアル設定 Serial2.begin(38400, SERIAL_8N1, 16, 17); // デバッグ用シリアル設定 Serial.begin(115200);
次にsetup 関数内でスイッチセンサーの初期設定 setSwitch を実行します。setSwitch では以下のコマンドを実行します。
- 接続要求コマンド $C
- 動作モード設定コマンド $M
- カウンタ最大値設定コマンド %X
全てのコマンドは必ず # (送信コマンドのアルファベット1文字)の応答文字列を受信します。例えば、$C コマンドに対する応答文字列は #C です。応答文字列を受信できない場合コマンドを再送します。
コマンド送信後、応答文字列を受信してコマンドの実行完了とします。ここでは、cstep変数を各コマンド実行完了フラグとして使用します。
// cstep 0 : 未接続、1 : 接続完了、2 : 動作モード設定完了、3 : カウンタ最大値設定完了 int cstep = 0; // コマンドに対する応答文字列を格納する配列 char revcmd[8];
// スイッチセンサー初期設定 void setSwitch() { // 接続要求コマンド $C 送信 Serial2.print("$C"); Serial.println("Send $C"); while(cstep != 3) { if(Serial2.available()) { memset(revcmd, 0, sizeof(revcmd)); // 応答文字列受信 for(int i = 0; i < sizeof(revcmd); i++) { revcmd[i] = Serial2.read(); } } if(cstep == 0) { if(strncmp(revcmd, "#C", 2) != 0) { // 接続要求コマンド $C 再送 Serial2.print("$C"); } else { // 接続完了 cstep = 1; Serial.println("#C"); } } if(cstep == 1) { if(strncmp(revcmd, "#M", 2) != 0) { // 動作モード設定コマンド送信 // 動作モード U の場合 $M01U // 動作モード P の場合 $M01P Serial2.print("$M01U"); } else { // 動作モード設定完了 cstep = 2; Serial.println("#M"); } } // 動作モードを U に設定した場合 カウンタ最大値を設定 if(cstep == 2) { if(strncmp(revcmd, "#X", 2) != 0) { // カウンタ最大値設定コマンド送信 // 最大値 9999 に設定 Serial2.print("%X019999"); } else { // カウンタ最大値設定完了 cstep = 3; Serial.println("#X"); } } } }
動作モード設定コマンドは、 動作モード P を設定する場合 $M01P を送信、動作モード U を設定する場合 $M01U を送信します。動作モード P, U はスイッチを押した時のスイッチデータが異なります。
- 動作モード P : スイッチを押すと コントローラは &P011 を受信
- 動作モード U : スイッチを押すと コントローラは &U010001を受信
スイッチを押す度に受信データの下4バイト部分はカウントアップ(&U010002, &U010003, &U010004,,,)
カウンタ最大値設定コマンドは、動作モードを U に設定した場合実行します。カウンタ最大値を 0001 から 9999 の間の数値で設定します。今回は最大値を 9999 に設定するため、コマンド %X019999 を送信します。
スイッチデータ受信と各機器の操作
スイッチを押すと、ESP32はスイッチデータ (& から始まる文字列)を受信します。ESP32は受信したスイッチデータをトリガーにして各機器へコマンドを送信します。スケッチの loop 関数内でスイッチデータを受信できるように実装します。ESP32 から各機器へコマンドを送信するために Arduinoのライブラリ WiFiClient ,HTTPClient を使用します。
#include <WiFi.h> #include <HTTPClient.h> WiFiClient wifiClient; HTTPClient http;
ESP32 の IPアドレスは 192.168.1.77 とします。サンプルプログラムはWi-Fi接続、エラー処理等は省略しています。正常系の動作で必要最小限の処理をご紹介します。
WSD002A-J にコマンドを送信する場合
setSwitch 関数内でスイッチセンサーの動作モードを P に設定します。スイッチが押されると ESP32は &P から始まる文字列を受信します。&P を受信すると ESP32 は HTTP で WSD002A-J に再生コマンドを送信します。WSD002A-J の IPアドレスは 192.168.1.197 とします。
if(Serial2.available()) {
memset(revcmd, 0, sizeof(revcmd));
// スイッチデータ受信
for(int i = 0; i < sizeof(revcmd); i++) {
revcmd[i] = Serial2.read();
}
// &P011 を受信
if(strncmp(revcmd, "&P", 2) == 0) {
// WSD002A-Jに再生コマンド送信
http.begin("http://192.168.1.197/play?notice=1");
int httpCode = http.GET();
http.end();
}
}
LEDN41 にコマンドを送信する場合
setSwitch 関数内でスイッチセンサーの動作モードを U に設定します。スイッチが押されると ESP32は &U から始まる文字列を受信します。&U を受信すると ESP32 は ソケット通信 で LEDN41 に表示コマンドを送信します。LEDN41の表示コマンド、IPアドレス、ポート番号は以下のとおり定義します。setup 関数内で WiFiClient を使用して、LEDN41 のIPアドレス、ポート番号に接続します。
char ledn41_cmd[8] = {0x1B, 0x30, 0x44, 0x30, 0x30, 0x30, 0x30, 0x0D}; IPAddress ledn41_ip(192, 168, 1, 199); uint16_t ledn41_port = 10001;
wifiClient.connect(ledn41_ip, ledn41_port);
&U から始まる文字列は4バイトのカウントアップデータも含むので、そのデータをLEDN41の表示コマンドに代入します。WiFiClient を使用してLEDN41に表示コマンドを送信します。
if(Serial2.available()) { memset(revcmd, 0, sizeof(revcmd)); // スイッチデータ受信 for(int i = 0; i < sizeof(revcmd); i++) { revcmd[i] = Serial2.read(); } // &U010001 を受信 if(strncmp(revcmd, "&U", 2) == 0) { // スイッチセンサーから受信したカウントデータをLEDN41のコマンドに代入 ledn41_cmd[3] = revcmd[4]; ledn41_cmd[4] = revcmd[5]; ledn41_cmd[5] = revcmd[6]; ledn41_cmd[6] = revcmd[7]; // LEDN41に表示コマンド送信 wifiClient.write(ledn41_cmd, sizeof(ledn41_cmd)); } }
レシートプリンタ にコマンドを送信する場合
LEDN41と同様の方法で操作します。レシートプリンタの印字コマンド、IPアドレス、ポート番号は以下のとおり定義します。setup 関数内で WiFiClient を使用して、レシートプリンタのIPアドレス、ポート番号に接続します。
char printer_cmd[20] = {0x1B, 0x40, 0x0D, 0x1B, 0x61, 0x01, 0x30, 0x30, 0x30, 0x30, 0x0A, 0x1B, 0x64, 0x05, 0x1D, 0x56, 0x01}; IPAddress printer_ip(192, 168, 1, 190); uint16_t printer_port = 9100;
wifiClient.connect(printer_ip, printer_port);
if(Serial2.available()) { memset(revcmd, 0, sizeof(revcmd)); // スイッチデータ受信 for(int i = 0; i < sizeof(revcmd); i++) { revcmd[i] = Serial2.read(); } // &U010001 を受信 if(strncmp(revcmd, "&U", 2) == 0) { // スイッチセンサーから受信したカウントデータをレシートプリンタのコマンドに代入 printer_cmd[3] = revcmd[4]; printer_cmd[4] = revcmd[5]; printer_cmd[5] = revcmd[6]; printer_cmd[6] = revcmd[7]; // レシートプリンタに印字コマンド送信 wifiClient.write(printer_cmd, sizeof(printer_cmd)); } }
最後に
今回はスイッチセンサーとその使用例についてご紹介いたしました。スイッチセンサーはスイッチを押すとシリアル通信でデータを送信するだけのシンプルなモジュールですが、今回のようにWi-Fiを内蔵するマイコンと組み合わせることで、スイッチから無線で機器を操作することができます。また機器の操作だけでなく、例えばスイッチデータを外部サーバ上にアップして、スイッチのカウント情報などを利用したアプリケーションを開発することも可能です。昨今はタブレットやスマートフォンなどの画面上のボタンを使用することも多いようですが、ある機能に特化した物理ボタンが必要な場合、今回のスイッチセンサーがお役に立つかもしれません。