본문 바로가기
HW 프로그래밍/아두이노

sprintf 표현법

by N2info 2021. 1. 18.

서식에 맞춰 시리얼 모니터에 출력하기 위하여 sprintf(...) 함수를 종종 사용하는데, 정수(%d), 문자(%c), 문자열(%s), 16 진수 값들(%x 혹은 %X)은 별 문제가 없는데 부동 소수 값(%f)을 출력하면 시리얼 모니터에 "?"만 출력 됩니다.

void setup() {
  // 여기에 초기화 부분을 넣어 주세요. 이것은 한번만 실행됩니다.
  char buf[32];
  float t1 = 29.15;

  Serial.begin(9600);
  sprintf(buf, "T1 온도: %3.2f℃", t1);
  Serial.println(buf);
}

void loop() {
  // 여기에 주 처리 부분을 넣어 주세요. 이것은 반복 실행됩니다.

}

 

1. String(float, [precision]).c_str()

String(float, [precision]).c_str() 함수를 사용하면 쉽게 부동 소수를 문자열로 바꿔 출력할 수 있습니다. precision은 부동 소수점 아래 숫자를 몇 자리까지 출력할 것인지 결정을 위한 값이며 이를 넣지 않으면 기본으로 2 자리 숫자가 출력 됩니다

void setup() {
  // 여기에 초기화 부분을 넣어 주세요. 이것은 한번만 실행됩니다.
  char buf[32];
  float t1 = 29.15;
  float t2 = 100.0;

  Serial.begin(9600);

  sprintf(buf, "T1 온도: %8s℃", String(t1, 1).c_str());
  Serial.println(buf);
  sprintf(buf, "T2 온도: %8s℃", String(t2, 2).c_str());
  Serial.println(buf);
}

void loop() {
  // 여기에 주 처리 부분을 넣어 주세요. 이것은 반복 실행됩니다.

}

 

2. dtostrf(double, width, precision, buffer)

부동 소수 값을 C 문자열로 바꿔 주는 dtostrf(...) 함수를 사용하여도 같은 결과를 얻을 수 있습니다:

void setup() {
  // 여기에 초기화 부분을 넣어 주세요. 이것은 한번만 실행됩니다.
  char buf[32];
  char temp[8];
  
  float t1 = 29.15;
  float t2 = 100.0;
  
  Serial.begin(9600);

  dtostrf(t1, 3, 1, temp);
  sprintf(buf, "T1 온도: %8s℃", temp);
  Serial.println(buf);
  dtostrf(t2, 3, 2, temp);
  sprintf(buf, "T2 온도: %8s℃", temp);
  Serial.println(buf);
}

void loop() {
  // 여기에 주 처리 부분을 넣어 주세요. 이것은 반복 실행됩니다.

}

 결과

 

sprintf(char *buf, const char *format, ...) 함수에서 format 문자열은 buf에 저장되는 문자열의 서식(형식)을 지정하기 위하여 사용됩니다. format%[flags][width][.precision][length]specifier로 이뤄집니다.  

아두이노에서 지원되는 서식은 성능과 효율성을 위하여 제한적입니다.

서식(format) 양식
%[flags][width][.precision][length]specifier
flags
-	사용되는 width 안에서 왼쪽 정렬

+	+와 - 기호를 숫자 앞에 강제로 출력 

# 	o, x 혹은 X 서식 지정자(specifier)와 같이 사용. 숫자 앞에 0, 0x, 혹은 0X 등을 붙임 

0 	숫자 앞에 0을 붙임. 0와 공백 문자는 사용된 width 보다 작을 때 붙여 짐
width
숫자 출력할 정수 혹은 문자열의 최소 폭을 지정. 

폭보다 출력 되는 숫자 혹은 문자열이 작을 경우 ' '(공백 문자)가 앞에 붙음. 
<- 0 flag이 붙은 숫자는 0가 붙음
.precision
숫자 d, i, o, u, x 혹은 X 서식 지정자와 같이 사용되어 
최소 출력 되는 숫자 길이를 지정하며, 
작을 경우 앞에 0을 붙임. 숫자 길이가 긴 경우 잘려 출력 되는 경우는 없음.
length (혹은 modifier를 사용)
h 	i, d 혹은 u 서식 지정자와 같이 사용되어 short 값을 출력할 때 사용 
l 	i, d 혹은 u 서식 지정자와 같이 사용되어 long int 혹은 unsigned long int 값을 출력할 때 사용
specifier
c 	글자(char)를 출력 d 부호가 있는 정수 값 출력 
i 	부호가 있는 정수 값 출력 
u 	부호가 없는 정수 값 출력 
o 	8 진수 부호가 없는 정수 값 출력 
x 	16 진수 부호가 없는 정수 값 출력. 
	a ~ f 소문자가 출력 됨. 
X 	16 진수 부호가 없는 정수 값 출력. 
	A ~ F 대문자가 출력 됨. 
p 	포인터 값이 16 진수 값으로 출력 되며, 
	x 지정자를 사용한 것과 같이 소문자로 출력 됨 s 문자열을 출력
 

스케치

간단하게 여러 format으로 출력하는 예제 스케치를 만들어 시험하여 보았습니다:

/* 
 * sprintf2 
 * 
 * 이 스케치는 sprintf 함수를 이용하여 문자, 숫자들, 포인터, 그리고 
 * 문자열을 서식(양식)에 맞춰 출력한 예제입니다. 
 * 
 * 이 예제 코드는 공유 저작물입니다. 
 * 
 */ 
 
 #define MAX_TYPE(type) ((type)(pow(2, sizeof(type) * 8 - 1) - 1)) 
 #define MAX_INT MAX_TYPE(int) 
 #define MAX_LONG MAX_TYPE(long) 
 
 void setup() { 
 	// 여기에 초기화 부분을 넣어 주세요. 이것은 한번만 실행됩니다. 
    char buf[80]; 
    
    Serial.begin(9600); 
    Serial.println("sprintf() 예제 2"); 
    Serial.println("================"); 
    sprintf(buf, "문자들: '%c', '%c'", 'a', (char)97);	Serial.println(buf); 
    sprintf(buf, "숫자들: %10i, %li", MAX_INT, MAX_LONG); Serial.println(buf); 
    sprintf(buf, "숫자들: %d, %ld", MAX_INT, MAX_LONG); Serial.println(buf); 
    sprintf(buf, "숫자들: %d, %ld", (unsigned int)(MAX_INT + 1), (unsigned long)(MAX_LONG + 1)); Serial.println(buf); 
    sprintf(buf, "숫자들: %u, %lu", (unsigned int)(MAX_INT + 1), (unsigned long)(MAX_LONG + 1)); Serial.println(buf); 
    sprintf(buf, "' ' 문자를 앞에 넣은 숫자: %10d", MAX_INT); Serial.println(buf); 
    sprintf(buf, "'0' 문자를 앞에 넣은 숫자: %010d", MAX_INT); Serial.println(buf); 	
    sprintf(buf, "왼쪽 정렬: %-10d %ld", MAX_INT, MAX_LONG); Serial.println(buf); 
    sprintf(buf, "오른쪽 정렬: %10d %ld", MAX_INT, MAX_LONG); Serial.println(buf); 
    sprintf(buf, "오른쪽 정렬: %10.8d %ld", MAX_INT, MAX_LONG); Serial.println(buf); 
    sprintf(buf, "+ 기호: %+10d %+ld", MAX_INT, MAX_LONG); Serial.println(buf); 
    sprintf(buf, "진수들: %04d %04o %#4o %04x %#4x %04X %#4X", 254, 254, 254, 254, 254, 254, 254); Serial.println(buf); 
    sprintf(buf, "진수들: %4d %4o %#4o %4x %#4x %4X %#4X", 254, 254, 254, 254, 254, 254, 254); Serial.println(buf); 
    sprintf(buf, "포인터: %p", &buf); Serial.println(buf); 
    sprintf(buf, "문자열: %s", "아두이노"); Serial.println(buf); 
} 

void loop() { 
	// 여기에 주 처리 부분을 넣어 주세요. 이것은 반복 실행됩니다. 
    
}
실행

스케치를 업로드하고 시리얼 모니터를 열면 다음과 같은 결과를 얻을 수 있습니다: