Arduinoタクトスイッチ Waitlessチャタリング回避プログラム
どこかのページで時間のかかる長いコードはチャタリングが発生しないと書いてあり頭の片隅にひっかかっていました。それならばイベントを発生させてから時間を伸ばしてみればいいのでは?ということでArduinoで待ちなしのチャタリング回避するスケッチを考えてみました。
通常のチャタリング回避とはボタンが押されてから30msほど待ってから、まだ押されている状態か判定してからコードを発砲します。(図の上段)今回はボタンが押されたら即発砲、ボタンをロックします。30ms後ボタンが状態が押されていなければロックを解除します。(図の下段)
const int buttonPin = 12; uint8_t addB; uint8_t lastB; int P = 0; int z = 0; boolean PushOk = true; boolean StateOk = true; unsigned long time1; long time2; long intrval_time; long wait = 0; uint8_t Bwait = 30;//発砲後の待ち Wait30ms PushOK30ms 60ms //uint8_t Bwait = 200;//Test用 400msの間 チャタリング無視する void setup() { pinMode(buttonPin, INPUT_PULLUP); Serial.begin(115200); } void loop() { addB = digitalRead (buttonPin); if((addB != lastB) && (PushOk == true)){ //High:HIGH(LOW)> HIGH:LOW(LOW) if((lastB == HIGH)&&(addB == LOW)&&(PushOk == true)&&(StateOk == true)){ time1 = millis(); } //High:HIGH(LOW)> HIGH:LOW(LOW) lastB = addB; } else { //LOW:LOW if((millis() - time1 >= 0) && (millis() - time1 <= 1) && (addB == LOW )&& (StateOk == true)){ StateOk = false;//LOCK PushOk = false;//LOCK z=1; /*------短押しの処理---------*/ P ++; Serial.print("Count::"); Serial.print( P ); intrval_time = millis() - time2; time2 = millis(); Serial.print(" Pushed Interval::"); Serial.println( intrval_time ); /*------短押しの処理---------*/ } /*-----長押しされたときの待ち時間のばし-----*/ if((millis() - time1 >= (Bwait*z)-(Bwait-1)) && (millis() - time1 <= Bwait*z) && (addB == LOW )){ wait = millis() - time1; wait = wait + Bwait -1; z++; Serial.print("WaitTime::"); Serial.println(wait); } /*------Waitより+BwaitでPushOk 解除-----------------*/ if ((millis()-time1 > wait + Bwait - 1) && (PushOk == false)){ PushOk = true;//60ms後にボタン検知を可能にする Serial.print("PushOkTime::"); Serial.println(millis() - time1); } /*------HIGH+HIGH-初期化----------------*/ if ((addB == HIGH) && (lastB == HIGH )&& (PushOk == true)){ StateOk = true; z=0; wait = 0; } } }
最初にストップウォッチのチャタリング回避を探してみましたが見つからずそれならばと作ってみました。そのせいでチャタリング回避プログラムと関係ないtimeが多々ありますが、チャタリング回避はtime1で測っています。
通常のタクトスイッチでは必要ないかも知れませんが、MIDIプログラムなどでは音切れ防止になるかもしれません
必要な回路はタクトスイッチを12pinと2つ横のGNDにさしてください。pullupしていますので抵抗はいらずの手抜き回路です。
長押し追加バージョン
const int ledPin1 = 13; const int buttonPin = 12; boolean led = 1; uint8_t addB; uint8_t lastB; int P = 0; long z = 0;//int 長押しのリミットあり boolean PushOk = true; boolean StateOk = true; unsigned long time1; unsigned long time2; unsigned int intrval_time;//int 長押しのリミットあり unsigned int wait = 0;//int 長押しのリミットあり uint8_t Bwait = 25;//発砲後の待ち Wait25ms PushOK30ms 50ms //uint8_t Bwait = 200;//Test用 400msの間 チャタリング無視する void setup() { pinMode(buttonPin, INPUT_PULLUP); pinMode(ledPin1, OUTPUT); Serial.begin(115200); } void loop() { addB = digitalRead (buttonPin); if((addB != lastB) && (PushOk == true)){ //High:HIGH(LOW)> HIGH:LOW(LOW) if((lastB == HIGH)&&(addB == LOW)&&(PushOk == true)&&(StateOk == true)){ time1 = millis(); } //High:HIGH(LOW)> HIGH:LOW(LOW) lastB = addB; } else { //LOW:LOW if((millis() - time1 >= 0) && (millis() - time1 <= 1) && (addB == LOW )&& (StateOk == true)){ StateOk = false;//LOCK PushOk = false;//LOCK z=1; /*------短押しの処理---------*/ P ++; Serial.print("Count::"); Serial.print( P ); intrval_time = millis() - time2; time2 = millis(); Serial.print(" Pushed Interval::"); Serial.println( intrval_time ); /*------短押しの処理---------*/ } /*-----長押しされたときの待ち時間のばし-----*/ if((millis() - time1 >= (Bwait*z)-(Bwait-1)) && (millis() - time1 <= Bwait*z) && (addB == LOW )){ wait = millis() - time1; wait = wait + Bwait -1; z++; //Serial.print("WaitTime::"); //Serial.println(wait); /*-------長押し繰り返し長押処理---2秒-------*/ if (z%80==0){ Serial.print ("long pushed led::"); led = !led; Serial.println (led); digitalWrite(ledPin1, led); } } /*------Waitより+BwaitでPushOk 解除-----*/ if ((millis()-time1 > wait + Bwait - 1) && (PushOk == false)){ PushOk = true;//60ms後にボタン検知を可能にする Serial.print("PushOkTime::"); Serial.println(millis() - time1); } /*------HIGH+HIGH-初期化----------------*/ if ((lastB == HIGH) && (addB == HIGH )&& (PushOk == true)){ StateOk = true; z=0; wait = 0; } } }