카드뉴스










버튼 한 번이 여러 번 입력되는 이유는 코드만의 문제가 아닙니다
버튼을 한 번 눌렀는데 LED가 두 번 바뀌거나 메뉴가 여러 칸 이동하는 경우가 있습니다. 처음에는 조건문이나 인터럽트 설정을 의심하기 쉽지만, 실제 원인은 기계식 버튼 접점의 바운스일 수 있습니다. 버튼이 눌리는 순간 접점이 바로 안정되는 것이 아니라 아주 짧은 시간 동안 붙었다 떨어졌다를 반복하면서 신호가 high와 low 사이를 빠르게 오갈 수 있습니다.
사람에게는 거의 느껴지지 않는 시간이지만 MCU 입장에서는 충분히 긴 시간일 수 있습니다. 수 MHz 이상의 클럭으로 동작하는 MCU는 그 짧은 흔들림도 여러 번 샘플링할 수 있고, 인터럽트 입력이라면 엣지가 여러 번 발생한 것처럼 보일 수 있습니다. 그래서 버튼 입력에서는 “눌렸다”는 순간을 바로 확정하지 않고, 일정 시간 동안 같은 상태가 유지되는지 확인하는 디바운싱 과정이 필요합니다.
풀업·풀다운과 디바운싱은 해결하는 문제가 다릅니다
버튼 회로에서 pull-up이나 pull-down은 입력 핀이 떠 있는 상태를 막기 위한 설정입니다. 버튼을 누르지 않았을 때 기본 전압을 high 또는 low로 고정해 플로팅 입력을 줄이는 역할을 합니다. 반면 디바운싱은 버튼 접점이 튀는 동안 발생하는 짧은 변화를 걸러내는 처리입니다. 둘 다 버튼 입력에 필요할 수 있지만, 풀업을 설정했다고 바운스가 사라지는 것은 아닙니다.
소프트웨어 디바운싱의 기본 흐름은 단순합니다. 입력 상태가 바뀌면 그 시각을 저장하고, 5ms나 10ms처럼 정한 시간이 지난 뒤 다시 읽습니다. 그때도 같은 상태가 유지되면 유효한 입력으로 인정합니다. 정확한 시간은 버튼 종류, 회로, 제품 요구사항에 따라 달라질 수 있으므로 상황을 보지 않고 하나의 값으로 고정하기보다 실제 파형이나 동작을 보고 조정하는 편이 좋습니다.
인터럽트 버튼도 디바운싱 설계가 필요합니다
인터럽트를 쓰면 버튼 입력을 놓치지 않는 데 도움이 될 수 있지만, 바운스 자체를 없애주지는 않습니다. 오히려 접점이 튀는 동안 인터럽트가 여러 번 들어와 ISR이 반복 실행될 수 있습니다. 버튼 인터럽트 안에서 긴 delay를 넣어 기다리는 방식은 다른 인터럽트 지연이나 main loop 정체를 만들 수 있어 권장하기 어렵습니다.
더 안정적인 구조는 인터럽트에서 시간값이나 플래그만 저장하고, 실제 디바운싱 판단은 main loop나 Timer 주기 처리에서 수행하는 방식입니다. 하드웨어로는 RC 필터나 슈미트 트리거 입력을 활용할 수 있고, 노이즈가 많은 환경에서는 회로와 소프트웨어를 함께 봐야 합니다. 디바운싱의 목표는 복잡한 코드를 만드는 것이 아니라, 버튼 한 번을 시스템 안에서 안정적인 입력 한 번으로 확정하는 것입니다.
디버깅은 파형과 로그를 같이 보면 빠릅니다
버튼 입력 문제가 의심될 때는 카운터 값만 보는 것보다 입력 핀 파형을 확인하는 것이 좋습니다. 로직 애널라이저나 오실로스코프로 누르는 순간의 high, low 전환을 보면 바운스가 실제로 얼마나 지속되는지 알 수 있습니다. 장비가 없다면 상태 변화 시각을 로그로 남겨 연속 입력 간격을 확인할 수 있습니다. 이 기록을 바탕으로 디바운싱 시간을 정하면 너무 짧아 여러 번 잡히거나, 너무 길어 버튼 반응이 둔해지는 문제를 줄일 수 있습니다.