아두이노를 사용할 때, 버튼입력의 신호가 이상하게 입력될 때가 종종 있다.
버튼이 오동작 하기 쉬운 이유는 접점 불량으로 발생하기 쉽기 때문이다.
이 오류를 해결하는 방법이 Debounce 알고리즘을 사용하는 것이다.
이번 포스팅에서는 이 Debounce 알고리즘을 살펴보고, 어떻게 쓰는 것인지 알아보도록 한다.
Debounce 는 쉽게 말해 특정시간이 지난 후 하나의 이벤트만 발생하도록 하는 기술이다.
버튼이 오동작 할 때를 보면 상황이 아래와 같을 때이다.
0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
신호를 엄청 빠르게 읽어오는데 0에서 1로, 1에서 0으로 바뀌는 구간이 바로 이상함이 감지되는 구간이다.
도저히 사람 손으로 신호를 주기에는 너무 찰나의 순간이기 때문에, 값이 튄 것이 확실하다.
우리는 아두이노 말고도 실상에서 이러한 현상을 이미 수 많이 겪었다.
바로 컴퓨터의 키보드나 마우스를 이용할 때, 두번씩 눌리거나 하는 이유가 이러한 신호의 bounce 때문이다.
놀랍게도 운영체제에 이미 이런 오류를 잡아주기 위해 debounce 세팅이 되어 있지만, 비정상적인 하드웨어인 경우에는 신호를 바로잡기에 한계가 있다.
그래서 우리는 키보드나 마우스에서 이러한 현상이 발생하는 경우 기기를 바꿔온 것이다.
Debounce 알고리즘의 원리는 간단하다.
1 단계 : 이전 신호 값을 전역변수에 값을 저장시킨다.
2 단계 : 저장된 이전 신호 값과 다른 값이 감지된 경우 그 시간차이가 설정한 debounce delay 시간보다 큰지 판별한다.
3 단계 : 시간 차이가 debounce delay 시간보다 크지 않다면 잘 못된 신호로 무시한다.
4 단계 : 시간 차이가 debounce delay 시간보다 크다면 올바른 신호로 판단하고, 이전 신호 값에 최신 신호값을 저장한다.
즉, debounce delay 시간은 사용자가 설정하고,
신호가 입력되었을 때, 그 신호가 이전값과 다른데 설정한 시간보다 빠르게 감지가 되었다면 잘 못된 신호로 판단하는 것이다.
짧은 순간에 값이 변하는 신호 값들을 무시한다는 것이다.
영상으로 판단하는게 더 좋을 듯 하다.
Debounce를 적용하지 않은 경우에는 4번이나 신호가 잘 못 입력된 반면
Debounce를 적용한 경우에는 오류가 한번도 발생하지 않았다.
Debounce 알고리즘은 위에 있는 것이 전부가 아니다.
이렇게 튀는 신호를 제어하는 과정을 통틀어 말한다.
쉽게 사용하려면 delay 시간을 설정하고
그 시간 이후에 센서 값을 한 번 더 감지해서 값이 같은지 비교해도 꽤 쓸만한 Debouncing 알고리즘이 된다.
직접 확인해보려면 아래 코드를 사용하시길 바란다.
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin
// Variables will change:
int ledState = HIGH; // the current state of the output pin
int buttonState; // the current reading from the input pin
int lastButtonState = HIGH; // the previous reading from the input pin
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
// set initial LED state
digitalWrite(ledPin, ledState);
}
void loop() {
int reading = digitalRead(buttonPin);
// put your main code here, to run repeatedly:
if (reading != buttonState) {
buttonState = reading;
// only toggle the LED if the new button state is HIGH
if (buttonState == HIGH) {
ledState = !ledState;
}
}
digitalWrite(ledPin, ledState);
}
Debounce 적용하지 않은 일반적인 Code
// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin
// Variables will change:
int ledState = HIGH; // the current state of the output pin
int buttonState; // the current reading from the input pin
int lastButtonState = HIGH; // the previous reading from the input pin
// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
// set initial LED state
digitalWrite(ledPin, ledState);
}
void loop() {
// read the state of the switch into a local variable:
int reading = digitalRead(buttonPin);
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;
// only toggle the LED if the new button state is HIGH
if (buttonState == HIGH) {
ledState = !ledState;
}
}
}
// set the LED:
digitalWrite(ledPin, ledState);
// save the reading. Next time through the loop, it'll be the lastButtonState:
lastButtonState = reading;
}
Debounce 적용한 Code
'코딩 > 아두이노' 카테고리의 다른 글
모터드라이버 L298N 5V로 모터 제어하기 (13) | 2021.03.11 |
---|---|
아두이노 타이머 카운터 인터럽트 사용하는 방법 CTC모드 (4) | 2021.02.23 |
아두이노 입출력 인터럽트에 대해서 알아보자 attachInterrupt() (2) | 2020.12.23 |
아두이노와 ESP8266으로 wifi에 연결해서 웹서버 만드고, 센서값 출력하기 (24) | 2020.10.23 |
아두이노 내부전원으로 서보모터(SG-90) 여러개 사용하는 방법 (0) | 2020.10.16 |
댓글