Serial.readString()함수나 Serial.readStringUntil()함수는 항상 시리얼 타임아웃에 영향을 받기 때문에 전송되는 데이터가 네트워크 문제로 지연이 되는 경우 중간에 끊어져 정상적인 문자열을 받아 처리할 수 없습니다. 그래서 아두이노 우노 보드에서는 시리얼 통신을 통해 시리얼 버퍼에 데이터가 들어오면 serialEvent()함수를 자동으로 호출해줍니다. serialEvent()함수를 이용하여 시리얼 통신을 해보겠습니다.
PC 시리얼 통신 - 시리얼 이벤트
1. serialEvent()함수를 선언합니다. serialEvent()함수에서는 Serial.read()함수를 사용하여 1바이트씩 데이터를 읽어 처리합니다.
void serialEvent() {
Serial.println(Serial.read());
}
serialEvent()함수는 Leonardo, Micro, Yún에서는 작동하지 않습니다.
loop()함수의 내용을 삭제합니다.
void setup() {
Serial.begin(9600);
while (!Serial) {
}
Serial.println("Serial Port Connected.");
}
void loop() {
}
void serialEvent() {
Serial.println(Serial.read());
}
2. 컴파일하고 업로드한 후 시리얼 모니터를 실행합니다.
입력창에 "홍길동"을 입력하고 엔터나 전송 버튼을 누릅니다. 그러면 입력한 한글이 ASCII 코드로 변환되어 9바이트가 시리얼 버퍼로 들어옵니다. 그래서 1바이트씩 출력됩니다.
시리얼 모니터에서는 입력란에 입력 후 전송하기 때문에 입력 데이터가 한번에 전송이 되어 1바이트씩 출력됩니다.
시리얼 모니터에서는 하단에서 첫번째 셀렉트 옵션을 "캐리지 리턴"으로 선택하였기 때문에 Carriage Return('\r')문자의 ASCII코드인 13이 출력됩니다.
참고로,
"새 줄"은 Line Feed('\n')문자의 ASCII코드인 10이 출력됩니다.
"Both NL & CR"은 Carriage Return('\r')문자와 Line Feed('\n')문자의 ASCII코드인 13과 10이 출력됩니다.
PuTTY로 연결하였다면 "홍길동"입력하고 엔터를 치면 "홍"이 입력되고 "길"의 "ㄱ"을 입력하는 순간 전송되기 때문에 1바이트씩 3번 출력되어 237, 153, 141이 출력됩니다. 같은 원리고 "동", "길", 엔터가 입력될때 마다 출력됩니다. 시리얼 모니터와 동일하게 출력됩니다.
그럼 serialEvent()함수에서 Serial.read()함수로 읽은 후 시리얼 버퍼에서 읽을 데이터가 있는지 출력해보겠습니다.
void serialEvent() {
Serial.println(Serial.read());
Serial.println("읽을 데이터의 바이트 수 : " + String(Serial.available()));
}
컴파일하고 업로드한 후 시리얼 모니터를 실행합니다.
입력창에 "홍길동"을 입력하고 엔터나 전송 버튼을 누릅니다. 출력된 걸 보면 8바이트(9바이트에서 1바이트를 읽었기 때문)가 아닌 0바이트가 나옵니다. 그 이유는 serialEvent()함수는 시리얼 버퍼에 데이터가 1바이트라도 있으면 호출되기 때문입니다. 즉 시리얼 버퍼로 데이터가 들어가면서 serialEvent()함수가 호출되기 때문에 순간적으로 시리얼 버퍼에 데이터가 없을 수 있습니다.
serialEvent()함수를 Serial.readStringUntil()처럼 처리하기
serialEvent()함수에서 Serial.readStringUntil()함수처럼 종료 문자인 Carriage Return('\r')이 전송되면 입력된 데이터를 String으로 가져오게 처리하겠습니다.
1. 전역 변수에 String 변수로 버퍼를 선언합니다.
String buffer = "";
2. serialEvent()함수에서는 Serial.read()함소로 읽은 데이터를 char로 형변환하여 String에 추가하고 그리고 읽은 데이터가 종료 문자인지 확인하고 종료 문자이면 버퍼를 출력합니다. 그리고 버퍼의 내용을 지웁니다.
void serialEvent() {
int readByte = Serial.read();
if (readByte == '\r') {
Serial.println(buffer);
buffer = "";
} else {
buffer += (char)readByte;
}
}
3. 컴파일하고 업로드한 후 시리얼 모니터를 실행합니다.
입력창에 "홍길동"을 입력하고 엔터나 전송 버튼을 누릅니다. 입력된 데이터로 정상적으로 출력됩니다.
PuTTY로 연결하여 "홍길동"을 입력하고 엔터를 누르면 시리얼 모니터랑 동일하게 출력됩니다.
터미널 클라이언트가 윈도우에서 엔터를 누르면 Carriage Return('\r')과 Line Feed('\n')이 들어오고
유닉스/리눅스에서 엔터를 누르면 Line Feed('\n')가 들어옵니다.
윈도우나 유닉스/리눅스 구분없이 모든 터미널 클라이언트 처리되게 하고 이전과 같게 수정하겠습니다.
String buffer = "";
void setup() {
Serial.begin(9600);
while (!Serial) {
}
Serial.println("Serial Port Connected.");
Serial.println("이름을 입력하세요.");
}
void loop() {
}
void serialEvent() {
int readByte = Serial.read();
if (readByte == '\r' || readByte == '\n') {
if (buffer != "") {
Serial.println(buffer + "님, 안녕하세요.");
buffer = "";
Serial.println("이름을 입력하세요.");
}
} else {
buffer += (char)readByte;
}
}
버퍼에서 앞/뒤에 붙는 탭이나 스페이스와 같은 화이트 문자를 지우고 싶을 경우에는 trim()함수를 추가하면 됩니다.
void serialEvent() {
int readByte = Serial.read();
if (readByte == '\r' || readByte == '\n') {
if (buffer != "") {
buffer.trim(); // trim 추가
Serial.println(buffer + "님, 안녕하세요.");
buffer = "";
Serial.println("이름을 입력하세요.");
}
} else {
buffer += (char)readByte;
}
}
컴파일하고 업로드한 후 시리얼 모니터를 실행하여 테스트합니다.
PuTTY로 연결하여 동일하게 테스트합니다. 시리얼 모니터랑 동일하게 출력됩니다.
시리얼 통신으로 입력되는 데이터 처리는 serialEvent()함수를 통해서 처리하고 loop()함수에서는 디지털 입력/출력 처리나 센서 입력처리를 나누어서 처리하면 효율이 좋을 것 같습니다.
'코딩교육-아두이노' 카테고리의 다른 글
아두이노 디지털 핀 (LED 배열 제어) - Arduino Digtal Pin - LED Array Control (0) | 2022.01.15 |
---|---|
아두이노 디지털 핀 (LED 제어) - Arduino Digtal Pin - LED Control (0) | 2022.01.15 |
아두이노 스케치 시작 (PC 시리얼 통신) - Arduino Serial Communication - PuTTY (0) | 2022.01.09 |
아두이노 스케치 시작 (PC 시리얼 통신) - Arduino Serial Communication - Hello, Arduino (0) | 2022.01.02 |
아두이노 통합 개발 환경 기능 이해 2 - Arduino IDE (0) | 2021.12.31 |