아두이노 강좌 #11 시리얼 UART 수신 인터럽트 serialEvent()
Lucy Archive
Lucy 2023
2020. 7. 10. 02:33

아두이노 시리얼 통신 수신 인터럽트 serialEvent()

  메인 루프의 기능을 충실이 수행하면서, 시리얼 통신에 대한 응답이 우선적으로 처리되어야 하는 경우 또는 시리얼 수신 버퍼에 데이터가 가득차 오버플로우가 생기는 것을 방지하기 위해 시리얼 수신 인터럽트를 사용할 수 있습니다. 본 포스트에서는

Arduino 수신 인터럽트 serialEvent() 사용 방법과 사용 예제

에 대해 작성하였습니다. 

관련포스트

기존 시리얼 통신 방식 또는 인터럽트가 무엇인지 모르시는 분은 아래의 포스트를 참고부탁드립니다. 

2020/07/03 - [Arduino/Basic] - 아두이노 강좌 #4 시리얼 통신 1. 개요 및 Hello World 출력

2020/07/04 - [Arduino/Basic] - 아두이노 강좌 #5 시리얼 통신 2. UART 초기화 및 송신 프로그래밍

2020/07/05 - [Arduino/Basic] - 아두이노 강좌 #6 시리얼 통신 3. UART 수신 프로그래밍

2020/07/09 - [Arduino/Basic] - 아두이노 강좌 #10 디지털핀 인터럽트 (EXTI, digitalPin Interrupt)


시리얼 통신 Polling vs Interrupt 동작 차이

  아래는 시리얼 통신 Echo 프로그램입니다. Echo 프로그램은 수신 된 데이터를 그대로 출력으로 송신하는 프로그램입니다. 아래는 동작하는 코드는 아니지만, 설명을 위해 구성만 갖추었습니다. 시리얼 통신 수신 인터럽트를 사용하기 위해서는 serialEvent() 라는 함수만 사용하면 간단히 구현이 가능합니다.

Echo 프로그램, (좌)폴링방식 (우)인터럽트방식Echo 프로그램, (좌)폴링방식 (우)인터럽트방식

(좌) 순차처리, (우) 인터럽트 처리(좌) 순차처리, (우) 인터럽트 처리

  시리얼 통신으로 데이터는 언제 올지 모르지만, loop()에서 프로그램이 돌아가는 중에 statement2 가 실행되고 난 후 시리얼 포트로 데이터가 들어왔다고 가정합시다. 이 때 (좌)폴링방식으로 처리하는 경우 loop() 문의 순차적인 구조에 따라 Echo 프로그램이 실행되고, (우)인터럽트 방식으로 처리하는 경우 시리얼 통신이 수신되면 loop()문의 하던 일을 멈추고 Echo 프로그램 동작 후 다시 loop() 문에서 멈춘 곳에서 다시 프로그램이 동작하게 됩니다.

  인터럽트를 사용하는 방식이 항상 좋은 것은 아닙니다. 하지만 우선순위로 먼저 처리해야 하는 로직이 있는 경우 인터럽트를 적절히 사용하여 사용자가 원하는 대로 프로그램 코딩이 가능합니다.


serialEvent() 사용 방법

  시리얼 통신 수신 인터럽트를 사용하는 방법은 아래와 같이 시리얼 포트를 초기화 하고, serialEvent() 함수를 사용만 해주시면 됩니다. 시리얼 통신이 수신 되면 동작하는 코드는 serialEvent() 에서 작성하시면 됩니다.

  serialEvent() 함수내에서 변수를 사용해야 하는 경우 아래의 코드와 같이 전역 변수를 사용하고, volatile 로 선언 되어야 합니다. 다른 인터럽트 사용시 모든 ISR 함수 사용 지침과 동일합니다. 아래의 코드도 개념적인 설명을 위한 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
volatile char cRxData;
volatile int iRxFlag;
 
/* 시리얼 인터럽트 방식 */
void setup(){
    Serial.begin(9600);
    Serial.println("Serial Port Connected!");
}
 
void loop(){
    
    if(iRxFlag == 1){
        iRxFlag = 0;
        statement1;
        statement2;
    }
 
}
/* 시리얼 수신 ISR */
void serialEvent(){
    iRxFlag = 1;
    cRxData = Serial.read();
}
cs

※ 주의사항

[각주:1]serialEvent() 함수는 아두이노 보드의 종류에 따라 지원이 되지 않는 경우 있어, Arduino Uno 보드가 아닌 경우 보드지원 여부 확인이 필요합니다.


시리얼 인터럽트 써먹기

예제 : Echo 프로그램

  시리얼 인터럽트를 사용하면, 아래와 같이 loop() 문에 아무 코드가 없어도 동작하는 프로그램을 작성 할 수 있습니다. 사실 이런 프로그램은 거의 없지만, 원리를 이해하기 위한 예제로 생각해주시길 부탁 드립니다.

Serial.write(Serial.read()); 시리얼 수신한 데이터를 바로 송신하는 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
/* 시리얼 인터럽트 방식 */
void setup(){
    Serial.begin(9600);
    Serial.println("Serial Port Connected!");
}
 
void loop(){
}
/* 시리얼 수신 ISR */
void serialEvent(){
    Serial.write(Serial.read());
}
cs

Echo 프로그램 실행 결과Echo 프로그램 실행 결과

예제 : 시리얼 통신으로 내장 LED 제어

  시리얼 통신으로 내장 LED를 제어하는 프로그램입니다. ISR 내에서 전역 변수를 사용해서 처리하는 경우, 아래와 같은 코드 구조로 코드를 작성 할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
volatile boolean state = false;
const int ledPin = 13;
 
void setup(){
    pinMode(ledPin,OUTPUT);
    Serial.begin(9600);
    Serial.println("Serial Port Connected!");
}
 
void loop(){
    digitalWrite(ledPin, state);
}
/* 시리얼 수신 ISR */
void serialEvent(){
    char cTemp = Serial.read();
    if(cTemp == '1'){
        state = true;
    }
    else{
        state = false;
    }
 
}
cs

마무리

  본 포스트에서는 시리얼 폴링 방식과 인터럽트 방식에 대한 차이를 알아보고, 시리얼 수신 인터럽트 ISR 함수 serialEvent() 함수 사용법에 대해 알아보았습니다. 이후의 포스트는 아날로그 입력/출력 방법과 활용에 대해 작성할 예정입니다.

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

관련포스트

👉 아두이노 시리얼 통신 관련글 목록 보기

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

👉 아두이노 전체 포스트 목록 보기 


  1. serialEvent() : https://www.arduino.cc/reference/en/language/functions/communication/serial/serialevent/ [본문으로]