/* * 参考URL * * 意外と知られていない?INPUT_PULLUP スイッチサイエンス マガジン * http://mag.switch-science.com/2013/05/23/input_pullup/ * * Arduinoで物理ボタンを作る (目立つボタンで「ッターーン!」しよう) * http://qiita.com/ie4/items/7c6764469f3d41c93a19 * * Arduinoのスケッチだけでスイッチのチャタリングを回避する * http://jumbleat.com/2016/08/19/switch_without_chatter/ * * 続・プログラミングでチャタリング回避 * http://jumbleat.com/2016/12/01/revision_of_avoiding_chatter/ * * Windows->ArduinoへのピンをON/OFFする情報連携は、バイト数を極力抑えたいため、ピン番号をintでWindowsから連携する際に、ONの時に正数、OFFの時に負数を与えることとしました。 * int情報をシリアル通信で送信する方法は以下の記事を参考にしました * http://d.hatena.ne.jp/kougaku-navi/20140501/p1 * * ESPDUINO-32(ESP32)でBluetooth SPPを使ってWindows10とCOMポート通信。Win7は接続できるところまで確認できた、Windows8.1はCOMポートが生成されないので利用できていない。以下のサイトが参考になった。 * https://techtutorialsx.com/2018/03/09/esp32-arduino-serial-communication-over-bluetoth-hello-world/ * * button_pushそのものには関係ないのですが、Leonardo対応のキーボード入力テストで使った * 「Keyboard_jp.h」は以下のサイトからダウンロードしました。 * Arduino Leonardoで\記号を打つ * https://mgt.blog.so-net.ne.jp/2016-01-14 * C:\Program Files (x86)\Arduino\libraries\Keyboard_jpなどのディレクトリを作成し、そこにKeyboard_jp.h/Keyboard_jp.cppをコピーします。 * * [プッシュボタンシステムの動作モード] * (1)プッシュボタンのON/OFF情報をWindowsアプリに送信するだけのスタンドアローンモード * (2)(1)に加えてWindowsアプリからリモート操作(ソフト入力、LED出力)ができるリモート操作モード * 電源を入れた時に、プッシュボタンを押していなければ(1)スタンドアローンモードで起動します。 * 電源を入れた時に、プッシュボタンのうちどれか1つを押しっぱなしにすると(2)リモート操作モードで起動します。 * プッシュボタンが押されているかどうかの判定時間は0.5秒です。 * * [button_push for wcs_button のバージョン履歴] * v00.01.06 2018/08/20 ArduinoProMicro用の調整(1ボタン用に配列を変更,6ボタン用のままだったため1プッシュが6プッシュになっていたのを修正) * v00.01.05 2018/06/03-08/08 ESPDUINO-32(ESP-WROOM-32)に対応、Bluetooth SPPに対応、ESP32の入出力pinは、入力ピンは12,13,5,23,19,18/出力ピンは26,25,17,16,27,14としました。互換性を維持するため、Windows側wcs_buttonからの制御pinはそのままで該当位置のpinになるよう変換を行うようにしました。 * ArduinoProMicro(Leonardo)に対応、実験的コードでキーボード入力を実装、wcs_button用には不要な機能なので、実験です。Leonardoをwcs_button用のプッシュボタン入力ボードとして利用する場合はUSB接続時にプッシュボタンを押したまま起動してください。 * MAYBE_STABLEの値はESP32は変更した方がよいかもしれないが、本バージョンリリース時点では変更していない。 * ProMicro(leonardo)の場合は、Windows側アプリにおいて、DTR/RTSを必ず有効にする必要があります。wcs_button v00.01.08以降を使ってください。 * Sコマンドにパラメータ9,10を追加しました。 * マイコンの設定値/ピンの値を取得できるコマンド"G"を追加しました。現時点の主な目的はマイコンボードのバージョンをチェックすることです(ピン番号"-1"を連携すれば取得できます)。 * v00.01.04 2017/11/18 フットスイッチに対応、フットスイッチは、LED出力のためピン出力を行う必要がないので、入力ピンの情報だけをPCにできる変数is_foot_switchを追加、デフォルトでtrueとしました。 * ボタンpin、LED出力pinをそれぞれ6個に拡張、入力ピンは8,9,10,11,12,13/出力ピンは2,3,4,5,6,7に変更した。 * v00.01.03 2017/08/12 LEDの出力レベルを負論理にできるようにした(デフォルトは正論理)。led_output_negativeをシリアルから受信コマンドS+0x0001[正論理]/S+0x0002[負論理]で制御できるようにした。 * v00.01.02 2017/08/10 シリアル通信の相手(Windowsなど)からLED出力ピンのON/OFF状態を得て、出力状態を変更できるようにした。 * 相手から受信するデータは、ヘッダが'H'1バイトで、それに続いてピン番号int2バイトを送信。 * ON/OFF状態は数値の正負で表現し、ONは正数、OFFは負数とした。 * v00.01.01 2017/07/30 初版 * * [ピンの値に変化があったらシリアル送信] * シリアルに連携する形式は以下です * ピン番号,onまたはoff * (例) * (1)8番ピンがon * 8,on * (2)8番ピンがoff * 8,off * ボタンのon/offを検知した時点で速やかにシリアルに連携します。配列btn_pin_arrの定義順にon/off状態をチェックしていき、今回の状態が前回と異なっている時に今回の状態を連携します。 * * [マイコンの設定値/ピンの値を取得] * マイコンの設定値/ピンの値を取得します。識別文字'G'+2バイト整数で表現(G:Getの略) * 値は-32768から32767 * 正数:2~32767はピンの現在値を返します(現時点では設定のみなのでon/offを返します) * 負数:-32768~-1はプログラムの各種設定値を返します。 * * 0,1に対しては応答しません。 * 負数の場合は、マイコンの設定値を「"v"+","+値+CR+LF」形式で返します。 * 例えば、スケッチのバージョンを得る場合は、ピン番号に-1を指定すると、以下の文字列が返って来ます。 * v,SKETCH_VERSION:00.01.05;CREATION_DATE:2018-06-14 * v,の後ろに文字列を連結 * 項目名(英数記号[a-zA-Z0-9+-_]を想定)+":"+値(項目名、値にはコロン、セミコロンは使えない) * 複数項目がある場合はコロン";"を付けて続けて返す * * <<< マイコン設定値を取得するピン番号一覧 >>> * -1:プログラムのバージョンを返します * (例)v,SKETCH_VERSION:00.01.05;CREATION_DATE:2018-06-16 * * [マイコンの設定値を変更] * シリアル側からマイコンの設定値を変更できる項目、識別文字'S'1バイト+2バイト整数で表現(S:Setの略) * 2バイト整数は以下の通り * ピン単位に正負論理を設定できるようにした方がよいのかわからない、今のところ未定、未実装 * 以下の設定はリモート制御を禁止していてもできるようにしています。 * 0x0000: * 0x0001:出力を正論理にする(初期値は正論理) * 0x0002:出力を負論理にする * 0x0003:リモート制御を許可 * 0x0004:リモート制御を禁止 * 0x0005:リモート制御の時に物理スイッチのpin監視を行う * 0x0006:リモート制御の時に物理スイッチのpin監視を行わない * 0x0007:ボタン入力pin+LED出力pinを連携 * 0x0008:ボタン入力pinのみを連携(フットスイッチ用を想定) * 0x0009:ESP-WROOM-32、SERIAL+SPPの接続を許可(制御はBluetooth SPPのみ) * 0x000A:ESP-WROOM-32、SPPのみ接続を許可 * 0x000B: * 0x000C: * 0x000D: * 0x000E: * 0x000F: */ #ifdef ARDUINO_AVR_LEONARDO //#include "Keyboard.h" #include "Keyboard_jp.h" #else #endif #ifdef ARDUINO_ESP32_DEV #include "BluetoothSerial.h" #if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it #endif BluetoothSerial SerialBT; #endif // 定義文字列にはコロン「:」、セミコロン「;」は入れないこと、設定情報をシリアルで返す時に区切り文字で使っているため #define SKETCH_VERSION "v00.01.06" // バージョン番号 #define CREATION_DATE "2018-08-20" // リリース日 #define MAYBE_STABLE 1000 // Arduino UNOで実測した限りではループでのctが5000くらいだったのでそれより小さい値として1000くらいにした #define SERIAL_SPEED 115200 // シリアル通信速度(4800,9600,19200,38400,57600,74880,115200,230400) unsigned long exec_start_time=0; // 計測を開始した時間 #define EXEC_SPAN_MILLISE 1000 // モードセットを識別する時間(ミリ秒) #define EXEC_SPAN_LED_ON 500 // リモート操作を認識した直後にLEDを光らせる時間(ミリ秒) const int buttonON = LOW; // ボタンが押されているとピンの値はLOW(PULL UP) const int buttonOFF = HIGH; // ボタンが離されたれるとピンの値はHIGH(PULL UP) boolean led_output_negative = false; // LEDの出力レベルを負論理にする、true:ボタンが押されると出力をLOW,false:ボタンが離されたれると出力をHIGH(既定値) boolean enable_remote_control = true; // リモート制御の可否、true:許可(既定値:現時点では)、false:禁止(将来はこちらにする予定) // Leonardoのキーボード機能をテストする場合のみtrue,wcs_button用では常にfalse boolean enable_hid=false; // leonardoの場合、ボタンを押しっぱなしで起動した時だけ有効にする,falseにするとUNOと同様のプッシュボタン送信装置として動作 #define LEONARDO_TST 1 int pattern_no = 0; boolean enable_spp=true; // ESP-WROOM-32の場合はBluetoosh sppを有効(serialは無効化)、ボタンを押しっぱなしで起動した時だけ無効にする boolean enable_both=true; // SERIALとSPPでの接続を許可する場合 boolean polling_physical_btn = true; // 物理スイッチのpin監視を行うかどうか、true:行う(既定値)、false:行わない // ESP32ボードは複数種類あるので、必要に応じて変更してください。以下のポートはESPDUINO-32の場合です。 #ifdef ARDUINO_ESP32_DEV #define SW_NUM 6 // pin監視するスイッチの数 #define LED_NUM 6 // 出力するポートの数 boolean sw_status_arr[SW_NUM] = {false,false,false,false,false,false};// 最初はOFF const int btn_pin_arr[SW_NUM] = {12,13,5,23,19,18}; const int led_pin_arr[LED_NUM] = {26,25,17,16,27,14}; const int conv_btn_arr[SW_NUM] = {8,9,10,11,12,13}; const int conv_led_arr[LED_NUM] = {2,3,4,5,6,7}; boolean btn_init_status[SW_NUM] = {true, true, true,true,true,true}; // 起動ときに動作モードを識別するため、buttonOFFを検出したらfalse boolean led_status_arr[LED_NUM] = {false,false,false,false,false,false}; // 最初はOFF #elif ARDUINO_AVR_LEONARDO #define SW_NUM 1 // pin監視するスイッチの数 #define LED_NUM 1 // 出力するポートの数 boolean sw_status_arr[SW_NUM] = {false}; // 最初はOFF const int btn_pin_arr[SW_NUM] = {8}; const int led_pin_arr[LED_NUM] = {2}; const int conv_btn_arr[SW_NUM] = {13}; const int conv_led_arr[LED_NUM] = {2}; boolean btn_init_status[SW_NUM] = {true}; // 起動ときに動作モードを識別するため、buttonOFFを検出したらfalse boolean led_status_arr[LED_NUM] = {false}; // 最初はOFF #else #define SW_NUM 6 // pin監視するスイッチの数 #define LED_NUM 6 // 出力するポートの数 boolean sw_status_arr[SW_NUM] = {false,false,false,false,false,false};// 最初はOFF const int btn_pin_arr[SW_NUM] = {8,9,10,11,12,13}; const int led_pin_arr[LED_NUM] = {2,3,4,5,6,7}; // 先頭の3個はbtn_pin_arrの出力を反映するためのポートです11,12,13は自由に設定可能 const int conv_btn_arr[SW_NUM] = {8,9,10,11,12,13}; // 0は評価しない、該当の番号を受けたら同じインデックスにあるbtn_pin_arrの番号が入力されたものとして扱います const int conv_led_arr[LED_NUM] = {2,3,4,5,6,7}; // 0は評価しない、該当の番号を受けたら同じインデックスにあるbtn_pin_arrの番号が入力されたものとして扱います boolean btn_init_status[SW_NUM] = {true, true, true,true,true,true}; // 起動ときに動作モードを識別するため、buttonOFFを検出したらfalse boolean led_status_arr[LED_NUM] = {false,false,false,false,false,false}; // 最初はOFF #endif boolean hold_status_before_push_on=false; // シリアル側からONの指示があった時、ボタンのプッシュ状態を見て、すぐにクリアしてしまうことがないように、通信相手の状態を優先としtrueがセットされます、ArduinoでプッシュボタンをONした時にはfalseをセットして優先権をArduinoに戻します。 boolean is_foot_switch=true; // trueにすると入力ボタンのピン情報のみを返し、LED出力ピンの情報を返しません。フットスイッチを使ったり、ボタン入力だけを連携したい時にtrueにします。falseにすると、入力ピンの情報に加えて、対応するLED出力ピンの情報も連携します void setup() { // ピン状態をリセット for ( int i=0; i < SW_NUM; i++ ) { pinMode(btn_pin_arr[i], INPUT_PULLUP); } for ( int i=0; i < LED_NUM; i++ ) { pinMode(led_pin_arr[i], OUTPUT); } // 起動直後に動作モードを認識 exec_start_time= millis(); while ( exec_start_time+EXEC_SPAN_MILLISE>millis() ){ for ( int i=0; i < SW_NUM; i++ ) { if(!btn_init_status[i])continue; if(buttonOFF==digitalRead(btn_pin_arr[i])){ btn_init_status[i]=false; } } } // 起動直後に押しっぱなしのボタンが1個でもあったらリモート制御を許可して起動します for ( int i=0; i < SW_NUM; i++ ) { if(btn_init_status[i]){ // リモート制御を許可して起動する場合は、SPAN_LED_ONミリ秒間すべてのLEDを点灯して消灯します。ボタンが1個しかない場合はわからないですが。 enable_hid=true; // leonardoの場合はhidを有効にする(2018/08/20,無効->有効に変更) enable_spp=false; // ESP-WROOM-32の場合はBluetooth SPPを無効にする enable_remote_control=true; exec_start_time= millis(); while ( exec_start_time+EXEC_SPAN_LED_ON>millis() ){ for ( int j=0; j < LED_NUM; j++ ) { // 点灯 digitalWrite(led_pin_arr[j], (led_output_negative? LOW:HIGH)); } } for ( int j=0; j < LED_NUM; j++ ) { // 点灯消灯 digitalWrite(led_pin_arr[j], (led_output_negative? HIGH:LOW)); } break; } } #ifdef ARDUINO_AVR_LEONARDO if(enable_hid){ //キーボードとして動作 Keyboard.begin(); return; } #else enable_hid=false;//leonardo以外はfalseにする #endif #ifdef ARDUINO_ESP32_DEV if(enable_spp){ //Bluetoothで接続 SerialBT.begin("wcs_button"); if(enable_both){ // btと同時にシリアル接続も許可する時 }else{ return; } } #else enable_spp=false;//ESP32以外はfalseにする #endif // Arduinoの標準設定は、デフォルトは8bit、パリティなし、1ストップビット(SERIAL_8N1),通信相手も同じ条件にすること Serial.begin(SERIAL_SPEED,SERIAL_8N1); } #ifdef ARDUINO_AVR_LEONARDO void hello_0() { Keyboard.write('y'); Keyboard.write('a');//Keyboard.write(KEY_RETURN); Keyboard.write('x'); Keyboard.write('a');//Keyboard.write(KEY_RETURN); Keyboard.write('!'); } void hello_1() { Keyboard.write('k'); Keyboard.write('o');//Keyboard.write(KEY_RETURN); Keyboard.write('n'); Keyboard.write('n');//Keyboard.write(KEY_RETURN); Keyboard.write('n'); Keyboard.write('i');//Keyboard.write(KEY_RETURN); Keyboard.write('t'); Keyboard.write('i');//Keyboard.write(KEY_RETURN); Keyboard.write('h'); Keyboard.write('a');//Keyboard.write(KEY_RETURN); } int hello_leonardo(int no) { Keyboard.press(KEY_LEFT_ALT); Keyboard.press(KEY_KANJI); Keyboard.releaseAll(); switch(no){ case 0: hello_0(); break; case 1: hello_1(); break; default: hello_0(); break; } Keyboard.write(KEY_RETURN); Keyboard.write(KEY_RETURN); Keyboard.press(KEY_LEFT_ALT); Keyboard.press(KEY_KANJI); Keyboard.releaseAll(); delay(250); no++; if(no>1)no=0; return no; } #endif // マイコンボードの実ピン番号を受信ピン番号にする,非0のピン番号が対象 int real2inp_pin(int rec_pin) { boolean found=false; if(!found){ // 入力ボタンの実ピン番号を変換する for ( int i=0; i < SW_NUM; i++ ) { if(btn_pin_arr[i]==rec_pin){ rec_pin=conv_btn_arr[i]; found=true; break; } } } if(!found){ // 出力LEDの実ピン番号を変換する for ( int i=0; i < LED_NUM; i++ ) { if(led_pin_arr[i]==rec_pin){ rec_pin=conv_led_arr[i]; found=true; break; } } } return rec_pin; } // 受信ピン番号をマイコンボードの実ピン番号にする,非0のピン番号が対象 int inp2real_pin(int rec_pin) { boolean found=false; if(!found){ // 入力ボタンのピン番号なら変換する for ( int i=0; i < SW_NUM; i++ ) { if(conv_btn_arr[i]==rec_pin){ rec_pin=btn_pin_arr[i]; found=true; break; } } } if(!found){ // 出力LEDのピン番号なら変換する for ( int i=0; i < LED_NUM; i++ ) { if(conv_led_arr[i]==rec_pin){ rec_pin=led_pin_arr[i]; found=true; break; } } } return rec_pin; } void serial_send_status(int rec_pin, boolean status) { // マイコンボードの実ピン番号を変換番号にする,非0のピン番号が対象 if(rec_pin>0){ rec_pin=real2inp_pin(rec_pin); } #ifdef ARDUINO_ESP32_DEV if(enable_spp){ if(rec_pin>0){ SerialBT.print(rec_pin); if ( status ) { // シリアル SerialBT.println(",on"); } else { SerialBT.println(",off"); } } if(enable_both){ // btと同時にシリアル接続も許可する時 }else{ return; } } #endif #if LEONARDO_TST&&ARDUINO_AVR_LEONARDO if(enable_hid&&rec_pin==13){ if(status){ pattern_no = hello_leonardo(pattern_no); if(false){ Keyboard.press(KEY_LEFT_SHIFT); Keyboard.press(KEY_END); Keyboard.press(KEY_DELETE); delay(300); Keyboard.releaseAll(); } } return; } #endif if(rec_pin>0){ Serial.print(rec_pin); if ( status ) { // シリアル Serial.println(",on"); } else { Serial.println(",off"); } } } /* void serial_send_status2(int rec_pin, boolean status) { int org_pin=rec_pin; // マイコンボードの実ピン番号を変換番号にする,非0のピン番号が対象 if(rec_pin>0){ rec_pin=real2inp_pin(rec_pin); } if(rec_pin>0){ Serial.print(org_pin); Serial.print("=>"); Serial.print(rec_pin); if ( status ) { // シリアル Serial.println(",on"); } else { Serial.println(",off"); } } } */ // バージョン文字列と作成日を返す // 一番最後にSerial.println()を使って改行する void send_version() { #ifdef ARDUINO_ESP32_DEV if(enable_spp){ SerialBT.print("v,");SerialBT.print("SKETCH_VERSION:");SerialBT.print(SKETCH_VERSION); SerialBT.print(";");SerialBT.print("CREATION_DATE:");SerialBT.println(CREATION_DATE); if(enable_both){ // btと同時にシリアル接続も許可する時はSerial.print()で送信したいのでスルー }else{ return; } } #endif Serial.print("v,");Serial.print("SKETCH_VERSION:");Serial.print(SKETCH_VERSION); Serial.print(";");Serial.print("CREATION_DATE:");Serial.println(CREATION_DATE); } /* * Windows側からのコマンド文字列については、enable_sppの場合はenable_bothがtrueであってもsppのみを取得しシリアルからの情報は破棄します * enable_bothの目的はsppに加えてシリアルにもピンの状態を連携する */ void detect_remote_button() { // Windows側からピンを制御,受信バッファに3バイト以上のデータが到着しているか確認 // 動作情報設定は、ヘッダ'S'1バイト+int2バイト=3バイト(数値の意味はコマンド表を参照、とりあえず必要そうなものから実装) // ピン情報設定は、ヘッダ'H'1バイト+int2バイト=3バイト // ピン情報取得は、ヘッダ'G'1バイト+int2バイト=3バイト int sum=0; #ifdef ARDUINO_ESP32_DEV if(enable_spp){ sum=SerialBT.available(); if(enable_both){ // sppのみを取得するのでシリアル情報は破棄します while(Serial.available()>0){ Serial.read(); } } }else{ sum=Serial.available(); } #else sum=Serial.available(); #endif if (sum>=3) { // ESP32ではsizeof(word)=4になるので「Serial.available() >= sizeof('H') + sizeof(word)」からバイト数埋め込みに変更 // ヘッダの確認 #ifdef ARDUINO_ESP32_DEV int header=enable_spp? SerialBT.read():Serial.read(); #else int header= Serial.read(); #endif if ( header == 'G' || header == 'H' || header == 'S' ) { #ifdef ARDUINO_ESP32_DEV byte low = enable_spp? SerialBT.read():Serial.read(); // 下位バイトの読み取り byte high = enable_spp? SerialBT.read():Serial.read(); // 上位バイトの読み取り #else byte low = Serial.read(); // 下位バイトの読み取り byte high = Serial.read(); // 上位バイトの読み取り #endif int rec_pin=makeWord(high,low); // 上位バイトと下位バイトを合体させてint型データを復元,Arduinoでは-32768-32767 int mask=(1<<15);//1000 0000 0000 0000,16bitCPUだと-32768 if(false){ Serial.print("rec_pin:");Serial.println(rec_pin);Serial.print("mask:");Serial.print(mask);Serial.print(",");Serial.println(((rec_pin&mask)>>15)&1);//0 or -1 } // 16ビット目に1がセットされておれば負数表現が入っているので、rec_pinからCPUのint型における負数を復元する if((((rec_pin&mask)>>15)&1)==1){ // 0 or 1,1なら16ビット目に1がセットされていて負数であることがわかる rec_pin|=(~0<<16);// 下位16ビットを除き全ての上位ビットに1をセットする,これで各CPUのint型における負数が求まる //Serial.println(rec_pin); } if(false){ Serial.print(sizeof(word));Serial.print(",0:");Serial.print(~0<<16);Serial.print(",1:");Serial.print(header);Serial.print(",2:");Serial.print(low);Serial.print(",3:");Serial.print(high);Serial.print(",rec_pin:");Serial.println(rec_pin); } if (header=='S') { // rec_pinの値を見て設定を実施 if (rec_pin==1){ // 1:出力を正論理 led_output_negative = false; } else if(rec_pin==2) { // 2:出力を負論理 led_output_negative = true; } else if(rec_pin==3) { // 3:リモート制御を許可 enable_remote_control = true; } else if(rec_pin==4) { // 4:リモート制御を禁止 enable_remote_control = false; } else if(rec_pin==5) { // 5:物理スイッチのpin監視を行う polling_physical_btn = true; } else if(rec_pin==6) { // 6:物理スイッチのpin監視を行わない polling_physical_btn = false; } else if(rec_pin==7) { // 7:ボタン入力pin+LED出力pinを連携 is_foot_switch = false; } else if(rec_pin==8) { // 8:ボタン入力pinのみを連携(フットスイッチ用を想定) is_foot_switch = true; } else if(rec_pin==9) { // 9:ESP-WROOM-32、SERIAL+SPPの接続を許可(制御はBluetooth SPPのみ) enable_both = true; } else if(rec_pin==10) { // 10:ESP-WROOM-32、SPPのみ接続を許可 enable_both = false; } else { // 何もしない } } else if (header == 'G' ) { // header == 'G' // 正数はピンの値を読み取る、負数の場合は定義文字列を返します if(rec_pin>0){ // ピンの値を読み取る,変換リストに基づいて実ピン番号に変換して値を得ます // 受信ピン番号をマイコンボードの実ピン番号に変換する int real_pin=inp2real_pin(rec_pin); // LED出力、ボタン入力状態を正しく得るため、状態配列の値を返す // // ここまでで、受信ピン番号rec_pinはボードの実ピン番号real_pinに変換されている // boolean status=digitalRead(real_pin)==buttonON? true:false; // serial_send_status(real_pin,status); // 入力ボタンのピン番号の場合 for ( int i=0; i < SW_NUM; i++ ) { if(btn_pin_arr[i]==real_pin){ serial_send_status(real_pin,sw_status_arr[i]); break; } } // 出力LEDのピン番号の場合 for ( int i=0; i < LED_NUM; i++ ) { if(led_pin_arr[i]==real_pin){ serial_send_status(real_pin,led_status_arr[i]); break; } } }else if(rec_pin==-1){ // -1:バージョン+作成日 send_version(); }else { // 未定義 } } else if (header == 'H' ) { // header == 'H' // ピンを制御 if(enable_remote_control){ boolean status=false; if (rec_pin> 0 ){ status=true; }else{ //Serial.print(rec_pin); //Serial.println(",nc"); status=false; rec_pin=-rec_pin; } // 受信ピン番号をマイコンボードの実ピン番号に変換する if(rec_pin>0){ rec_pin=inp2real_pin(rec_pin); } // ここで、受信ピン番号rec_pinはボードの実ピン番号に変換されている // 入力ボタンのピン制御かどうかを確認する for ( int i=0; i < SW_NUM; i++ ) { if( btn_pin_arr[i]==rec_pin){ sw_status_arr[i]=status; hold_status_before_push_on=true; // 入力ピンは物理ボタンが押されるまではリモート設定された値を保持するのでtrueをセット //int btn_pin=btn_pin_arr[i]; // LEDピンのインデックス番号からプッシュボタンの入力ピンを求める //serial_send_status(btn_pin,status); led_status_arr[i]=status;// 出力ピンのステータスを変更する(リモート優先の時はsw_status_arr[i]がfalseでも対応する出力ピンled_status_arr[i]をfalseにしないので、リモートでfalseを受信したタイミングでled_status_arr[i]をfalseにします) serial_send_status(rec_pin,status); serial_send_status(led_pin_arr[i],status);// 出力ピンのステータスを変更したのでリモート側に通知 return; } } // 出力LEDのピン制御かどうかを確認する for ( int i=0; i < LED_NUM; i++ ) { if( led_pin_arr[i]==rec_pin){ led_status_arr[i]=status;// 出力ピンのステータスを変更する hold_status_before_push_on=true; // 出力ピンは物理ボタンが押されるまではリモート設定された値を保持するのでtrueをセット //int btn_pin=led_pin_arr[i]; // LEDピンのインデックス番号からプッシュボタンの入力ピンを求める //serial_send_status(btn_pin,status); serial_send_status(rec_pin,status);// 出力するLEDピン番号の変更後の状態値を返す if (status) { // 出力状態を変更 digitalWrite(rec_pin, (led_output_negative? LOW:HIGH)); // loopでまとめてset_output_voltageを実行させているのでコメントにしても大丈夫 } else { digitalWrite(rec_pin, (led_output_negative? HIGH:LOW)); // loopでまとめてset_output_voltageを実行させているのでコメントにしても大丈夫 } } } } } } } } void loop(){ for ( int i=0; i < SW_NUM; i++ ) { detect_button(i); } set_output_voltage(); detect_remote_button(); } void set_output_voltage(){ // if (hold_status_before_push_on) return; // リモート設定された値を保持する場合は個別設定しない(リモート設定の時はled_pin_arrもリモート制御しているので設定しても構いはしないが動作は不要なのでスキップさせている) for ( int i=0; i < LED_NUM; i++ ) { if ( led_status_arr[i] ) { digitalWrite(led_pin_arr[i], (led_output_negative? LOW:HIGH)); } else { digitalWrite(led_pin_arr[i], (led_output_negative? HIGH:LOW)); } } } int detect_button(int idx){ int btn_pin=btn_pin_arr[idx]; int led_pin=led_pin_arr[idx]; boolean status=sw_status_arr[idx]; unsigned long ct=0; boolean detect_changed = false; int buttonState = buttonOFF; // 物理スイッチのpin監視を行う機能を付けた時に0からbuttonOFFに変更した // on状態の変化を検出 buttonState = digitalRead(btn_pin); if (!polling_physical_btn){ // 物理スイッチのping監視を行わない場合は常にボタン状態はOFFにします buttonState=buttonOFF; } while (buttonState == buttonON) { if ( hold_status_before_push_on ){ hold_status_before_push_on=false; // 物理ボタンが押されたので、優先権をArduinoに戻します for ( int i=0; i < SW_NUM; i++ ) {// 全てのボタンをいったんクリアします sw_status_arr[i]=false; } status=sw_status_arr[idx]; } else { // Arduino優先の時は入力ボタンの情報変更はしない } ct++; if ( ct > MAYBE_STABLE ) { if ( ! status ) { status=!status; detect_changed=true; } else { // 既にON状態を識別済み } break; } buttonState = digitalRead(btn_pin); } // off状態の変化を検出 if ( ct == 0 ) { // buttonState = digitalRead(btn_pin);// on状態の変化を検出しようとした時に先に読み込んでいるのでここで再度の読み込みは不要,OFFを検出しています // Arduino側でoff状態の場合は、 if ( hold_status_before_push_on ) { // 後でLEDピンを変更する直前に変更します //buttonState=sw_status_arr[idx]? buttonON:buttonOFF; // ボタンが押されている、押されていない時のピンの状態にする(INPUT_PULLUP指定しているので要注意) } else { while (buttonState == buttonOFF) { ct++; if ( ct > MAYBE_STABLE ) { if ( status ) { status=!status; detect_changed=true; } else { // 既にOFF状態を識別済み } break; } buttonState = digitalRead(btn_pin); if (!polling_physical_btn){ // 物理スイッチのpin監視を行わない場合は常にボタン状態はOFFにします buttonState=buttonOFF; } } } } // シリアルでボタンの状態を通信相手に送信 if ( detect_changed ) { // ボタン入力ピンの情報を連携 serial_send_status(btn_pin,status); if ( is_foot_switch ) { // LED出力ピンの状態は連携しない } else { // LED出力ピンの状態を連携する serial_send_status(led_pin,status); } } if (0){ if ( hold_status_before_push_on ) { buttonState =sw_status_arr[idx]? buttonON:buttonOFF; // ボタンが押されている、押されていない時のピンの状態にする(INPUT_PULLUP指定しているので定義値をセット) } if (buttonState == buttonON) { // ボタンが押されていたら digitalWrite(led_pin, (led_output_negative? LOW:HIGH)); } else { digitalWrite(led_pin, (led_output_negative? HIGH:LOW)); } } if (polling_physical_btn){ // 物理スイッチを監視する場合のみ、ステータスを変更します // リモートモードで、物理スイッチの動作を禁止していない場合は、物理スイッチのONでリモートによる出力値を更新しないモードをクリアする、ちょうと、ソフトスイッチの処理のようなコードを書く、整理する必要あり sw_status_arr[idx]=status; // スイッチ状態がfalseでも、リモート操作中でled_status_arr[idx]がtrueの時はled_status_arr[idx]はtrueを保持します if ( ! sw_status_arr[idx] && hold_status_before_push_on && led_status_arr[idx] ) { // リモート操作中で、出力ピン状態がtrueの時は出力値を更新しない,物理スイッチはOFFだがリモートで出力ピンをONにしているので、ON状態を変更しない(リモート操作でスイッチをOFFにした時は、対応する出力ピンはその時にOFFにするようにしている) } else { // LEDピンの状態を更新,通信ポートに状態を送信するのは変化があった時だけなので、ここでは送信しない led_status_arr[idx]=status; // serial_send_status(led_pin_arr[idx],status); } } else { // 物理ボタンを監視しない場合は、何も変更しません。 } return buttonState; }