Menu
CoddyTech

인터럽트로 버튼 누름 횟수 세기

Coddy Arduino 여정의 delay 없이 타이밍 제어하기 섹션에 포함된 레슨. 18개 중 15번째.

입력 섹션에서 보았듯이 버튼은 바운스합니다. 약 1밀리초 동안 접점이 닿았다가 떨어지고 다시 닿으며, 누를 때와 놓을 때 모두 발생합니다. 인터럽트는 접점이 닿을 때마다 감지하므로, 1을 더하는 FALLING ISR은 한 번의 클릭을 여러 번으로 셉니다.

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이 시작된 시간을 알려 줍니다. 손을 놓을 때 발생하는 바운스가 그 안에 들어가도록 클릭 시간보다 긴 구간을 선택하고, 빠르게 두 번 클릭할 때의 간격보다는 짧게 설정하세요. 사람의 경우 200ms가 적절합니다.

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 플레이그라운드