터미널에 인쇄하려는 변수가 있는데 문자열로 인쇄하는 가장 쉬운 방법은 무엇입니까?
현재 나는 다음과 같은 것을한다 :
Serial.print("Var 1:");Serial.println(var1);
Serial.print(" Var 2:");Serial.println(var2);
Serial.print(" Var 3:");Serial.println(var3);
더 좋은 방법이 있습니까?
터미널에 인쇄하려는 변수가 있는데 문자열로 인쇄하는 가장 쉬운 방법은 무엇입니까?
현재 나는 다음과 같은 것을한다 :
Serial.print("Var 1:");Serial.println(var1);
Serial.print(" Var 2:");Serial.println(var2);
Serial.print(" Var 3:");Serial.println(var3);
더 좋은 방법이 있습니까?
답변:
ardprintf
printf
직렬 연결을 통해 시뮬레이션하는 해킹 된 기능입니다 . 이 기능 (맨 아래에 제공)은 기능이 필요한 파일의 시작 부분에 붙여 넣을 수 있습니다. 충돌을 일으키지 않아야합니다.
와 비슷하게 호출 할 수 있습니다 printf
. 이 예제에서 실제로 작동하는 것을 참조하십시오.
void setup()
{
Serial.begin(9600);
}
void loop()
{
int l=2;
char *j = "test";
long k = 123456789;
char s = 'g';
float f = 2.3;
ardprintf("test %d %l %c %s %f", l, k, s, j, f);
delay(5000);
}
예상대로 출력은 다음과 같습니다.
test 2 123456789 g test 2.30
함수 프로토 타입은 다음과 같습니다.
int ardprintf(char *, ...);
함수 호출에서 감지 된 인수 수를 리턴합니다.
이것은 함수 정의입니다.
#ifndef ARDPRINTF
#define ARDPRINTF
#define ARDBUFFER 16
#include <stdarg.h>
#include <Arduino.h>
int ardprintf(char *str, ...)
{
int i, count=0, j=0, flag=0;
char temp[ARDBUFFER+1];
for(i=0; str[i]!='\0';i++) if(str[i]=='%') count++;
va_list argv;
va_start(argv, count);
for(i=0,j=0; str[i]!='\0';i++)
{
if(str[i]=='%')
{
temp[j] = '\0';
Serial.print(temp);
j=0;
temp[0] = '\0';
switch(str[++i])
{
case 'd': Serial.print(va_arg(argv, int));
break;
case 'l': Serial.print(va_arg(argv, long));
break;
case 'f': Serial.print(va_arg(argv, double));
break;
case 'c': Serial.print((char)va_arg(argv, int));
break;
case 's': Serial.print(va_arg(argv, char *));
break;
default: ;
};
}
else
{
temp[j] = str[i];
j = (j+1)%ARDBUFFER;
if(j==0)
{
temp[ARDBUFFER] = '\0';
Serial.print(temp);
temp[0]='\0';
}
}
};
Serial.println();
return count + 1;
}
#undef ARDBUFFER
#endif
** %
문자 를 인쇄하려면 %%
. *를 사용하십시오 .
이제 Github gists 에서 사용할 수 있습니다 .
나는 일반적으로 질문에 두 가지 대답을하지 않을 것이지만, 나는 오늘 이것을 단지 발견 했다 . 여기서 버퍼없이 printf를 사용할 수있다.
// Function that printf and related will use to print
int serial_putchar(char c, FILE* f) {
if (c == '\n') serial_putchar('\r', f);
return Serial.write(c) == 1? 0 : 1;
}
FILE serial_stdout;
void setup(){
Serial.begin(9600);
// Set up stdout
fdev_setup_stream(&serial_stdout, serial_putchar, NULL, _FDEV_SETUP_WRITE);
stdout = &serial_stdout;
printf("My favorite number is %6d!\n", 12);
}
void loop() {
static long counter = 0;
if (millis()%300==0){
printf("millis(): %ld\tcounter: %ld (%02X)\n", millis(), counter, counter++);
delay(1);
}
}
여기에는 여전히 부동 소수점 제한이 있습니다.
편집 : 나는 이것에 대해 약간의 테스트를 할 것이라고 생각했으며 꽤 잘 작동합니다. 포맷 된 출력으로 루프에 더 나은 테스트를 추가했습니다.
serial_putchar
함수에서 return 문을 작성하지 않으 return !Serial.write(c);
시겠습니까? 부울 리턴 값의 의미를 뒤집는 삼항 연산자보다 깨끗하지 않습니까?
serial_putchar
기능 주셔서 감사 합니다. 대접을합니다. :-) 부동 소수점 제한 을 고칠 수 있습니까 ?
이것은 아마도 더 좋지 않을 것입니다. 출력을 위해 String 객체를 사용할 수 있습니다 . 이러한 객체는 연결을 허용하고 자동 유형 변환을 지원합니다.
Serial.begin(9600);
String label = "Var";
const byte nValues = 3;
int var[nValues] = {36, 72, 49};
for (int i = 0; i < nValues; i++) {
String stuff = label + i + ": ";
Serial.println(stuff + var[i]);
}
나는 일반적으로 탭을 사용하여 일련 번호가 더 잘 표시되도록했습니다. 내가 일하는 것처럼 정렬하면 arduino가 변수에 특정 변화가 있음을 알면서 가능한 한 빨리 발사 할 수 있습니다.
다음과 같이 해보십시오 :
Serial.println("Var 1:\tVar 2tVar 3:");
Serial.print("\t");
Serial.print(var1);
Serial.print("\t");
Serial.print(var2);
Serial.print("\t");
Serial.print(var3);
Serial.println();
또는 이와 같은 것 :
Serial.print("Var 1:");Serial.println(var1);
Serial.print("\tVar 2:");Serial.println(var2);
Serial.print("\tVar 3:");Serial.println(var3);
나는 이것을 디버깅에만 사용하지만 :
int a = 10;
int b = 20;
Serial.println("a = " + String(a) + " and b = " + String(b));
나는 Arduino 세계의 초보자이지만 최근에는 이것이 예외적 인 C ++ (예외 및 다형성 제외)임을 알았습니다. 그러나 여전히 템플릿을 즐길 수 있습니다. 그래서 내 솔루션은 다음 템플릿을 사용하는 것입니다.
void myprint(void)
{
Serial.println("");
}
template<typename ...Args>
void myprint(const uint64_t & val, Args && ...args)
{
serialPrintUint64(val);
myprint(args...);
}
template<typename T, typename ...Args>
void myprint(const T & t, Args && ...args)
{
Serial.print(t);
myprint(args...);
}
....
// somewhere in your code
myprint("type: ", results.decode_type,
"\t value: ", results.value,
"\t addr: ", results.address,
"\t cmd: ", results.command);
여기서 좋은 점은 여기에 여분의 메모리와 추가 처리를 사용하지 않는다는 것입니다.
나는 보통 (통증 적으로) 여러 줄을 고수 Serial.print
하지만 그것이 복잡해지면 다시 돌아갑니다 sprintf
. 사용 가능한 버퍼가 있어야한다는 점에서 짜증납니다.
사용법은 다음과 같이 간단합니다 (??).
char buffer[35]; // you have to be aware of how long your data can be
// not forgetting unprintable and null term chars
sprintf(buffer,"var1:%i\tvar2:%i\tvar3:%i",var1,var2,var3);
Serial.println(buffer);
경고의 말이지 만, 기본적으로 부동 유형을 지원하지 않습니다.
Streaming.h
대신 에을 사용하여
Serial.print("Var 1:");Serial.println(var1);
Serial.print(" Var 2:");Serial.println(var2);
Serial.print(" Var 3:");Serial.println(var3);
하나는 쓸 수있다
Serial << "Var 1:" << var1) << " Var 2:" << var2 << " Var 3:" << var3 << endl;
사실상 의 정의는 <<
이 Streaming.h
를 일련의 일반 Serial.print()
호출 로 변환 합니다. 즉, <<
코드 크기를 늘리지 않고 구현되는 구문 설탕입니다.
당신이하지 않은 경우 Streaming.h
설치 얻을 Streaming5.zip
에서 arduiniana.org . 라이브러리 디렉토리에서 압축을 풉니 다 (예 :) ~/sketchbook/libraries
. 스트림 연산자로 #include <Streaming.h>
사용하는 스케치 내에 선을 추가하십시오 <<
.
기본 변환 지정자 _HEX, _DEC, _OCT 및 _BIN과 _FLOAT 함수 (소수 자릿수 포함) 및가 제공됩니다 endl
. 예를 들어 위도 및 경도 값을 "좌표는 -23.123, 135.4567"과 같은 형식으로 인쇄하려면 다음과 같이 쓸 수 있습니다.
Serial << "Your coordinates are " << _FLOAT(latitude,3) << ", " << _FLOAT(longitude,4) << endl;
이것은 또한 다음과 같이 쓸 수 있습니다
Serial << F("Your coordinates are ") << _FLOAT(latitude,3) << ", " << _FLOAT(longitude,4) << endl;
RAM으로 가져 오는 대신 PROGMEM에서 더 긴 문자열을 유지합니다.
참고로 Streaming.h
문자열을 작성하지는 않습니다. 인수의 텍스트를 <<
스트림으로 전달합니다 . 스트림 출력 대신 문자열이 필요하거나 필요한 경우 arduiniana 의 PString 클래스는 스트림 입력에서 문자열을 작성할 수 있습니다.
사용법은 변수의 데이터 유형에 따라 다릅니다.
그들이 있다면 int
, 그렇 %d
거나 %i
한다면 string
,%s
printf 용 래퍼
요구 사항에 따라 제한을 변경할 수 있습니다
#include <stdarg.h>
void p(char *fmt, ... ){
char buf[128]; // resulting string limited to 128 chars
va_list args;
va_start (args, fmt );
vsnprintf(buf, 128, fmt, args);
va_end (args);
Serial.print(buf); // Output result to Serial
}
출처 : https://playground.arduino.cc/Main/Printf
사용 예 :
p("Var 1:%s\nVar 2:%s\nVar 3:%s\n", var1, var2, var3); // strings
p("Var 1:%d\nVar 2:%d\nVar 3:%d\n", var1, var2, var3); // numbers
ESP8266
Serial
프레임 워크 클래스에 내장되어 있습니다. 추가 라이브러리 또는 기능이 필요하지 않습니다.
// strings
Serial.printf("Var 1:%s\nVar 2:%s\nVar 3:%s\n", var1, var2, var3);
// numbers
Serial.printf("Var 1:%d\nVar 2:%d\nVar 3:%d\n", var1, var2, var3);
printf 형식 참조 페이지의 형식 지정 팁에 대한 자세한 내용 : http://www.cplusplus.com/reference/cstdio/printf/
\n
줄 바꿈의 이스케이프 시퀀스입니다.
이스케이프 시퀀스는 문자열 리터럴 및 문자 리터럴 내의 특정 특수 문자를 나타내는 데 사용됩니다.
출처 : http://en.cppreference.com/w/cpp/language/escape
[편집] -@Juraj가 언급했듯이 대부분의 AVR 모듈에서는 사용할 수 없습니다. 그래서 일반적인 AVR 모듈에 대한 ESP8266 언급과 printf 래퍼를 추가했습니다.
에서 http://playground.arduino.cc/Main/Printf 내 mega2560에 노력하고 벌금을 관찰
그것이 방금 작동 한 전부이며 vsnprintf_P 또는 PROGMEM이 필요하지 않습니다 ...
#include "Arduino.h"
void local_printf(const char *format, ...)
{
static char line[80];
va_list args;
va_start(args, format);
int len = vsnprintf(line, sizeof(line), format, args);
va_end(args);
for (char *p = &line[0]; *p; p++) {
if (*p == '\n') {
Serial.write('\r');
}
Serial.write(*p);
}
if (len >= sizeof(line))
Serial.write('$');
}
void setup()
{
Serial.begin(115200);
local_printf("%s:%d: %s\n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
}
void loop()
{
static int count=0;
local_printf("%s:%d: %s %d\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, count++);
delay(1*1000);
}
// src/main.c:24: void setup()
// src/main.c:30: void loop() 0
// src/main.c:30: void loop() 1
printf()
대신 이것을하고 싶 습니까?