아두이노 코딩 스위치 입력 인터럽트(Interrupt) 방식으로 LED 제어
Lucy Archive
Lucy 2023
2020. 7. 20. 22:35

아두이노 우노 스위치 입력 인터럽트 예제아두이노 우노 스위치 입력 인터럽트 예제

Arduino Uno Switch Input EXTI Method for LED Control

아두이노 우노 보드에서 스위치 입력을 인터럽트 방식으로 구현하여 LED를 제어하는 예제입니다. 인터럽트 방식으로 여러가지 동작을 동시에 기능 하는 것처럼 프로그래밍 구현이 가능합니다. 본 포스트에서는

스위치 인터럽트 방식을 이용하여 우선순위에 따라 사용할 수 있는 두 가지 코드 예제

를 소개합니다.

Hardware

준비물

본 예제의 구성품은 아래와 같습니다.

  • Arduino Uno x 1 EA
  • Dip Type LED x 1 EA
  • Dip Type Tact Switch x 1 EA
  • Dip Type Resistor x 1 EA
  • Bread Board x 1 EA
  • Jumper Wires

회로도 : 스위치, LED연결

본 포스트의 회로도와 LED 연결 방식은 이전 스위치 폴링 방식 LED 제어 포스트와 동일합니다.

Arduino EXTI Example(좌) 회로도, (우) 연결 방법 예시

본 예제의 회로 구성은 아래와 같습니다.

  • D2 : 스위치 인터럽트 FALLING EDGE 로 설정, 내부 풀업 사용
    • Switch ON 시점 : LED Toggle
  • D13 : LED 출력
    • HIGH 출력 일 때 LED 켜짐
    • LOW 출력일 때 LED 꺼짐

예제 설명

스위치가 On 되는 시점에 LED 가 토글 되는 예제입니다. 코드 우선순위에 따라 다르게 처리 하는 방식의 예제 2가지를 소개합니다.
  • 예제1 - 스위치 동작 우선 순위 최고 높은 경우 : ISR() 에서 모두 실행
  • 예제2 - 스위치 동작 우선 순위 높으나 즉시 실행 하지 않아도 될 때 : ISR() 에서 flag 활성화 loop() 에서 기능 동작

Interrupt Service Routine(ISR)은 인터럽트가 접수되었을 때 실행 되는 코드입니다. ISRInterrupt Handler 와 동일한 용어 입니다.

예제1 : ISR에서 모두 실행

Code

스위치가 ON 되는 타이밍에 LED 를 토글시키는 명령어 입니다.

Serial.println() 문은 인터럽트 우선 순위 처리를 확인하기 위해 작성하였습니다. 

loop() 문의 delay() 함수는 코드 실행 순서롤 보여 주기 위해 억지로 시간 지연을 추가하였습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#define switchPin 2 // 스위치 핀 번호 
#define ledPin 13 // LED 핀 번호
 
volatile int state = LOW;
 
void setup() {
    pinMode(switchPin, INPUT_PULLUP);
    pinMode(ledPin, OUTPUT);
    attachInterrupt(digitalPinToInterrupt(switchPin),INT0_ISR,FALLING); //Interrupt Init
 
    Serial.begin(9600);
    while(!Serial) {;}
    Serial.println("Program Start....");
    delay(1000);
}
 
void loop() 
{
    Serial.println("Statement 1");
    delay(300);
    Serial.println("Statement 2");
    delay(300);
    Serial.println("Statement 3");
    delay(300);
    Serial.println("Statement 4");
    delay(300);
    Serial.println("Statement 5");
    delay(300);
}
 
void INT0_ISR() //Interrupt ISR
{
    digitalWrite(ledPin, !digitalRead(ledPin));
    Serial.println("LED Toggled!");
}
cs

실행 결과

아래 영상과 같이 Tack-Switch 를 누르는 순간 LED 가 Toggle 되는 결과를 볼 수 있습니다.

예제2 : ISR에서 Flag 만 활성화

Code

스위치가 ON 되는 타이밍에 bFlag 를 True 로 활성화하고, LED 토글기능은 loop() 문 안에서 다른 기능들과 함께 순차적으로 처리 합니다.

Serial.print() 문은 Example 1 과 처리 방식 차이를 보여주기 위해 작성한 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#define switchPin 2 // 스위치 핀 번호 
#define ledPin 13 // LED 핀 번호
 
volatile boolean bFlag = false;
 
void setup() {
    pinMode(switchPin, INPUT_PULLUP);
    pinMode(ledPin, OUTPUT);
    attachInterrupt(digitalPinToInterrupt(switchPin),INT0_ISR,FALLING); //Interrupt Init
 
    Serial.begin(9600);
    while(!Serial) {;}
    Serial.println("Program Start....");
    delay(1000);
}
 
void loop() 
{
    Serial.println("Statement 1");
    delay(300);
    Serial.println("Statement 2");
    delay(300);
    Serial.println("Statement 3");
    delay(300);
    Serial.println("Statement 4");
    delay(300);
    Serial.println("Statement 5");
    delay(300);
 
    if(bFlag == true){ // bFlag 가 True 인 경우 실행
        bFlag = false;
        digitalWrite(ledPin, !digitalRead(ledPin));
        Serial.println("----> LED Toggled!");
    }
}
 
void INT0_ISR() //Interrupt ISR, 버튼 ON 되는 경우 bFlag 를 반전
{
    bFlag = !bFlag;
    Serial.println("----> Button Pushed!!");
}
cs

실행 결과

아래 동영상과 같이 Tact-Switch 누르는 순간에 ISR() 함수로 진입하고, LED Toggle 기능은 "Statement 5" 실행 이 후 동작합니다. Tact-Switch 가 Statement 5 실행 완료 전까지 짝수만큼 눌려지는 경우 LED Toggle 기능은 수행하지 않습니다.


Review

예제1, 예제2 결과비교

아래 그림은 예제1과 예제2의 프로그램 순서도를 나타냅니다. 예제1은 INT0 인터럽트가 발생하면 LED Toggle 기능을 수행 후 ISR 함수를 빠져나옵니다. 예제2는 INT0 인터럽트가 발생하면 전역변수 bFlag 를 반전하고, loop() 문에서 순차적인 동작을 수행합니다.

인터럽트 신호 처리 방법 예시(좌) 예제1, (우) 예제2 프로그램 순서도 및 결과

위의 두가지 방식으로 프로그램을 작성하였지만, 어느 것이 더 좋다고 말할 수는 없습니다. 이벤트의 종류에 따라 최우선적으로 실행이 되어야 하는지, 이벤트를 기억하고 실행을 누락만 하지 않으면 되는 지에 따라 코드 작성 방법이 선택되어야 합니다.

ISR(Interrupt Handler) 함수는 메인 loop() 에서 잠깐 빠져나와 동작을 하기 떄문에, ISR() 함수 내에서 최소한의 코드만 수행되어야 하는 것이 보편적입니다. 하지만, 용도에 따라, 코드작성에 따라 유연하게 사용이 가능합니다. 

문제점 : 디바운스 소개

위 프로그램 실행 결과 스위치를 한번 눌려질 때 스위치의 물리적인 진동에 의해 접촉면이 붙었다가 떨어지는 현상이 발생합니다. 이런 현상을 채터링(Chattering) 이라고 하고 방지하기 위해 디바운스라는 방법을 사용합니다. 해결 방법으로 회로조치, 소프트웨어 코드 추가 등의 방법이 있고, 일반적으로 두가지 모두 사용합니다.


마무리

본 포스트는 인터럽트 방식으로 스위치를 입력 받아 LED를 제어하는 코드에 대해 알아보았습니다. 사용자가 결정하는 버튼 동작 인터럽트 우선순위에 따라 2가지 방식의 코드를 소개하였습니다.

이 회로와 코드에서는 채터링 현상을 방지하는데는 한계가 있습니다. 다음 포스트는 소프트웨어적인 방법으로 채터링을 방지하는 디바운스 코드를 소개할 예정입니다.

끝까지 읽어주셔서 감사합니다.^^

관련포스트

👉 아두이노 디지털 입출력 관련글 목록 보기

👉 아두이노 인터럽트 관련글 목록 보기

👉 아두이노 관련글 전체 목록 보기