EMBEDDED · INPUT STATE

버튼 디바운스: 안정 상태와 시간 단위를 분리하기

접점 샘플을 곧바로 버튼 이벤트로 쓰지 않는다. 후보 상태, 확정 상태, 경과 시간을 분리하고 RTOS tick과 밀리초를 섞지 않는다.

세 값으로 전이를 관리한다

stable은 마지막으로 확정한 논리 상태, candidate는 현재 관찰 중인 후보, since는 후보가 시작된 시각이다. 새 샘플이 candidate와 다르면 후보와 시각만 갱신한다. 후보가 stable과 다르고 정해진 안정 시간이 지났을 때에만 stable을 바꾸고 이벤트를 한 번 내보낸다.

분기와 관측 지점을 나눈 자체 개념도
  1. 새 샘플 ≠ 후보: 후보와 시작 시각 갱신

  2. 같은 후보, 대기 시간 미달: 확정 상태 유지

  3. 시간 충족·후보 ≠ 확정: 상태 변경, 이벤트 1회

이 그림은 주기적으로 입력을 읽는 상태 기계다. 샘플 사이에서 생겼다가 사라진 짧은 펄스는 관찰하지 못할 수 있다. 스캔 간격, 허용 지연, 접점 잡음의 특성을 함께 정해야 한다.

동작을 검증할 최소 의사코드

sample(raw, now):
    if raw != candidate:
        candidate = raw
        since = now
    if candidate != stable and elapsed(now, since) >= wait:
        stable = candidate
        emit(stable)

read_gpio 어댑터에서 active-low 같은 전기적 극성을 논리적 눌림으로 바꾼다. 시작할 때 읽은 값을 stable·candidate에 넣어 기동 이벤트를 생략할지, 초기 눌림도 이벤트로 알릴지를 API 계약으로 정한다. 보드 GPIO 번호나 OS 호출은 이 상태 기계 밖에 둔다.

elapsed는 사용하는 타이머 폭의 unsigned 차이를 일관되게 계산해야 한다. 한 바퀴 이상 관찰을 놓친 시간을 복원할 수는 없으므로 최대 스캔 공백과 비교 가능한 시간 범위를 제한한다. 위 코드는 설명용이며 특정 MCU에 그대로 적용할 드라이버가 아니다.

tick을 ms라고 부르지 않는다

FreeRTOS V11.1.0의 pdMS_TO_TICKS는 tick rate를 곱한 뒤 1000으로 정수 나눗셈한다. 예를 들어 100 Hz에서 5 ms 요청은 0 tick이 된다. xTaskGetTickCount 결과를 now_ms라는 변수에 그대로 넣어 ms 임계값과 비교하면 1 kHz가 아닌 설정에서 판단 시간이 달라진다.

현재 시각·since·wait를 모두 tick으로 유지하거나, 경계에서 명시적으로 같은 시간 단위로 변환한다. 0 tick을 허용할지 최소 1 tick으로 제한할지도 설계 선택이다. 최소 지연을 엄밀히 보장해야 한다면 tick 위상과 스케줄링 지연까지 포함해 검사한다.

고정 버전: FreeRTOS V11.1.0 시간 변환 매크로

잡음·반복·경계 조건을 따로 검사한다

상태 기계 테스트 계획
입력기대 결과
짧은 0→1→0 튐확정 전이면 이벤트 없음
눌림을 계속 유지눌림 이벤트 1회
해제도 안정 시간을 충족해제 이벤트 1회
타이머 wrap 부근의 전이허용 간격 내에서 동일 결과
대기열 포화·소비자 지연유실·재시도 정책을 명시

ISR과 task가 상태를 동시에 바꾸게 두지 않는다. 한 문맥이 상태 기계를 소유하고 다른 문맥은 샘플이나 이벤트만 전달하도록 설계하면 검사 범위가 작아진다. 길게 누르기·자동 반복·더블 클릭은 확정된 눌림/해제 이벤트 위에 별도 상태로 올린다.

원문과 검증 범위

이 글의 사용자 공유 근거는 Part 3 software debouncing(#174)과 Part 4 reusable button driver(#149)다. Part 1의 직접 게시물과 첨부는 확인하지 못했다. 작성자의 Part 2·5는 시리즈 맥락이며 사용자 공유 기록으로 세지 않는다.

Yamil Garcia의 software debouncing 및 reusable button driver 자료를 계기로 입력 추상화와 시간 단위를 정리했다. 원문 코드 전체를 복제하지 않았으며 위 의사코드와 테스트 계획은 독립 구성이다. 실제 보드의 바운스 파형, RTOS 스케줄링, 전기적 입력 조건은 이 글에서 측정하지 않았다.

출처: Part 3 software debouncing · 출처: reusable button driver