임베디드 설계 노트 (2/6) — DI(Digital Input) 설계: 카운터 누적 디바운싱
산업 현장에서 250ms 디바운싱을 선택한 이유와 구현 전략
핵심 요약
- 산업 현장의 DI는 스위치 바운싱뿐 아니라 전자기 노이즈까지 견뎌야 한다
delay()방식 대신 카운터 누적 방식(Integrator-like Counter)을 적용해 노이즈 내성을 확보했다- 응답 속도(250ms)를 희생하더라도 오판정을 막는 것이 이 프로젝트의 최우선 과제였다
배경
임베디드 시스템에서 DI는 외부 접점 상태를 읽어오는 역할을 한다. 하지만 실제 환경에서는 스위치의 물리적 떨림(Bouncing)이나 전동기 구동으로 발생하는 전자기 노이즈가 신호에 섞인다.
이번 프로젝트의 설계 목표는 "어떤 노이즈 환경에서도 오판정을 하지 않는 신뢰성 확보"였다. 반응 속도가 다소 희생되더라도 시스템 오동작을 막는 것이 최우선이었다.
본문
하드웨어 구성
| 항목 | 사양 | 비고 |
|---|---|---|
| 포트 수 | 4 Port (DI1~DI4) | - |
| 입력 방식 | 무전압 접점 (Dry Contact) | MCU 내부/외부 풀업 활용 |
| 스캔 주기 | 1ms | 타이머 인터럽트 기반 |
| 보호 회로 | 포토커플러 또는 RC LPF | HW 1차 노이즈 제거 |
디바운싱 로직: 카운터 누적 방식
일반적인 delay() 방식은 CPU 자원을 낭비하고 멀티태스킹 환경에 부적합하다. 본 설계에서는 카운터 누적 방식을 적용했다.
동작 원리: - 매 스캔 주기(1ms)마다 입력 핀 상태를 읽어 카운트 증감 - High 입력 시 카운터 증가 (최댓값 제한), Low 입력 시 카운터 감소 (최솟값 0) - 임계값 도달 시 상태 변경 (히스테리시스 적용)
기본 임계값은 250회. 1ms x 250 = 250ms 이상 지속되어야 실제 상태로 인정한다.
typedef struct {
uint16_t counter; // 누적 카운터
uint8_t state; // 확정된 현재 상태 (0 or 1)
uint16_t threshold; // 임계값 (예: 250)
} DI_Channel_t;
void Process_DI_Scan(DI_Channel_t *di, bool raw_input) {
if (raw_input == HIGH) {
if (di->counter < di->threshold) di->counter++;
} else {
if (di->counter > 0) di->counter--;
}
// 히스테리시스 적용: 임계값 도달 시에만 상태 변경
if (di->counter >= di->threshold) {
di->state = HIGH;
} else if (di->counter == 0) {
di->state = LOW;
}
}
시행착오 / 주의사항
왜 250ms인가? 산업용 공조기나 대형 밸브 제어 환경에서는 수 ms 단위의 빠른 응답보다 "한 번 결정된 상태가 변하지 않는 것"이 훨씬 중요하다. 릴레이 미세 떨림이나 인버터 노이즈로 알람이 오동작하면 시스템 전체가 셧다운될 수 있다.
장점: 순간적 스파이크 노이즈에 매우 강하다. 카운터 누적 중 노이즈가 끼면 카운트가 다시 깎이므로 필터링 성능이 뛰어나다.
단점: 물리적 입력과 논리적 인지 사이에 250~500ms의 지연이 발생한다 (High→Low, Low→High 전이 모두 고려 시).
마무리
DI 설계의 핵심은 현장 환경에 대한 이해에 있다. 실험실에서는 10ms 디바운싱으로 충분하지만, 수십 미터 케이블이 깔린 현장에서는 수백 ms 단위 필터링이 필요할 때가 많다. 이번 프로젝트에서는 소프트웨어 카운터 방식으로 하드웨어 수정 없이 노이즈 문제를 해결할 수 있었다.
시리즈 전체 안내: 시리즈 목차
댓글
댓글 쓰기