假设我有一些要打印到终端的变量,以字符串形式打印它们的最简单方法是什么?
目前,我正在执行以下操作:
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);
有一个更好的方法吗?
Answers:
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]);
}
我通常使用Tab键来使序列中的内容排列得更好。像我一样安排一切,让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;
<<
in 的定义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;
这样会将较长的字符串保留在PROGMEM中,而不是将其带入RAM。
注意,Streaming.h
不会像这样构建任何字符串。它只是将其<<
参数的文本传递到流中。如果需要或需要字符串而不是流输出,arduiniana的PString类可以从流输入构建字符串。
用法将取决于变量的数据类型。
如果是int
,则为%d
或%i
如果是string
,则为%s
包装包装
您可以根据自己的要求更改限额
#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模块上不可用。所以我增加了ESP8266的提法和常见AVR模块的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()
自身?