아두이노 인터럽트의 이해 (interrupt)

 

인터럽트는 지정된 핀의 input 상태가 원하는 조건와 일치하면 미리 등록한 인터럽트 callback 함수(ISR, Interrupt Service Routines)를 자동으로 호출해주는 기능입니다. 이때 실행중이던 loop() 함수 안의 루틴은 인터럽트 callback 함수가 끝날 때 까지 대기상태가 됩니다.

즉, 특정 핀의 입력 상태가 바뀔때 아두이노는 이를 자동으로 감지해서 모든 동작을 잠시 멈춘 다음, ISR(Interrupt Service Routines) 이라 불리는 미리 지정된 함수를 실행하고, 다시 원래 작업으로 복귀합니다. 이를 하드웨어 인터럽트라 부릅니다. 이 외에도 타이머(timer) 인터럽트가 있는데 이건 사용 방법이 전혀 다르므로 여기서는 다루지 않습니다.

인터럽트는 Signal 상태에 따라 자동으로 특정 동작을 수행할 수 있도록 해주며, 타이밍 문제를 해결 할 수 있는 강력한 기능입니다. 주로 Rotary encoder, User input 등 을 처리하거나 모션센서 시그널을 모니터링 할 때 사용되곤 합니다.

아두이노는 인터럽트를 지원하기 위해 몇 개의 핀을 인터럽트 핀으로 지정해 두었습니다. 하드웨어 인터럽트는 이 핀을 통해서만 동작합니다.

 

 

아두이노 인터럽트 핀

 

UNO 기준으로 2개의 인터럽트 핀이 할당되어 있습니다. Number 0 (D2), Number 1 (D3). 각 보드별 지원되는 인터럽트 핀은 아래와 같습니다. 인터럽트 callback (ISR) 을 등록할 때 핀 번호가 아니라 인터럽트 넘버를 사용한다는 점에 주의!

Board                     int.0 int.1 int.2 int.3 int.4 int.5
Uno, Ethernet    2       3
Mega2560           2       3       21       20       19       18
Leonardo             3       2       0         1           7

Arduino Due 보드는 모든 핀에 인터럽트가 지원됩니다.

 

 

주의 사항

 

  1. 인터럽트 callback 함수(ISR, Interrupt Service Routines)는 파라미터를 전달하거나 리턴할 수 없습니다. void xxx_callback() 형태가 됩니다.
  2. ISR 안에서는 delay() 함수를 사용할 수 없습니다.
  3. 그리고 milli-단위의 시각을 가져오는 함수인 millis() 를 사용하더라도 값이 증가하지 않습니다. delayMicroseconds() 의 경우에는 인터럽트에 독립적이므로 정상 동작합니다.
  4. ISR 안에서 Serial data를 읽을 경우 값이 소실됩니다.
  5. ISR 안에서 수정되는 전역 변수는 volatile 로 선언되어야 합니다.
  6. ISR 은 최대한 짧고 빠르게 수행되도록 작성해야 합니다.
  7. 여러개의 ISR이 등록되어 있더라도 동시에 수행되지는 않습니다.
  8. 블루투스 모듈과의 통신을 위해 주로 사용되는 SoftwareSerial 라이브러리의 경우 내부적으로 인터럽트를 사용하는 것으로 알려져 있습니다. 따라서 UNO 보드의 경우 D2, D3 에 연결해야만 정상동작 합니다. 이를 회피하기 위해서 D0, D1 핀에 연결해서 Hardware Serial 로 동작시킬 수 있습니다.

 

 

인터럽트 등록 함수

 

void attachInterrupt(interrupt, ISR, mode)

interrupt: 인터럽트 번호, 핀 번호 아님! 아두이노 DUE 보드만 핀 번호로 사용. (int)
ISR: 인터럽트가 발생할 때 수행할 callback 함수
mode: 인터럽트가 수행될 조건
LOW: pin 이 LOW 상태일 때
CHANGE: pin 입력 값이 변경 될 때
RISING: LOW -> HIGH 로 변경 될 때
FALLING: HIGH -> LOW 로 변경 될 때
(HIGH: HIGH 상태일 때 – 아두이노 DUE 에서만 지원)

 

예제 코드

int pin = 13;
volatile int state = LOW;

void setup()
{
  pinMode(pin, OUTPUT);
  attachInterrupt(0, blink, CHANGE);
}

void loop()
{
  digitalWrite(pin, state);
}

void blink()
{
  state = !state;
}

 

앞서 인터럽트에서 수정하는 전역변수는 volatile로 선언해야 한다고 했습니다. state 변수를 전역으로 선언한 뒤, ISR 에서 수정하도록 하겠습니다. 따라서 아래와 같이 선언해줘야 합니다.

volatile int state = LOW;

 

인터럽트를 사용하려면 미리 인터럽트를 사용한다고 아두이노에 알려줘야 겠죠. setup() 초기화 함수 안에서  attachInterrupt() 함수를 이용하면 됩니다. 여기서는 핀 입력값이 변경될 때 마다 실행되도록 하기 위해 CHANGE 모드를 사용했습니다.

attachInterrupt(0, blink, CHANGE);

 

attachInterrupt() 함수에 사용된 blink 는 함수를 나타냅니다. 즉, 스케치 어딘가에 blink() 함수의 동작을 정의해둬야 합니다.

void blink()
{
  state = !state;
}

blink() 함수는 단순하게 입력값이 변경되었음을 알려주는 변수 state의 값을 HIGH->LOW 또는 LOW->HIGH로 바꿔줍니다.

blink() 함수는 ISR callback() 함수이고, 이 안에서 수정되는 전역 변수가 state이기 때문에 앞서 state를 volatile로 선언했음을 상기하세요.

 

You may also like...