割り込みでボタン押下を数える
CoddyのArduinoジャーニー「delayを使わないタイミング制御」セクションの一部。レッスン 15/18。
Inputs セクションで見たように、ボタンはバウンスします。約1ミリ秒の間、接点が触れては離れ、また触れます。これは押したときにも、離したときにも起こります。割り込みは接点が触れるたびに検出するため、1を加算する FALLING ISR では、1回のクリックが何度もカウントされます。
ISR 内で delay() を使ってデバウンスすることはできません。delay() はクロック自身の割り込みを必要としますが、ISR の実行中は割り込みが一時停止されます。代わりにクロックを使いましょう。最後にカウントした押下の時刻を記録し、それからすぐに起きた立ち下がりは無視します。
unsigned long lastPress = 0;
void onPress() {
unsigned long now = millis();
if (now - lastPress >= 200) {
presses = presses + 1;
lastPress = now;
}
}ISR 内で millis() を読み取っても問題ありません。ISR が開始した時刻が返されます。クリックより長く、離したときのバウンスがその範囲内に収まり、2回の素早いクリックの間隔より短い時間幅を選びましょう。人が操作する場合は、200 ms でうまくいきます。
チャレンジ
中級このカウンターはクリックを何度も数えてしまいます。onPress()の中でデバウンス処理を行いましょう。
unsigned long lastPress変数を追加しますlastPressから少なくとも200 ms経過した場合にのみ立ち下がりを数え、その後、時刻をlastPressに保存します
Runを押し、ボタンを数回クリックしてカウントを確認し、次にCheckを押します。
自分で試してみよう
const int buttonPin = 2;
volatile int presses = 0;
int shown = 0;
void onPress() {
// ピンが立ち下がるたびにカウントされ、チャタリングも含まれるため、ここで除去する
presses = presses + 1;
}
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(buttonPin), onPress, FALLING);
}
void loop() {
// カウントが変わるたびに表示する
if (presses != shown) {
shown = presses;
Serial.println(shown);
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
delayを使わないタイミング制御のすべてのレッスン
自分で練習してみよう: Arduinoプレイグラウンド