인터럽트 기초 정리: 폴링과 ISR 흐름 한 번에 보기

카드뉴스

폴링과 인터럽트의 차이는 누가 먼저 확인하느냐입니다

임베디드에서 버튼 입력, 센서 상태, 통신 수신을 처리하는 방법은 크게 폴링과 인터럽트로 나눠 볼 수 있습니다. 폴링은 CPU가 메인 루프에서 상태를 계속 확인하는 방식입니다. 반대로 인터럽트는 이벤트가 발생했을 때 하드웨어가 CPU에게 알려주고, CPU가 잠시 현재 흐름을 멈춘 뒤 ISR로 들어가는 방식입니다. 둘 중 하나가 항상 정답은 아닙니다. 반응 속도, CPU 사용량, 코드 복잡도, 디버깅 난이도를 같이 봐야 합니다.

폴링은 구조가 단순합니다. `while` 루프 안에서 버튼 핀을 읽거나, UART 수신 플래그를 확인하거나, 센서 값을 주기적으로 읽으면 됩니다. 흐름이 눈에 보이기 때문에 처음 배우기 쉽고 디버깅도 편합니다. 다만 확인 주기가 길면 이벤트를 늦게 잡거나 놓칠 수 있고, 너무 자주 확인하면 CPU 시간을 낭비할 수 있습니다. 느린 상태 표시, 주기적인 센서 확인, 놓쳐도 큰 문제가 없는 입력에는 폴링이 실용적인 선택이 될 수 있습니다.

폴링을 쓸 때도 주기를 정해야 합니다. 버튼은 디바운싱 시간, 센서는 변환 시간, 통신 플래그는 버퍼가 넘치기 전까지의 여유를 봐야 합니다. 단순한 구조라고 해서 아무 때나 읽으면 되는 것은 아닙니다. 메인 루프의 한 바퀴 시간이 길어지면 폴링 응답도 같이 늦어집니다.

그래서 폴링 코드는 루프 시간이 관리되어야 합니다. 불필요한 delay가 많으면 버튼 반응, 센서 갱신, 통신 처리 모두 늦어지고, 나중에는 어디서 지연이 생겼는지 추적하기 어려워집니다.

인터럽트는 빠르지만 코드 흐름을 더 조심해야 합니다

인터럽트는 빠른 반응이 필요한 이벤트에 유리합니다. UART 수신, 타이머 주기, 외부 핀 변화, 긴급 정지 입력처럼 놓치면 안 되는 상황에서 자주 사용됩니다. 이벤트가 들어오면 CPU는 현재 실행 중이던 코드를 잠시 멈추고 인터럽트 서비스 루틴을 실행합니다. 이 구조 덕분에 메인 루프가 다른 일을 하고 있어도 중요한 이벤트를 처리할 수 있습니다.

하지만 ISR 안에서 많은 일을 하면 문제가 생깁니다. 긴 계산, delay, printf, 무거운 통신 처리, 블로킹 함수는 다른 인터럽트를 늦추거나 시스템 응답성을 떨어뜨릴 수 있습니다. 그래서 일반적으로 ISR에서는 플래그 설정, 짧은 데이터 저장, 카운터 증가처럼 빠른 작업만 하고, 실제 처리는 메인 루프나 RTOS 태스크로 넘깁니다. 인터럽트 우선순위와 중첩 가능성도 프로젝트 규모가 커질수록 중요한 설계 요소가 됩니다.

선택 기준은 이벤트의 시간 요구사항입니다

버튼 입력 하나만 봐도 답은 상황에 따라 달라집니다. 사람이 누르는 버튼은 수 ms 단위의 디바운싱이 필요하고, 반응 속도가 아주 빠를 필요가 없는 경우가 많습니다. 이때는 폴링과 타이머 기반 처리만으로도 충분할 수 있습니다. 반면 고속 펄스 카운트, 통신 수신 버퍼, 제어 주기 타이머는 인터럽트나 DMA를 함께 봐야 할 수 있습니다.

디버깅할 때는 “이 이벤트가 언제 발생했고, 언제 처리됐는가”를 확인해야 합니다. GPIO 토글로 ISR 진입 시간을 보거나, 로직 애널라이저로 신호와 처리 타이밍을 비교하면 코드 감각이 훨씬 좋아집니다. 폴링과 인터럽트는 우열의 문제가 아니라 요구사항에 맞게 CPU 시간을 배치하는 방법입니다.

댓글 남기기