101_인터럽트란_비상전화호출 🚨📞

인터럽트 비상 호출

도로시와 지니가 함께하는 하던 일을 잠시 멈추고 1마이크로초 만에 긴급 처리하는 CPU의 비서 시스템

  • 👧 도로시: “지니야! 아두이노 코드가 delay(2000)로 쉬고 있을 때 비상 정지 버튼을 눌렀는데, 아두이노가 2초 동안 멍때리느라 버튼 신호를 완전히 무시하고 지나가 버렸어! 로봇이 벽에 부딪힐 뻔했잖아!”
  • 🐱 지니: “그게 바로 반복문에서 일일이 상태를 확인하는 ‘폴링(Polling)’의 치명적인 한계야! 그럴 때 아두이노가 무슨 일을 하고 있든 즉시 하던 일을 낚아채서 긴급 명령을 실행하게 만드는 마법이 바로 인터럽트(Interrupt, 가로채기) 란다!”
  • 🐶 토토: “바우! 공부하다가 중요한 전화가 오면 책갈피를 꽂아두고 전화부터 받는 거다 멍!”

  • 🖥️ 강의 슬라이드: slides.md

1. 도로시의 고민: 폴링(Polling)의 한계와 긴급 상황 무시

폴링의 지연 문제

🚨 메인 루프가 바쁠 때 발생하는 이벤트 누락(Missed Event)

일반적인 아두이노 스케치는 void loop() 함수를 위에서 아래로 순차 실행합니다.

graph TD
    subgraph 순차적 폴링 방식의 한계
        L1["1. 센서 값 계산 (수백 ms 소요)"] --> L2["2. LCD 화면 출력 (느림)"]
        L2 --> L3["3. delay(1000) 멍때리기"]
        L3 --> L4["4. 디지털 핀 버튼 눌렸나 확인 (if문)"]
        L4 --> L1
    end
    
    Event["사용자가 2번 단계에서 비상 버튼 클릭!"] -.->|"3번 delay 중이라 감지 못함!"| L3
  • 폴링(Polling) 방식에서는 루프 도중 delay()나 복잡한 계산이 실행 중일 때 스위치를 누르면 아두이노가 그 신호를 감지하지 못하고 허공으로 날려버립니다.
  • 산업용 로봇이나 자율주행차에서는 범퍼 충돌 스위치나 비상 정지 버튼이 0.001초라도 씹히면 대형 사고로 이어집니다.

2. 폴링(Polling) vs 인터럽트(Interrupt) 비교

초인종과 문지방 확인 비교

🚪 주기적으로 문을 열어보기 vs 초인종 벨소리에 즉시 반응하기

비교 항목 폴링 (Polling) 인터럽트 (Interrupt)
비유 손님이 왔나 1분마다 문 열어보기 손님이 초인종(Ding-Dong)을 누르면 즉시 문 열기
CPU 자원 낭비 아무 일도 없는데 계속 핀 상태를 검사함 평소엔 메인 연산에 100% 집중 (낭비 제로)
반응 속도 루프 한 바퀴를 다 돌 때까지 지연됨 신호 발생 즉시 (1마이크로초 이내) 반응!
이벤트 누락 delay() 중에 버튼을 뗐다 누르면 놓침 초고속 펄스도 하드웨어가 절대 놓치지 않음
주요 사용처 온습도 센서 주기적 측정 비상 정지 버튼, 엔코더 바퀴 회전수 계수

3. 인터럽트 동작의 3단계 흐름: 책갈피와 복귀

인터럽트 서비스 루틴 흐름도

📖 Context Save ➡️ ISR 실행 ➡️ Resume의 매끄러운 사이클

하드웨어 인터럽트 신호가 들어왔을 때 ATmega328P 마이크로컨트롤러 내부에서는 다음과 같은 기계적 전환이 발생합니다.

sequenceDiagram
    autonumber
    participant Main as 메인 프로그램 (void loop)
    participant Stack as 스택 메모리 (Stack)
    participant HW as 하드웨어 핀 (D2 / D3)
    participant ISR as 인터럽트 서비스 루틴 (ISR)

    Main->>Main: 모터 구동 및 화면 출력 연산 중...
    HW->>Main: 비상 버튼 펄스 발생 (FALLING edge)!
    Main->>Stack: 1. 현재 실행 주소(PC)와 레지스터 상태 저장 (책갈피 꽂기)
    Main->>ISR: 2. 우선순위 점프! 긴급 ISR 함수로 이동
    ISR->>ISR: 모터 즉시 정지 플래그 설정 및 상태 변경
    ISR->>Main: 3. 복귀 신호 (RETI)
    Stack->>Main: 책갈피 주소를 복원하여 하던 작업 계속 진행
  1. 책갈피 꽂기 (Context Save):
    • CPU가 실행 중이던 프로그램 카운터(PC)와 상태 레지스터(SREG) 값을 스택(Stack) 메모리에 안전하게 백업합니다.
  2. 비상 출동! ISR (Interrupt Service Routine):
    • 미리 등록해 둔 전용 인터럽트 처리 함수(emergencyStop())로 즉시 건너뛰어 초고속으로 처리합니다.
  3. 제자리로 복귀 (Resume):
    • ISR 함수가 끝나면 스택에서 책갈피를 꺼내와, 인터럽트가 걸렸던 바로 그 다음 줄부터 아무 일도 없었다는 듯 메인 코드를 이어갑니다.

4. 인터럽트의 2가지 주요 분류

아두이노 인터럽트 핀 분류

🌐 외부 하드웨어 핀 인터럽트 vs 내부 시스템 인터럽트

  • 1. 외부 인터럽트 (External Hardware Interrupt):
    • 물리적인 전선 핀에 걸리는 전압이 HIGH에서 LOW로 떨어지거나(FALLING) 전압이 바뀔 때 발동합니다.
    • 아두이노 우노(UNO)는 디지털 2번 핀(INT0) 과 디지털 3번 핀(INT1) 단 2개만 지원합니다!
  • 2. 내부 인터럽트 (Internal Software / Timer Interrupt):
    • 칩 내부의 하드웨어 타이머 카운터가 오버플로우되거나, UART 시리얼 수신 버퍼에 새 글자가 도착했을 때 자동으로 발동합니다.

5. ISR(인터럽트 함수) 작성 시 3대 절대 규칙

  1. 짧고 굵게 끝내라 (Short & Fast):
    • ISR 내부에서는 화면에 글자를 출력(Serial.println)하거나 오래 기다리는 delay() 함수를 절대 사용하면 안 됩니다 (delay()는 타이머 인터럽트를 쓰므로 ISR 안에서 영원히 멈춥니다).
  2. volatile 키워드 필수:
    • ISR 내부에서 값을 바꾸고 메인 loop()에서도 읽는 전역 변수는 반드시 앞에 volatile int count = 0; 처럼 volatile을 붙여 컴파일러 최적화에 의한 변수 캐싱 오류를 방지해야 합니다.
  3. 플래그(Flag) 전달 기법:
    • ISR 안에서는 isStopped = true; 처럼 깃발(플래그)만 꽂아두고, 실제 무거운 작업은 loop() 함수가 처리하도록 설계하는 것이 정석입니다.

🌟 도로시와 지니의 핵심 요약 노트!

인터럽트 요약

  • 👧 도로시: “인터럽트는 아두이노가 delay()로 아무리 깊은 잠에 빠져 있어도 1마이크로초 만에 즉시 깨워주는 초인종 비상벨이구나!”
  • 🐱 지니: “맞아! ISR 함수는 번개처럼 짧게 실행되어야 하며, 공유 변수에는 volatile을 선언한다는 규칙을 꼭 기억하렴.”
  • 🐶 토토: “바우! 이제 아두이노 2번 핀에 버튼을 달고 외부 인터럽트(attachInterrupt) 코드를 직접 만들어보자 멍!”
서브목차