아두이노(Arduino)의 프로그램 언어는 C/C++를 사용합니다.
작성된 프로그램을 스케치(Sketches)라고 하고 파일은 .ino로 저장됩니다.
스케치(Sketches)는 setup()과 loop() 함수로 구조가 단순하게 구성되어 있습니다.
void setup() {
}
void loop() {
}
setup() 함수
아두이노(Arduino) 보드가 실행되면 처음에 한번만 실행되는 함수입니다. 그리고 리셋 버튼이 눌러지면 동일하게 한반만 실행됩니다.
라이브러리 설정, 핀모드 설정, 변수 설정등 초기화 하는 셋업 코드를 작성합니다.
loop() 함수
setup()함수가 실행된 후 반복되는 함수입니다.
보드의 디지털 핀과 연결된 센서로 부터 정보를 가져오거나 연산을 한 후 결과를 출력하는 코드를 작성합니다.
전역 변수
전역으로 사용할 변수를 선언합니다. setup()함수 이전에 선언합니다.
참고로, setup()함수, loop()함수에서 사용하는 변수는 지역 변수로 함수를 벗어나 사용할 수 없습니다.
다음은 아두이노 IDE에서 제공하는 예제인 BareMinimum(최소한)의 소스입니다.
메뉴 : 파일 > 예제 > 01. Basics > BareMinimum
컴파일하고 업로드하여 실행할 수 있는 기본 구조의 스케치 코드입니다. 업로드하여 실행보면 아무런 동작도 하지 않습니다.
void setup() {
// put your setup code here, to run once:
}
void loop() {
// put your main code here, to run repeatedly:
}
PC 시리얼 통신 출력 - Hello, Arduino
1. PC와 연결된 포트로 시리얼 통신하기 위해서는 setup()함수에 Serial.begin()함수를 사용해야 합니다. Serial.begin()함수의 파라메타로 통신속도를 설정해야 합니다. 통신속도는 9600(Baud Rate - 보드 레이트)으로 설정하였습니다.
void setup() {
Serial.begin(9600);
while(!Serial) {
}
Serial.println("Serial Port Connected.");
}
Baud Rate(보드 레이트)는 초당 Symbol(심볼)이 전송되는 속도입니다. 통신 단위는 초당 신호(Signal) 요소의 수입니다.
시리얼 통신에서는 Data bit가 8-bit입니다. 그래서 Symbol(심볼)은 8-bit입니다.
9600(Baud Rate)이면 초당 8-bit를 9600개가 전송되는 겁니다.
통신속도는 300(Baud Rate) ~ 2,000,000(Baud Rate)으로 설정할 수 있습니다.
일반적으로 9600(Baud Rate)를 사용합니다.
시리얼이 정상적으로 연결될 때까지 대기하기 위해서 무한 루프로 대기하게 합니다. 무한 루프 처리를 위해 while()문을 사용하여 시리얼이 연결되지 않으면 while()문을 유지하고 시리얼이 연결되면 while()문을 종료하게 됩니다. 짧은 시간안에 연결되기 때문에 while()문은 없어도 됩니다.
시리얼이 연결되면 Serial.println()함수를 사용하여 연결 상태를 시리얼로 출력합니다.
2. 시리얼 통신으로 "Hello, Arduino"가 출력되게 loop()함수에서 Serial.println()함수를 사용합니다.
1초 마다 시리얼 통신으로 출력하기 위해서는 delay()함수로 대기시켜야 합니다. delay()함수는 밀리초(millisecond)로 설정해야 합니다. 1초는 1000밀리초(millisecond)입니다.
void loop() {
Serial.println("Hello, Arduino");
delay(1000);
}
3. 툴바의 확인 버튼이나 메뉴의 [스케치 > 확인/컴파일]을 클릭하여 컴파일 합니다.
컴파일이되면 스케치 프로그램의 크기를 콘솔로 알려줍니다.
4. 툴바의 업로드 버튼이나 메뉴의 [스케치 > 업로드]을 클릭하여 아두이노 우노 보드로 업로드합니다.
5. 툴바의 시리얼 모니터 버튼이나 메뉴의 [툴 > 시리얼 모니터]를 클릭하여 시리얼 모니터를 실행시킵니다.
그러면 1초마다 "Hello, Arduino"가 출력됩니다.
시리얼 모니터 하단에 있는 "타임스팸프 표시"를 체크하면 출력 시간이 표시됩니다.
시리얼 통신을 계속함으로 아두이노 우노 보드는 TX가 주황색으로 불이 들어옵니다.
PC 시리얼 통신 - 입력과 출력
1. PC와 연결된 포트로 전송을 받기 위해서는 Serial.available()함수를 사용하여 전송이 될 때까지 무한 루프로 대기하게 합니다. 무한 루프 처리를 위해 while()문을 사용하여 조건이 true이면 while()문을 유지하고 false이면 while()문을 종료하게 됩니다.
Serial.available()함수는 시리얼 버퍼에 수신된 데이터의 바이트 수를 리턴합니다. 그래서 리턴된 값이 1이상이면 대기(무한 루프)를 종료합니다.
Serial.readString()함수를 사용하여 시리얼 버퍼에서 입력된 데이터를 읽어서 String으로 가져옵니다.
Serial.readString()함수는 String를 리턴하고 시리얼 버퍼에서 읽어 들인 데이터는 지웁니다.
void loop() {
Serial.println("이름을 입력하세요.");
while(Serial.available() == 0) {
}
String name = Serial.readString();
Serial.println(name + "님, 안녕하세요.");
}
또는 Serial.readStringUntil()함수를 사용하여 시리얼 버퍼에서 종료 문자로 Line Feed('\n')문자 전까지 전송된 데이터를 읽어서 String으로 가져옵니다.
Serial.readStringUntil()함수는 String를 리턴하고 시리얼 버퍼에서 읽어 들인 데이터는 지웁니다.
void loop() {
Serial.println("이름을 입력하세요.");
while(Serial.available() == 0) {
}
String name = Serial.readStringUntil('\n');
Serial.println(name + "님, 안녕하세요.");
}
2. 컴파일하고 업로드한 후 시리얼 모니터를 실행합니다.
시리얼 모니터 출력에 "이름을 입력하세요."라고 나옵니다. 입력창에 "홍길동"을 입력하고 엔터나 전송 버튼을 누릅니다. 그러면 1초 후 입력된 이름으로 인사말인 "홍길동님, 안녕하세요."라고 출력됩니다. 그리고 다시 "이름을 입력하세요."가 출력됩니다.
Serial.readString() vs Serial.readStringUntil()
Serial.readString()함수는 시리얼 버퍼에 데이터가 전송된 후 시리얼 타임아웃 시간안에 추가로 데이터가 전송되지 않으면 시리얼 버퍼에서 데이터를 읽어서 String으로 가져옵니다.
기본적으로 시리얼 타임아웃 시간은 1000밀리초(millisecond)입니다. 즉 1초 동안 추가 데이터가 전송되지 않아야 합니다. 만약, 시리얼 타임아웃 시간안에 추가로 데이터가 전송되면 다시 1초 동안 대기합니다.
예를 들어, "홍길동" 전송후 1초가 되기전에 "고길동"을 다시 전송하였다면 추가로 전송된 데이터까지 읽어 리턴합니다.
이름을 입력하세요.
홍길동고길동님, 안녕하세요.
그래서 연속으로 오는 데이터를 구분하여 처리해햐 한다면 Serial.readString()함수 대신 Serial.readStringUntil()함수를 사용해야 합니다.
만약, 데이터가 규칙적이라면 Serial.readBytes()함수를 사용하는 것이 좋습니다.
Serial.readStringUntil()함수는 시리얼 타임아웃 시간안에 종료 문자로 지정한 Line Feed('\n')문자가 전송되면 Line Feed('\n')문자 전까지 시리얼 버퍼에서 데이터를 읽어서 String으로 바로 가져옵니다. 즉, 종료 문자(Line Feed - '\n')뒤에 추가적인 데이터가 있어도 종료 문자(Line Feed - '\n') 전까지만 읽고 리턴합니다. 그리고 다시 읽습니다.
예를 들어, "홍길동\n고길동"을 입력하여 전송하였다면 시리얼 버퍼에서 "홍길동"을 읽어 처리 한 후 다시 시리얼 버퍼에서 "고길동"을 읽어 처리합니다.
다만, 시리얼 모니터에서 "홍길동\n고길동"을 입력하여 전송하면 종료 문자로 지정한 Line Feed('\n')문자로 인식하지 않고 문자 '\'과 문자 'n'으로 인식하여 "홍길동\n고길동님, 안녕하세요."로 출력됩니다.
시리얼 모니터가 아닌 프로그램에서 처리하면 분리되어 처리됩니다.
시리얼 모니터에서 테스트하기 위해 종료 문자를 Line Feed('\n')문자에서 느낌표('!')문자로 변경해서 처리해보겠습니다.
void loop() {
Serial.println("이름을 입력하세요.");
while(Serial.available() == 0) {
}
String name = Serial.readStringUntil('!');
Serial.println(name + "님, 안녕하세요.");
}
업로드한 후 시리얼 모니터 입력란에 "홍길동!고길동"을 입력하고 엔터나 전송 버튼을 누립니다.
이름을 입력하세요.
홍길동님, 안녕하세요.
이름을 입력하세요.
고길동님, 안녕하세요.
이름을 입력하세요.
그러면 "홍길동님, 안녕하세요."이 출력된 후 1초 후에 "고길동님, 안녕하세요."이 출력됩니다.
"홍길동"처리 후 바로 "고길동"이 처리되지 않는 이유는 종료 문자로 지정한 느낌표('!')문자가 "고길동" 뒤에 없기 때문입니다.
"홍길동!고길동!"으로 다시 입력하여 전송하면 바로 처리되는 것을 확인할 수 있습니다.
가변의 입력된 데이터가 즉시 처리되기 위해서는 Serial.readStringUntil()함수를 사용하 것이 좋습니다.
그럼, Serial.readStringUntil()함수를 사용하고 시리얼 모니터에서 전송 즉시 처리하게 하기 위해서 어떻게 해야 할까요?
어떻게 데이터 뒤에 종료 문자로 지정한 Line Feed('\n')문자가를 어떻게 포함해서 전송할 수 있을까요?
시리얼 모니터 하단에서 첫번째 셀렉트 옵션이 데이터를 전송할 때 추가로 전송할 문자를 선택하게 해줍니다.
"line ending없음"은 입력 데이터 뒤에 아무런 데이터를 추가하지 않고 전송합니다.
"새 줄"은 입력 데이터 뒤에 Line Feed(\n)를 추가하여 전송합니다. "새 줄"은 영어로 New Line(NL)입니다.
"캐리지 리턴"은 입력 데이터 뒤에 Carriage Return(\r)를 추가하여 전송합니다.
"Both NL & CR"은 입력 데이터 뒤에 Carriage Return(\r)과 NL인 Line Feed(\n)이 추가하여 전송합니다.
"새 줄"으로 선택하고 전송하면 Serial.readStringUntil()함수에서는 Line Feed('\n')문자 전까지 시리얼 버퍼에서 데이터를 읽어서 String으로 바로 가져올 겁니다.
참고로, 시리얼 타임아웃 시간은 Serial.getTimeout()함수의 리턴값으로 확인할 수 있습니다.
void setup() {
Serial.begin(9600);
Serial.println("시리얼 타임아웃 시간 : " + String(Serial.getTimeout()) + "ms");
}
또한, Serial.setTimeout()함수로 시리얼 타임아웃 시간을 설정할 수 있습니다.
그렇지만, Serial.readString()함수는 시리얼 타임아웃 시간을 너무 짧게 설정되면 데이터를 끈어서 읽는 현상이 발생됩니다.
void setup() {
Serial.begin(9600);
Serial.setTimeout(1);
Serial.println("시리얼 타임아웃 시간 : " + String(Serial.getTimeout()) + "ms");
}
시리얼 타임아웃 시간 : 1ms
이름을 입력하세요.
⸮님, 안녕하세요.
이름을 입력하세요.
⸮님, 안녕하세요.
이름을 입력하세요.
⸮길동님, 안녕하세요.
이름을 입력하세요.
Serial.getTimeout()함수는 사용 가능하나 공식 사이트의 Serial 함수 리스트에는 표시되어 있지 않습니다. 혹시 모르니 참고만 하시길 바랍니다.
PC 시리얼 통신 - 바이트 단위로 읽기
Serial.available()함수의 리턴 값을 바로 출력하면 항상 1만 나옵니다. 그 이유는, 시리얼 버퍼가에 1바이트만 있어도 Serial.available()함수는 리턴하기 때문입니다. 그래서 delay()함수로 1초간 대기를 걸어주고 다시 Serial.available()함수를 호출하여 받으면 정상적으로 입력(전송)된 전체 바이트를 알 수 있습니다.
1. 바이트 단위로 읽기 위해서는 Serial.read()함수를 사용합니다. 그러면 1바이트를 읽어 리턴하고 시리얼 버퍼에서 읽은 1바이트는 지웁니다.
void loop() {
Serial.println("이름을 입력하세요.");
while (Serial.available() == 0) {
}
delay(1000);
int dataLength = Serial.available();
Serial.println("읽을 데이터의 바이트 수 : " + String(dataLength));
while (dataLength > 0) {
int value = Serial.read();
Serial.println(value);
dataLength = Serial.available();
Serial.println("읽을 데이터의 바이트 수 : " + String(dataLength));
}
}
2. 컴파일하고 업로드한 후 시리얼 모니터를 실행합니다.
시리얼 모니터 출력에 "이름을 입력하세요."라고 나옵니다. 입력창에 "홍길동"을 입력하고 엔터나 전송 버튼을 누릅니다.
입력된 데이터가 한글이고 인코딩이 UTF-8이기 때문에 읽을 데이터의 바이트 수가 9로 나옵니다.
읽은 바이트를 출력하면 237, 153, 141, 234, 184, 184, 235,143,153이 출력됩니다.
출력 값을 16진수로 계산하면 ED, 99, 8D, EA, B8, B8, EB, 8F, 99입니다.
한글을 UTF-8로 인코딩해서 인코딩 ASCII 코드로 변환하면 바이트 단위로 %XX%XX%XX로 변환됩니다.
그래서 3바이트씩 나눠서 16진수에 "%"를 붙이면 %ED%99%8D, %EA%B8%B8, %EB%8F%99가 됩니다.
ASCII 코드를 UTF-8로 디코딩하면 %ED%99%8D -> 홍, %EA%B8%B8 -> 길, %EB%8F%99 -> 동이 됩니다.
'코딩교육-아두이노' 카테고리의 다른 글
아두이노 스케치 시작 (PC 시리얼 통신) - Arduino Serial Communication - serialEvent (0) | 2022.01.09 |
---|---|
아두이노 스케치 시작 (PC 시리얼 통신) - Arduino Serial Communication - PuTTY (0) | 2022.01.09 |
아두이노 통합 개발 환경 기능 이해 2 - Arduino IDE (0) | 2021.12.31 |
아두이노 통합 개발 환경 기능 이해 1 - Arduino IDE (0) | 2021.12.31 |
아두이노 통합 개발 환경 설치 - Arduino IDE 1.8.18 (0) | 2021.12.19 |