/* * 参考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 * * [button_push for wcs_button のバージョン履歴] * v00.01.02 2017/08/10 シリアル通信の相手(Windowsなど)からLED出力ピンのON/OFF状態を得て、出力状態を変更できるようにした。 * 相手から受信するデータは、ヘッダが'H'1バイトで、それに続いてピン番号int2バイトを送信。 * ON/OFF状態は数値の正負で表現し、ONは正数、OFFは負数とした。 * v00.01.01 2017/07/30 初版 */ #define MAYBE_STABLE 1000 // Arduino UNOで実測した限りではループでのctが5000くらいだったのでそれより小さい値として1000くらいにした #define SW_NUM 3 // pin監視するスイッチの数 const int buttonON = LOW; // ボタンが押されているとピンの値はLOW const int buttonOFF = HIGH; // ボタンが押されていないとピンの値はHIGH //const int buttonPin = 7; const int global_led_pin = 13; boolean sw_status_arr[SW_NUM] = {false,false,false}; // 最初はOFF const int btn_pin_arr[SW_NUM] = {5, 6, 7}; const int led_pin_arr[SW_NUM] = {8, 9, 10}; //const int led_pin_arr[SW_NUM] = {13, 13, 13}; boolean hold_status_before_push_on=false; // シリアル側からONの指示があった時、ボタンのプッシュ状態を見て、すぐにクリアしてしまうことがないように、通信相手の状態を優先としtrueがセットされます、ArduinoでプッシュボタンをONした時にはfalseをセットして優先権をArduinoに戻します。 void setup() { // Arduinoの標準設定は、デフォルトは8bit、パリティなし、1ストップビット(SERIAL_8N1),通信相手も同じ条件にすること Serial.begin(9600); pinMode(global_led_pin, OUTPUT); for ( int i=0; i < SW_NUM; i++ ) { pinMode(btn_pin_arr[i], INPUT_PULLUP); pinMode(led_pin_arr[i], OUTPUT); } } void serial_send_status(int rec_pin, boolean status) { Serial.print(rec_pin); if ( status ) { // シリアル Serial.println(",on"); } else { Serial.println(",off"); } } void detect_remote_button() { // Windows側からピンを制御,受信バッファに3バイト(ヘッダ'H'1バイト+int2バイト)以上のデータが到着しているか確認 if ( Serial.available() >= sizeof('H') + sizeof(int) ) { // ヘッダの確認 if ( Serial.read() == 'H' ) { int low = Serial.read(); // 下位バイトの読み取り int high = Serial.read(); // 上位バイトの読み取り int rec_pin = makeWord(high,low); // 上位バイトと下位バイトを合体させてint型データを復元 boolean status =false; if (rec_pin> 0 ){ status=true; }else{ status=false; rec_pin=-rec_pin; } for ( int i=0; i < SW_NUM; i++ ) { if( led_pin_arr[i]==rec_pin){ sw_status_arr[i]=status; hold_status_before_push_on=true; int btn_pin=btn_pin_arr[i]; // LEDピンのインデックス番号からプッシュボタンの入力ピンを求める serial_send_status(btn_pin,status); break; } } } } } void loop(){ for ( int i=0; i < SW_NUM; i++ ) { detect_button(i); } detect_remote_button(); } 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 = 0; // on状態の変化を検出 buttonState = digitalRead(btn_pin); 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]; } 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 ( detect_changed ) { serial_send_status(btn_pin,status); } if ( hold_status_before_push_on ) { buttonState =sw_status_arr[idx]? buttonON:buttonOFF; // ボタンが押されている、押されていない時のピンの状態にする(INPUT_PULLUP指定しているので定義値をセット) } if (buttonState == buttonON) { // ボタンが押されていたら digitalWrite(led_pin, HIGH); digitalWrite(global_led_pin, HIGH); } else { digitalWrite(led_pin, LOW); digitalWrite(global_led_pin, LOW); } sw_status_arr[idx]=status; return buttonState; }