端末に出力したい変数がいくつかあるとしたら、それらを文字列で印刷する最も簡単な方法は何ですか?
現在、私は次のようなことをしています:
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で利用可能です。
通常、質問に2つの答えを出すことはありませんが、今日はこれを見つけただけです。ここでは、バッファーなしで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
機能をありがとう。それは御treat走になります。:-)あなたは、修正することができ、浮動小数点の制限を?
これはおそらく良くない、ただ違うだけです。出力に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;
<<
in Streaming.h
in の定義は、それを一連の通常の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モジュールでは利用できません。そこで、ESP8266の記述と一般的なAVRモジュールのprintfラッパーを追加しました
1つの可能な解決策は次のとおりです。
Serial.println((String)"Var 1:" + var1 + " Var 2:" + var2 + " Var 3:" + var3);
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()
するのではなく、なぜこれをやりたいのでしょうか?
int Money_amount = 55;
Serial.print(String("New amount: $" + Money_amount));
端末に表示されます:
New amount: $55
+
演算子を使用してintをc-stringに連結することはできません。