아두이노 강좌 #6 시리얼 통신 3. UART 수신 프로그래밍
Lucy Archive
Lucy / Facilitate4U
2020. 7. 5. 01:13
Arduino EchoArduino Echo

아두이노 시리얼(UART) 통신 수신

  지난 포스트에서는 아두이노 시리얼 통신 출력에 대해 알아보았습니다. 시리얼 출력은 Serial.print(), Serial.println(), Serial.write() 등의 함수를 사용하여 간단하게 구현이 가능했습니다. 시리얼 수신 코드를 작성 하는 방법은 송신에 비해 다소 복잡합니다. 우리가 외국어를 공부하더라도, 간단한 말하기는 배우기만 하면 써먹을 수 있지만, 듣는 것은 더 어러운 것과 비슷한 이치입니다. 본 포스트에서는

시리얼 통신 수신하는 방법을 알아보고, 간단한 여러 예제

를 작성해 보겠습니다.

UART 송신/수신 비교

  시리얼 통신은 일상에서 대화와 비슷합니다. 말하는 것은 내가 원하는 말과 타이밍을 말을 하면 되지만, 듣는 것은 상대방이 언제 얘기할지 모르고, 무슨 말을 할지 모르기 때문에 듣고 해석해야 하고, 말이 길어지면 지속적으로 집중에서 그 말을 해석해야 합니다.

외국어 말하기 듣기 대조외국어 말하기 듣기 대조

  시리얼 통신도 마찬가지 입니다. 데이터 송신은 내가 보낼 데이터를 내가 원하는 타이밍에, 아두이노에서 제공된 출력 함수로 데이터를 송신하면 됩니다. 시리얼 수신 언제 어떤 얼마나 큼 데이터가 연속으로 올지 모르기 때문에, 시리얼 수신 처리는 송신보다 다소 복잡합니다.

UART 송신 수신 대조UART 송신 수신 대조


UART 수신 프로그램 작성 방법

  시리얼 데이터가 수신 되면 되는 일을 알아 보고, 어떻게 수신된 데이터를 처리할 수 있을지 확인 합니다. 아두이노에서 제공되는 Serial 수신 관련 함수들이 수신된 데이터 처리에 어떻게 사용되는지 알아보겠습니다.

UART 데이터 수신 되면 벌어지는 일

우편 도착과 유사한 시리얼 데이터 수신우편 도착과 유사한 시리얼 데이터 수신

데이터가 수신 과정은 우편 도착 과정과 비슷합니다. 우편이 도착하고, 우편을 확인하는 과정은 아래와 같습니다.

  • 편지가 도착하면 지정된 우편함에 보관
  • 우편함이 크기는 정해져 있음
  • 이미 도착한 편지도 있을 수 있음
  • 우편함이 가득차 편지를 재대로 못 받는 일을 방지하기 위해
    • 우편함을 자주 또는 주기적으로 확인
    • 우편이 도착하면 알람을 받는 받아서 바로 받은 우편 찾기
    • 확인 한 우편은 꺼내서 버리거나 다른데 보관하기
  • 받은 우편함은 내가 필요한 우편일 수 있고, 필요 없는 우편일 수 있다.

UART 로 데이터가 수신 처리 과정의 이벤트도 이와 유사합니다.

  • 수신된 데이터는 MCU 내부 지정된 수신 버퍼에 저장됨
  • 수신 버퍼의 크기도 정해져 있음
  • 수신 버퍼에 이전에 수신 된 데이터가 차지 할 수 있음
  • 버퍼에 데이터가 가득차 있으면 새로운 데이터 저장 불가
    • 수신 버퍼에 저장된 데이터가 있는지 자주 또는 주기적으로 확인
    • 수신 인터럽트 활성화
    • 수신 버퍼의 데이터 확인 후 비워주기
  • 수신 버퍼의 데이터에 따라 프로그램 동작

UART 수신 처리 프로그래밍 순서(Polling 방식)

아두이노에서 UART 수신 처리를 하기 위해 주로 Polling 방식과 Interrupt 방식이 있습니다. 본 포스트에서는 Polling 방식만 다루고, Interrupt 방식은 사전에 추가 설명이 필요하여 추후 포스트에 설명하도록 하겠습니다.

Polling 방식

  • 시리얼 포트를 초기화 : Serial.begin()
  • 수신 버퍼에 데이터가 있는지 확인 : if(Serial.available() > 0)
  • 데이터를 읽고, 읽은 데이터 수신 버퍼에서 지우기 : Serial.read()

Interrupt 방식

  • 시리얼 포트를 초기화 : Serial.begin()
  • 수신 인터럽트 활성화 : 아두이노에서는 불필요
  • 시리얼 수신 될 때 Call 되는 함수에 프로그램 작성 : serialEvent()
  • 데이터를 읽고, 읽은 데이터 수신 버퍼에서 지우기 : Serial.read()

UART 수신 관련 아두이노 함수 사용법

  UART 수신 관련 함수의 종류[각주:1]는 많이 있지만, 일반적으로 사용하기 쉬운 2가지 함수만 소개합니다. 보통의 경우 Serial.available() 함수와 Serial.read() 함수가 세트로 많이 사용됩니다. Serial.available() 함수는 시리얼 포트로 수신 된 데이터가 있는지 확인하고, Serial.read() 함수는 수신 버퍼에 저장된 데이터 1바이트를 읽고, 읽은 데이터를 수신 버퍼에서 삭제합니다. 

Serial.available()

시리얼 수신 버퍼에 저장된 데이터가 있는지 확인합니다.

Syntax

  • Serial.print()

Parameters : 없음

Returns : 수신 버퍼에 저장된 데이터 수를 반환

Example

  • if(Serial.available() > 0) : 수신 된 데이터가 있는 지 확인

Serial.read()

수신 버퍼에 저장된 데이터 1바이트를 읽고, 수신 버퍼에서 읽은 데이터를 지웁니다.

Syntax

  • Serial.read()

Parameters : 없음

Returns : 수신 버퍼에서 1바이트를 반환 합니다. (Datatype : int)

Example

  • Serial.print("Hello world!") : "Hello world!" 문자열을 출력
  • Serial.print(65) : 숫자 65를 문자열 "65" 로 출력
  • Serial.print(65, HEX) : 숫자 65를 16진수 "41"(0x41)로 출력
  • Serial.print(3.141592) : 실수 3.141592 를 소수점 2자리 "3.14"를 출력
  • Serial.print(3.141592, 4) : 실수 3.141592 를 소수점 4자리 "3.1415"를 출력

UART 수신 함수 사용해보기

Serial Echo

시리얼 포트로 수신 된 데이터를 그대로 출력으로 송신하는 예제 입니다.

1
2
3
4
5
6
7
8
9
10
11
void setup(){
    Serial.begin(9600);
    Serial.println("Echo Program Start...\n");
}
 
void loop(){
    if(Serial.available() > 0){ // 수신 버퍼에 수신된 데이터가 있는 경우..
        Serial.write(Serial.read()); // 1바이트 수신한 데이터를 송신..
        Serial.write("\n");
    }
}
cs

Serial Echo2

위의 Serial Echo 프로그램에서 시리얼 모니터에서 포기 편한 방식의 프롬프트를 추가한 버전입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int iRev; // 시리얼 수신 데이터 임시 저장소
 
void setup(){
    Serial.begin(9600);
    Serial.println("Echo Program Start...\n");
}
 
void loop(){
    if(Serial.available() > 0){ // 수신 버퍼에 수신된 데이터가 있는 경우..
        iRev = Serial.read();
        
        // Serial 입출력 확인 시켜주기 위한 터미널 프롬프트 추가
        Serial.print("PC -> Arduino : ");
        Serial.write(iRev);
        Serial.write("\n");
        Serial.print("Arduino -> PC : ");
        Serial.write(iRev);
        Serial.write("\n");
    }
}
cs

Serial Echo2 프로그램 실행 결과Serial Echo2 프로그램 실행 결과

Serial Data 수신 받아 LED 켜고 끄기

아래 코드는 시리얼 포트로 1을 입력 받으면 LED를 켜고, 0을 입력 받으면 LED 를 끄는 예제 코드 입니다.

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
int iRev;
 
void setup(){
    pinMode(13OUTPUT);
    Serial.begin(9600);
    Serial.println("LED Control Program Start...\n");
    Serial.println("Input '1' : LED ON");
    Serial.println("Input '0' : LED OFF");
}
 
void loop(){
    if(Serial.available() > 0){ // 수신 버퍼에 수신된 데이터가 있는 경우..
        iRev = Serial.read();
        
        if(iRev == '1'// 수신한 데이터가 1 인경우
        {
            digitalWrite(13HIGH); // 아두이노 우노 내장 LED 켜기
            Serial.println("LED ON!");
        }
        else if (iRev == '0'// 수신한 데이터가 0인 경우
        {
            digitalWrite(13LOW); // 아두이노 우노 내장 LED 끄기
            Serial.println("LED OFF!");
        }
        else // 수신한 데이터가 1,0 이 아닌 경우
        {
            Serial.println("You have entered an invailid value..");
            Serial.println("Input 0 or 1");
            Serial.println("Input '1' : LED ON");
            Serial.println("Input '0' : LED OFF");
        }
    }
}
cs


마무리

  시리얼 수신 데이터 처리하기 위해 Serial.available() 함수와 Serial.read() 함수에 대해 알아 보고, Echo 프로그램 및 시리얼 통신으로 LED 를 제어하는 예제를 작성해보았습니다.

  지금까지 아두이노 주변 장치(Peripheral) 와 관련된 내용으로 작성하였는데, 좀 더 복잡한 코드 작성 및 응용을 위해서 아두이노 프로그래밍 언어에 대한 포스팅을 진행 후 주변 장치에 대한 내용을 추가적으로 다루겠습니다.

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

관련포스트

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

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



  1. 아두이노 시리얼 관련 함수 : https://www.arduino.cc/reference/en/language/functions/communication/serial/ [본문으로]