지난 글에서 푸시버튼에 대해 간단히 서술했는데, 이번에는 푸시버튼을 이용해 카운터를 만드려고 한다. 간단히 버튼을 한번씩 누를 때마다 숫자를 1씩 증가시켜 시리얼로 출력하는 기능을 구현해보자.
내부 PULL_UP 저항을 사용한다고 가정하면 회로는 아래와 같다.
2: Push Button - input
13: LED - output
#define BUTTON 2
#define LED 13
void setup(){
pinMode(BUTTON, INPUT_PULLUP);
pinMode(LED, OUTPUT);
Serial.begin(9600);
}
우선 단순하게 생각하면 아래와 같은 코드를 짤 수 있다.
// 전역변수
int count = 0;
void loop(){
if (digitalRead(BUTTON) == LOW){ // pull-up 이므로 LOW가 버튼 눌렀을 떄!
count++;
digitalWrite(LED, HIGH);
Serial.println(count);
} else {
digitalWrite(LED, LOW);
}
}
그러나 이렇게 짠 경우 실행을 해보면 버튼을 한번 누르는데 출력값이 20~30씩 커지는 것을 볼 수 있다.
이유는 우리가 얼핏 생각한 것보다, 아두이노의 동작이 훨씬 빠르기 때문이다. 따라서 빠르게 눌렀다 떼는 그 찰나에도 loop()
가 20~30번 실행되었던 것이다.
그렇다면 원하는 동작을 어떻게 수행할 수 있을까?
버튼을 누르는 과정을 조금 자세히 구분하면 버튼을 누르는 순간(A), 버튼이 계속 눌리고 있는 구간(B), 버튼에서 손을 떼는 순간(C)가 있다.
구간 B에서 루프 함수가 여러번 실행되므로, 이 때 카운트가 한번만 높아지도록 코드를 수정할 필요가 있다.
따라서 이미 카운트 했다는 것을 표기하는 플래그 변수를 사용할 것이다.
bool flag = false;
void loop(){
bool isPushed = !digitalRead(BUTTON); // pull-up 이므로 LOW가 눌린 순간
if (isPushed == LOW && !flag){ // 아직 표시하지 않은 경우만
count++;
flag = true; // 이미 카운트를 했음
Serial.println(count);
digitalWrite(LED, HIGH);
}
if (!isPushed){
isPushed = false; // 버튼에서 손을 뗐다면 다시 플래그 변수를 flase로 돌려줌
digitalWrite(LED, LOW);
}
}
이런식으로 고치면 이제 한번에 하나씩만 숫자가 올라가는 것을 볼 수 있다.
참고로 저 A인 순간과 C인 순간을 포착하는 방식도 있는데 관련해서는 이후에 포스팅 할 예정이다.