티스토리 뷰

Arduino Uno Switch Debouncing and Chattering

대부분의 스위치를 손으로 한번 누를 때, 접점 부근에서 스위치의 물리적인 떨림에 의해 여러 번 눌러지는 현상을 채터링(Chattering) 이라고 합니다. 이 채터링에 의한 노이즈를 보호하기 위해 디바운스(Debounce)라는 방법을 사용합니다. 디바운싱은 회로적인, 소프트웨어적인 방법으로 처리가 가능합니다. 본 포스트에서는

스위치의 물리적인 떨림에 의한 채터링 현상을 제거하는 디바운스 처리

에 대해 작성하였습니다.

채터링과 디바운스

채터링

아래와 같이 스위치를 짧게 한번 눌렀다 때면, 스위치의 물리적 떨림에 의해 스위치가 여러번 눌러진 것과 같은 현상을 채터링 이라고 합니다. 첫 번째 파형사진 시간 간격이 한칸에 20ms 이고, 채터링이 한번 발생한 것 처럼 보입니다. 하지만, 첫번째 스위치 누른 타이밍의 시간을 좁게 확대해서 보면 스위치가 눌러지고 200 us 정도가 지나서 채터링이 앞서 한번더 있었던 것으로 확인됩니다. 

스위치 채터링 현상스위치 채터링 현상

디바운스 : 회로적인 방법

스위치의 채터링 현상을 제거하기 위해 스위치에 역할을 할 수 있는 커패시터를 추가하는 방법이 있습니다. 스위치의 종류 및 부착된 기구에 따라 채터링이 발생되는 타이밍이 달라, 각 어플리케이션에 맞게 저항도 추가하여 RC에 의한 시정수 조정으로 채터링 현상을 방지하는 타이밍을 제어합니다. 

아래 그림은 간단히 스위치에 0.1uF 커패시터를 추가하고 파형을 비교한 그림입니다. 100nF 커패시터를 추가시 비교적 짧은 시간의 채터링(수백 us 이하)은 방지가 되지만, 긴(수 ms 이상)시간의 채터링은 방지가 되지 않습니다. 더 긴 시간 디바운스효과를 만들기 위해 큰 용량의 캐패시터를 사용할 수 있지만, 수 ~uF 크기를 초과하는 경우 소형 커패시터는 찾기가 힘들고 비효율적입니다.

※ D2 포트는 MCU 내부에서 풀업 저항이 연결 되어있는 상태입니다.

디바운스 커패시터디바운스 커패시터 유무 차이 (100us /div)

디바운스 커패시터디바운스 커패시터 유무 차이 (20mss /div)

디바운스 : 소프트웨어 방법

프로그래밍으로 디바운스를 구현하는 방법은 상황에 따라 다양합니다. 아래는 디바운스를 구현하기 위해 제가 제안하는 방식 입니다. 스위치 눌러짐 인식이 Falling Edge 인 경우 입니다.

  • 제작된 회로 및 기구조립 상태에서 채터링 간격을 여러 번 측정
  • 1st edge 에서 lat edge 사이의 통계적인 시간을 측정 : ex) 최대 100ms
  • Falling Edge 발생 이후 30ms 이내에 Falling Edge 가 발생하는 경우 프로그램에서 무시하는 코드를 작성

디바운스 예제

회로도

본 예제의 아두이노 연결은 아래와 같습니다.

  • D2 : 스위치 입력 포트로 사용 - 인터럽트 Falling Edge, 내부 풀업(Pull-up) 저항 사용
  • D13 : LED 출력 포트

채터링 테스트 회로도채터링 테스트 회로도

코드

주요 코드는 아래와 같습니다.

  • 4번 줄 : #define 문에서 debounceTime 조정이 가능합니다. 코드에서 100ms 로 설정한 이유는 사람이 100ms 안에 두번 눌리는 것이 힘들 것이라고 판단하였기 때문입니다.
  • 10번 줄 : attachInterrupt() 함수를 사용하여 D2 핀을 Falling Edge 일 때 수신 인터럽트로 사용합니다.
  • 18 ~ 26번 줄 : buttonPushed() ISR 함수에서 지난 falling edge 시간보다 debounceTime 초과한 경우에 버튼이 눌러진 것으로 간주합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#define buttonPin 2
#define ledPin 13
#define debounceTime 100 // <<- Set debounce Time (unit ms) 
 
volatile int state = LOW;
 
void setup() {
    pinMode(buttonPin, INPUT_PULLUP);
    pinMode(ledPin, OUTPUT);
    attachInterrupt(digitalPinToInterrupt(buttonPin),buttonPushed,FALLING);
}
 
void loop() {
    digitalWrite(ledPin, state);
}
 
// 버튼이 눌러진 경우 이전 Falling 에지 발생 시간보다 100ms 를 초과한 경우 state 를 반전
void buttonPushed() {
    static unsigned long lastTime = 0;
    unsigned long now = millis();
    if((now-lastTime) > debounceTime)
    {
        state=!state;
    }
    lastTime = now;
}
cs

실행 결과

아래 영상에서 버튼 누르는 경우 채터링 발행 하는 것을 확인 할 수 있지만, 프로그램 코드로 채터링 현상을 무시하여 LED가 정상적으로 반전 되는 것을 확인 할 수 있습니다. 


마무리

본 포스트에서 채터링 현상에 대해 알아보고, 이를 방지하기 위한 디바운싱 방법에 대해 알아보았습니다. 본 코드에 작성한 millis() 시간 함수에 대해 사용법을 모르시는 분은 아래 관련 포스트를 참고해주세요.

끝까지 읽어 주셔서 감사합니다.^^

See Also

아두이노 시간 함수 delay(), delayMicrosecons(), millis(), micros()

2020/07/02 - [Arduino/Basic] - 아두이노 강좌 #3 시간 관련 함수 설명, delay() 없이 LED Blink 코드 작성


댓글
댓글쓰기 폼
최근에 올라온 글
«   2020/10   »
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Total
21,965
Today
190
Yesterday
595