HOWTO · Arduino
Arduino printf 함수
sprintf() 함수와 Serial.print() 함수를 사용하여 printf()와 동일한 출력을 얻을 수 있습니다.
이 페이지의 내용
표준 Arduino 프로그래밍 환경은 시리얼 모니터에 출력하는 이식성 있는 printf() 호출을 제공하지 않습니다. 일부 보드 코어에는 자체 Serial.printf() 메서드가 있으므로 사용 중인 보드의 문서를 확인하세요. 이식성 있는 스케치에서는 sprintf()로 문자 버퍼에 형식을 지정한 다음 Serial.print() 또는 Serial.println()으로 전송할 수 있습니다. 형식 문자열이 필요하지 않다면 여러 번의 시리얼 호출로 같은 메시지를 바로 구성할 수도 있습니다.
Arduino는 printf()를 제공하나요?
모든 Arduino 보드에서 보장되는 단일 printf() 인터페이스는 없습니다. C 라이브러리의 printf()는 보통 표준 출력 스트림에 쓰지만, 마이크로컨트롤러 환경에서는 이 스트림이 시리얼 포트에 연결되지 않을 수 있습니다. 코어별로 Serial.printf()가 제공되기도 하지만, 사용 가능 여부와 지원하는 형식 지정자는 대상에 따라 다릅니다. 아래 스케치는 setup()과 loop()를 사용하고 Serial을 통해 출력합니다. 호스트 측의 간단한 시리얼 대역 객체를 사용하면 Arduino 보드 없이도 같은 예제를 실행할 수 있습니다. 실제 보드에서는 Arduino 코어가 Serial과 스케치 수명 주기를 제공합니다.
sprintf()로 문자열을 만들고 Serial로 전송하기
메시지에 자리 표시자나 여백 채우기가 필요하다면 sprintf()를 사용하세요. 이 함수는 완성된 텍스트를 문자 배열에 쓰고, 이어서 Serial.println()이 그 텍스트와 줄바꿈을 전송합니다. 이 스케치는 배열의 용량을 포매터에 전달하는 snprintf()를 사용하고, 메시지 전체가 들어가는지 확인한 뒤 전송합니다.
#include <cstdio>
#ifdef ARDUINO
#include <Arduino.h>
#else
class HostSerial {
public:
void begin(unsigned long) {}
void println(const char* text) { std::puts(text); }
};
HostSerial Serial;
#endif
void setup() {
Serial.begin(9600);
char buffer[32];
const int value = 42;
const int length = std::snprintf(buffer, sizeof(buffer), "The answer is: %d", value);
if (length >= 0 && static_cast<unsigned int>(length) < sizeof(buffer)) {
Serial.println(buffer);
}
}
void loop() {}
#ifndef ARDUINO
int main() {
setup();
return 0;
}
#endif
The answer is: 42
snprintf()는 끝의 널 문자를 제외하고 기록할 문자 수를 반환합니다. 이 수가 배열 용량 이상이면 스케치는 일부만 잘린 메시지를 전송하지 않습니다. 사용 중인 보드의 C 라이브러리가 snprintf()를 예상대로 제공하는지 확인하세요. 형식 지정 함수의 제공 여부와 동작은 보드와 코어에 따라 달라질 수 있습니다.
Serial.print()로 출력을 구성하기
간단한 라벨과 값만 출력한다면 직접 호출하여 임시 형식 지정 버퍼를 사용하지 않을 수 있습니다. Serial.print()는 같은 줄에 계속 출력하고, Serial.println()은 줄을 끝냅니다. 이 스케치는 시리얼 호출을 이어 같은 줄을 구성합니다.
#include <cstdio>
#ifdef ARDUINO
#include <Arduino.h>
#else
class HostSerial {
public:
void begin(unsigned long) {}
void print(const char* text) { std::printf("%s", text); }
void print(int value) { std::printf("%d", value); }
void print(double value, int digits) { std::printf("%.*f", digits, value); }
void println(const char* text) { std::printf("%s\n", text); }
};
HostSerial Serial;
#endif
void setup() {
Serial.begin(9600);
const int temperature = 25;
const double humidity = 60.5;
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.print(" C, Humidity: ");
Serial.print(humidity, 1);
Serial.println("%");
}
void loop() {}
#ifndef ARDUINO
int main() {
setup();
return 0;
}
#endif
Temperature: 25 C, Humidity: 60.5%
호스트 측 대역 객체는 여기서 사용하는 호출을 모사해 하드웨어 없이도 스케치의 출력 줄을 보여 줍니다. 실제 Arduino 코어는 아닙니다. 보드에서 Serial.print(humidity, 1)은 소수점 아래 한 자리까지 출력하도록 요청하며, 지원되는 정확한 형식은 보드의 Serial 구현에 따라 다릅니다.
부동소수점 값과 버퍼 크기 처리하기
Arduino 코어마다 sprintf()를 통한 부동소수점 형식 지정 동작은 다릅니다. 일부 임베디드 C 라이브러리는 프로그램 메모리를 절약하기 위해 형식화된 입출력에서 부동소수점 변환을 제외합니다. %f에 의존하기 전에 대상 코어를 확인하세요. 코어가 일반적인 Arduino Print 구현을 지원한다면 Serial.print(value, digits) 형식을 대안으로 사용할 수 있습니다.
형식화된 출력은 끝의 \0을 포함해 문자 배열 안에 전부 들어가야 합니다. 사용할 수 있다면 배열의 실제 용량을 지정해 snprintf()를 사용하고, 결과를 쓰기 전에 반환값을 확인하세요. 형식화된 텍스트가 배열보다 길면 버퍼를 늘리거나 메시지를 짧게 줄이세요. 버퍼가 커지면 많은 보드에서 제한적인 RAM을 더 많이 사용합니다.
적절한 방법 선택하기
하나의 형식 문자열로 구조화된 메시지를 더 읽기 쉽게 만들 수 있다면 sprintf() 또는 snprintf()를 선택하고, 결과를 Serial.println()으로 전송하세요. 몇 개의 라벨과 값만 이어 붙이면 된다면 Serial.print() 호출을 선택하세요. 두 방법 모두 시리얼 인터페이스로 텍스트를 보내지만, 모든 보드에서 같은 형식 지정 기능을 보장하지는 않습니다. 컴파일 대상 보드의 코어별 메서드와 부동소수점 동작을 확인하세요.