[아두이노] [강좌] 16. Serial 통신(2) - 시리얼 통신 함수 알아보기
지난 시간에 Serial.begin() 함수는 알아봤지만 한번 더 간단히 설명하면.
Serial.begin(speed)
Serial.begin(speed, config)
매개 변수
speed : 시리얼 통신 속도. Baud Rate(보레이트)라고 하며 초당 전송되는 비트 수를 말한다.
config : 시리얼 통신 환경을 설정하며, 데이터 길이, 패리티 비트, 정지 비트를 설정한다. |
여기서 통신 속도가 중요하다고 설명했었으며, 데이터 통신을 하는 상대방의 통신 속도와 같아야 한다고 설명했었음.
그럼 이제 초기화를 했으니 사용해보자.
Serial.print(value)
Serial.println(value)
print() 함수 또는 println() 함수는 아두이노에서 데이터를 전송하는 함수이다. print() 또는 println() 함수의 매개 변수로는 여러 가지 타입이 사용될 수 있다. 숫자가 들어갈 수도 있고, 문자가 들어갈 수도 있고, 문자열이 들어갈 수도 있다. value 값으로 들어갈 수 있는 타입이 너무 여러가지라 일단 예제로 설명.
다음 예제를 보자.
SerialPrintTest.ino |
void setup() { Serial.begin(9600); }
void loop() { int i = 65; float f = 65; char c = 65;
Serial.println(i); Serial.println(f); Serial.println(c); Serial.println(“Hello, Arduino!”);
while(1) ; } |
위 예제를 아두이노 보드에 업로드 한 후 시리얼 모니터를 실행해보자. 아래와 똑같이 나오는지 확인해보자.

자, 문자열인 "Hello, Arduino!"는 문자열 그대로 출력된 걸 알겠는데.
int 형의 변수와 float 형의 변수, char 형의 변수에 똑 같은 65를 저장하고 출력을 했는데 다 다르게 출력됐다? int랑 float은 같은 숫자지만 정수냐 실수냐의 차이라 다르게 찍혔다 치고. char 형 변수에 65를 넣었는데 쌩뚱맞게 왠 ‘A’??
Serial을 사용해서 데이터를 전송할 때, 주의해야 하는 점이 바로 이것이다. Serial.print() 함수를 사용할 때 매개 변수의 타입이 무엇인가에 따라 실제로 전송되는 데이터가 달라지기 때문.
왜??
이 것을 이해하기 위해서는 숫자 1과 문자 ‘1’이 다르다는 것을 이해해야 한다.
우리가 사용하는 문자 중 숫자를 나타내는 문자와 알파벳, 그리고 일부 특수 문자들은 컴퓨터 등에서 알아볼 수 있게 각각 고유 번호가 할당되어 있고, 컴퓨터나 아두이노 보드 등에서는 이 고유 번호를 받아 문자로 인식하게 된다. 이 고유 번호를 ‘아스키 코드’라고 한다. (맨 아래 “*참고”를 참조)
알파벳 대문자 ‘A’에 할당된 고유 번호(아스키 코드)가 바로 65이고, 이 값이 문자를 나타내는 char 형 변수에 저장되었기 때문에 65에 해당하는 ‘A’가 시리얼 모니터에 출력된 것.
사실 시리얼 통신은 모든 데이터를 숫자로만 전송할 수 있기 때문에 받는 쪽에서도 숫자로만 받을 수 있다. 즉, 1을 보내든 100을 보내든 받는 쪽에서도 1로만, 100으로만 받을 수 있다는 말. 그리고 시리얼 모니터 프로그램은 그 받은 숫자를 아스키 코드 표와 대조하여 해당하는 문자로만 출력한다.
응?? 이 말대로라면 위 예제에서 int 형으로 65를 보내든, float 형으로 65를 보내든, char 형으로 65를 보내든 받는 쪽에선 똑같이 65를 받기 때문에 셋 다 ‘A’가 찍혀야 하는 것이 아닌가?? 어떻게 int 형인지 float 형인지 char 형인지 알고 다 다르게 찍힌 거지?
이유는, 아두이노가 매우 친절하기 때문이다.
Serial.print() 함수는 매개 변수에 따라 데이터를 다르게 보내기 때문. 즉, Serial.print(i) 했을 때와 Serial.print(f) 했을 때, Serial.print(c) 했을 때의 전송 데이터가 다 다르다는 말.
매개 변수로 char 형 데이터를 받으면 데이터 자체가 문자라는 뜻이므로 그 값 그대로 전송한다. 저장된 65를 그대로 전송하고, 그 데이터를 받은 시리얼 모니터 프로그램은 65에 해당하는 문자인 ‘A’를 출력한다.
하지만 매개 변수로 int 형 데이터를 받으면 아두이노는 그 숫자를 문자열로 바꿔서 보내버린다. i 변수에 숫자 65가 저장되어 있었으므로, 아두이노는 그 값을 문자 ‘6(아스키 코드 54)’과 문자 ‘5(아스키 코드 53)’로 변환하여 두 개의 문자를 보내게 되는 것이다. 그래서 시리얼 모니터 프로그램은 숫자 54와 53을 수신하게 되고, 그에 해당하는 문자인 ‘6’과 ‘5’를 차례로 출력하게 되는 것.
float 형 데이터도 마찬가지이다. 65라는 값을 문자 ‘6’,’5’,’.’,’0’,’0’으로 만들어 총 다섯 개의 문자를 보낸다. 단, 소수점 아래는 두 자리까지만 변환한다.
여기서 중요한 건 매개 변수로 숫자를 넣으면 숫자가 찍히고 문자를 넣으면 문자가 찍힌다는 거! 아두이노는 참 친절하다는 거!!
print() 함수와 println() 함수의 차이는 매개 변수로 전달된 데이터를 출력한 후 줄바꿈을 하느냐, 하지 않느냐의 차이. println() 함수를 사용하면 데이터를 출력한 후 다음 줄로 커서를 이동시킨다.
그럼 시리얼 통신으로 데이터를 보냈으니까, 받는 함수도 알아볼까용? (분위기 전환)
int Serial.available()
데이터를 읽기 전에 우선 수신된 데이터가 있는지 확인부터 해야겠지. available() 함수는 수신 버퍼에 읽지 않은 데이터가 몇 개인지를 반환하며, 매개 변수는 없다.
반환 값
value : 수신된 데이터 중 아직 읽지 않은 데이터의 개수. 새로 수신된 데이터가 없을 경우 0을 반환한다. |
char Serial.read()
수신 버퍼에서 하나의 데이터를 읽어온다. 데이터는 수신된 순서대로 저장되고 읽어온다.
반환 값
data : 새로운 데이터 중 첫 번째 값.
|
데이터를 읽어오는 함수를 직접 사용해볼까? 스케치에 다음 코드를 입력한 후 업로드.
SerialReadTest.ino |
void setup() { Serial.begin(9600); }
void loop() { if(Serial.available() > 0) { char c = Serial.read(); Serial.print("rx : "); Serial.println(c); } } |
시리얼 모니터를 실행한 후 아래에 표시된 부분을 “No line ending”으로 설정하자.

시리얼 모니터에서 아두이노로 데이터를 전송할 때 마지막에 줄바꿈 문자를 자동으로 붙이지 않겠다는 설정이다.
이제 데이터를 보내보자. 맨 위에 있는 입력 창에 보낼 데이터를 쓴 다음 “Send” 버튼을 눌러보자. "Send" 버튼을 누르면 시리얼 모니터 프로그램은 입력된 문자를 아두이노 보드로 전송한다.
난 ‘1’을 보내보고, ‘a’를 보내보고, “Hello”라는 단어도 보내봤다.



오. 다들 위와 같이 나오지요?
setup() 함수에서 Serial 통신을 속도 9600bps로 초기화 한 후, loop() 함수에서 "if(Serial.available() > 0)" 구문으로 수신된 데이터가 있는지 확인한다. 0보다 큰 값이 반환되어 수신된 데이터가 있다고 판단되면 "Serial.read()" 함수로 데이터를 읽어 변수 c에 저장, 그 값을 "rx : "이라는 문자열과 함께 다시 전송한다. 그럼 시리얼 모니터 프로그램은 다시 수신된 데이터를 화면에 출력하게 되는 것.
여기서 read() 함수로 읽은 데이터를 저장하는 변수 타입이 ‘char’ 형태라는 것에 유의하자. ‘a’라는 문자를 char 형 변수로 받아 print() 함수에 썼기 때문에 ‘a’이라는 문자가 시리얼 모니터에 출력된 것이다. 만일 byte 형 또는 int 형의 변수로 받아 print() 함수에 썼다면, 아두이노의 친절에 의해 ‘a’의 아스키 코드 값인 ‘65’가 출력된다. print() 함수에 숫자를 쓰면 숫자가, 문자를 쓰면 문자가 출력된다는 것에 꼭 유의.
뭔가 굉장히 길게 설명을 했지만, 결국 Serial 통신에서 알아야 하는 내용은 다음 세 가지이다.
1. 시리얼 통신을 사용하기 위해서 송신 쪽과 수신 쪽의 보레이트를 같게 설정해야 한다.
2. print()/println() 함수를 사용하여 데이터를 송신한다.
3. available() 함수로 새로 수신된 데이터가 있는지 확인한 후 read() 함수로 읽어온다.
간단하지?
시리얼 통신을 이용해 다른 기기와 데이터를 주고 받기 위해서 알아야 할 내용은 여기까지 만으로도 충분하다.
다음 강좌에서는 이 외에 Serial 통신을 편리하게 사용할 수 있도록 아두이노에서 제공하는 함수들에 대해 더 알아볼꺼임.
그럼 이번 강좌는 여기서 끝! 안녕~