Menu
CoddyTech

割り込みでボタン押下を数える

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 でうまくいきます。

challenge icon

チャレンジ

中級

このカウンターはクリックを何度も数えてしまいます。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);
  }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

delayを使わないタイミング制御のすべてのレッスン

自分で練習してみよう: Arduinoプレイグラウンド