터미널에 인쇄하려는 변수가 있는데 문자열로 인쇄하는 가장 쉬운 방법은 무엇입니까?
현재 나는 다음과 같은 것을한다 :
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);
더 좋은 방법이 있습니까?
답변:
ardprintfprintf직렬 연결을 통해 시뮬레이션하는 해킹 된 기능입니다 . 이 기능 (맨 아래에 제공)은 기능이 필요한 파일의 시작 부분에 붙여 넣을 수 있습니다. 충돌을 일으키지 않아야합니다.
와 비슷하게 호출 할 수 있습니다 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() 대신 이것을하고 싶 습니까?