1. 기초 이론
지난 게시글에서 다뤘던 Digital Input의 연장선인 Interrupt에 대해 알아봅시다. 우선 Interrupt의 사전적 정의를 보면 아래와 같습니다.
뜻만 보더라도 어떤 기능인지 알 수 있듯 MicroController를 '방해'하고 '중단'시키는 기능입니다.
좀 더 일상에서 비유를 들자면 우리는 숙제(Main Task)를 하고 있다고 가정해봅시다. 숙제를 하는 중간에 전화(Digital Input)가 오기로 해서 전화(Digital Input)를 받아야 합니다. 이런 상황에서 지난 게시글의 이론 기반으로 Code를 짠다면, 다음과 같은 행동을 보이게 될 것입니다. 우리는 숙제(Main Task)를 하고 있는 도중에 전화(Digital Input)가 왔을 때, 숙제(Main Task)를 끝마치지 않았기 때문에 전화(Digital Input)가 왔는지 확인할 겨를이 없습니다. 그래서 우리는 숙제(Main Task)가 끝나야 전화(Digital Input)가 왔는지 알 수 있을 겁니다. 하지만 숙제(Main Task)가 끝났을 때, 전화(Digital Input)가 끊어졌을지(Low) 아직 오고 있을지(High)는 모르는 일입니다. 전화(Digital Input)가 오고 있을 수도 있고 왔다가 끊어졌을 수도 안 왔을 수도 있는 일입니다. 이러한 문제 때문에 우리는 숙제(Main Task)를 하면서 전화(Digital Input)가 오는 것을 제때 확인할 방법이 필요합니다. 예를 들면, 무음을 해제하고 벨소리로 전환(Set Interrupt)하는 것이죠. 그럼 우린 숙제(Main Task)를 하다가 전화(Digital Input)가 왔을 때, 벨소리(Interrupt Flag)가 울리는 것을 듣고 대응을 할 수가 있습니다. 이전에 비해 매우 효율적으로 변한 것을 볼 수 있습니다.
예시를 드느라 멀리 돌아왔는데 본질로 돌아와 봅시다. 우리는 제어기가 main문을 돌고 있을때 Switch 혹은 다른 전자적인 신호가 입력되었을 때, 입력 신호를 매번 확인하는 것이 아니라 Interrupt를 등록해 놓고 ISR(Interrupt Service Routine)으로 처리할 겁니다. 이렇게 막 어려운 말을 난무하면 보기 싫죠?
가볍게 말하면, 그냥 Interrupt로 쓸 수 있는 Pin은 정해져있습니다. 그 핀을 Interrupt로 등록해놓고 그 Pin에 신호가 왔을 때, 수행할 함수를 묶어놓으면 됩니다.
위와 같이 INTx로 적혀있는 Pin은 Interrupt로 쓸 수 있다는 얘기입니다.
(해당 그림은 구글에 'Arduino Uno Pin Map'을 검색하면 찾을 수 있습니다)
Interrupt Pin과 Function을 묶었다면, 우리는 할 수 있는 것을 모두 끝냈습니다. 이제 Digital Input이 들어오는 것을 기다려야 하는 거죠.
아, 그리고 중요한게 Interrupt를 받아들이는 데는 몇 가지 종류가 있습니다. 아두이노 기준으로는 Falling / Rising / Change Mode가 있습니다. 하나씩 까 봅시다.
- Falling Edge: Falling Edge Detect로 설정해두면, 사전적 정의 그대로 떨어지는 부분을 Interrupt 신호로 감지하게 됩니다. Input 전압이 HIGH로 떠있다가 LOW로 떨어지는 순간을 캐치해 연결되어 있는 Function을 수행하게 됩니다.
- Rising Edge: Falling Edge와 반대로 Input 전압이 LOW로 떨어져 있는 상태에서 HIGH로 뜰 때를 캐치하여 연결되어 있는 Function을 수행하게 됩니다.
- Change Edge: Change는 말 그대로 전압의 Level이 HIGH -> LOW 나, LOW -> HIGH의 변화가 있을 때를 모두 Signal로 받아 Interrupt와 연결되어 있는 Function(ISR)을 수행시킵니다.
Interrrupt를 사용하고자 할 때, 현재 회로 상황에 맞춰서 선택하면 됩니다.
- Falling Edge가 필요한 상황: Input 신호가 들어오지 않았을 때는 LOW의 값을 유지하다가 Input이 HIGH로 뜬 순간 ISR을 동작시키고 싶다!
- Rising Edge가 필요한 상황: Input 신호가 들어오지 않았을 때는 HIGH의 값을 유지하다가 Input이 LOW로 떨어진 순간 ISR을 동작시키고 싶다!
- Change Edge가 필요한 상황: Input 신호의 변화에 따라 ISR을 동작시키고 싶다!
2. 실습 예제
2번 Pin으로 Interrupt를 입력받아 13번 내장 LED를 켜는 Code를 짜 봅시다.
Input 때와 동일하게 2번 Pin은 Pull-up Input으로 설정해두고 13번 Pin은 Output으로 설정하면 될 것 같네요.
* 동작 특성
- Switch를 누르지 않았을 때는 LED는 Off
- Switch를 눌렀을 때는 LED On
동작 특성만 봤을 때는 이전 게시글인 Digital Input과 동일합니다.
void setup() {
// put your setup code here, to run once:
pinMode(2, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(2), led_OnOff, CHANGE);
pinMode(13, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
}
void led_OnOff() {
if (digitalRead(2) == HIGH) {
// Switch Open
digitalWrite(13, LOW);
}
else {
// Switch Close
digitalWrite(13, HIGH);
}
}
이전 Digital Input Code와 현재 Code는 Loop 내에 Logic이 추가되었을 경우 차이가 발생합니다. 예를 들어 Loop 내에 수행 시간이 10초가 걸리는 Logic이 추가되었다고 가정해 봅시다. 그렇다면 이전 Digital Input 게시글의 Code는 10초짜리 Logic을 수행한 뒤 잠깐의 시간 동안 스위치의 Input을 읽어서 입력이 들어왔는지 아닌지를 확인합니다. 이렇게 되면 Logic이 수행되는 10초 동안의 입력은 무시가 되겠죠?
하지만 Interrupt Code로 구현하게 되면, 10초짜리 Logic이 수행되는 동안 Digital Input이 들어왔을 때, 하던 일을 멈추고 led_OnOff 함수를 수행하게 될 것입니다. 그럼 즉각 즉각 동작하는 것으로 보이겠죠? 이러한 이유로 로직이 복잡해질수록 우리는 Interrupt를 자주 마주할 수밖에 없을 것입니다.
이에 관련된 Arduino 문서는 아래 링크를 참고해주세요~
https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/
'임베디드 일지 > 아두이노 기초' 카테고리의 다른 글
[아두이노 기초] Serial 통신 (0) | 2023.03.30 |
---|---|
[아두이노 기초] ADC (0) | 2022.09.14 |
[아두이노 기초] GPIO Input (0) | 2022.04.09 |
[아두이노 기초] Arduino Mega 2560 - 2 (0) | 2021.12.17 |
[아두이노 기초] Arduino Mega 2560 - 1 (0) | 2021.12.16 |