मैं एक स्ट्रिंग में कई चर कैसे प्रिंट कर सकता हूं?


46

कहो मेरे पास कुछ चर हैं जो मैं टर्मिनल पर प्रिंट करना चाहता हूं, उन्हें एक स्ट्रिंग में प्रिंट करने का सबसे आसान तरीका क्या है?

वर्तमान में मैं ऐसा कुछ करता हूं:

Serial.print("Var 1:");Serial.println(var1);
Serial.print(" Var 2:");Serial.println(var2);
Serial.print(" Var 3:");Serial.println(var3);

क्या ऐसा करने के लिए इससे अच्छा तरीका है?


एक विचार है, लेकिन मुझे नहीं पता कि यह काम करेगा, क्या इस का कुछ संशोधन है ... फिर, मुझे नहीं पता कि क्या यह Arduino पर समर्थित है: stackoverflow.com/questions/804288/…
apnorton

जवाबों:


37

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

** %चरित्र मुद्रित करने के लिए , का उपयोग करें %%। *


अब, जीथब जिस्ट पर उपलब्ध है ।


3
अच्छा विचार है, हालांकि मुझे लगा कि यह अधिक न्यूनतम हो सकता है, इसलिए मैंने इस संस्करण को बिना बफरिंग के फिर से लिखा। कोई भी इच्छुक व्यक्ति जिस्ट की
eleotlecram

13

मैं आम तौर पर एक प्रश्न के दो उत्तर नहीं देता, लेकिन मुझे केवल यह आज मिला , जहां आप बिना किसी बफर के प्रिंटफ का उपयोग कर सकते हैं।

// 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 !Serial.write(c);? क्या बूलियन रिटर्न वैल्यू के अर्थ को कम करने के लिए ट्रिनिकल ऑपरेटर की तुलना में क्लीनर नहीं है?
डंकन सी।

यह एक अच्छा बिंदु है और मुझे यह पसंद है। कोड मेरा नहीं था और मैंने इसे पा लिया जैसा मैंने पाया था।
मडिवड

serial_putcharसमारोह के लिए धन्यवाद । यह एक इलाज का काम करता है। :-) क्या आप फ्लोटिंग पॉइंट लिमिटेशन को ठीक कर सकते हैं ?
ग्रीनऑनलाइन

4

यह शायद बेहतर नहीं है, बस अलग है। आप आउटपुट के लिए स्ट्रिंग ऑब्जेक्ट का उपयोग कर सकते हैं । ये ऑब्जेक्ट कॉन्टेक्ट करने की अनुमति देते हैं और स्वचालित टाइपकास्टिंग का समर्थन करते हैं।

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]);
}

4
जाहिर है कि मेमोरी लिमिट से सावधान रहना जरूरी है। एक स्थान पर बहुत सारे अवतरण और अन्य स्ट्रिंग ऑपरेशन अंतरिक्ष की एक आश्चर्यजनक मात्रा का उपयोग कर सकते हैं।
पीटर ब्लूमफील्ड

@ पीटरआर.ब्लूमफील्ड बिल्कुल सच है! यही कारण है कि मैंने उल्लेख किया कि यह वैरिएंट बेहतर नहीं है;)
क्लाउस-डाइटर वारज़ेचा

4

मैं आमतौर पर टैब्स का इस्तेमाल सीरियल में चीजों को बेहतर बनाने के लिए करता था। चीजों को लाइन अप करने की तरह मैं 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);

ईमानदारी से, मैं ऐसा ही करता हूं ("\ t" और "\ n") और सामान्य रूप से कोड-ब्लॉटिंग स्ट्रिंग ऑब्जेक्ट घंटियाँ और सीटी से बचें।
क्लाउस-डाइटर वारज़ेचा

1
@KlausWarzecha, मैं शायद ही कभी चर नाम देता हूं क्योंकि वे अच्छे कॉलम में हैं। इसके अलावा रैंडम प्रिंट आउट देखना भी आसान बना दें जो इस सिंटैक्स से मेल नहीं खाता
Steven10172

4

मैं केवल डीबगिंग के लिए इसका उपयोग करता हूं लेकिन:

int a = 10;
int b = 20;
Serial.println("a = " + String(a) + " and b = " + String(b));

स्ट्रिंग $ क्या है?
जुराज

LMFTFM (मुझे मेरे लिए ठीक करने दें)।
लाइनरट्रॉन 22

2

मैं 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);

यहाँ अच्छी बात यह है कि यह किसी भी अतिरिक्त मेमोरी और अतिरिक्त प्रसंस्करण का उपयोग नहीं करता है।


1

मैं आमतौर पर (दर्द से) कई लाइनों के साथ छड़ी करता हूं, 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);

चेतावनी का एक शब्द, हालांकि, यह (डिफ़ॉल्ट रूप से) फ्लोटिंग प्रकारों का समर्थन नहीं करता है।


1
स्प्रिंटफ एक भयानक घृणा है। अपने बफ़र्स इत्यादि को सुरक्षित करने के लिए सुरक्षित, आसान प्रकार नहीं, आदि यह 1960 के दशक से एक उपकरण है। उस ने कहा, मैं भी इसका उपयोग करता हूं, लेकिन यह दिल के बेहोश के लिए नहीं है ....
डंकन सी।

ओवररन से बचने के लिए, स्निप्रफ का उपयोग करें ... बीटीडब्लू के अधिकांश moder IDE (Arduino IDE नहीं) प्रदान किए गए चर प्रकारों के खिलाफ स्ट्रिंग प्रारूप की जांच करेंगे, और एक चेतावनी फेंक देंगे।
अगली

1

के 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इंस्टॉल नहीं किया है, तो arduiniana.orgStreaming5.zip से प्राप्त करें । उदाहरण के लिए, अपनी लाइब्रेरी निर्देशिका में इसे अनज़िप करें ~/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 वर्ग स्ट्रीम इनपुट से स्ट्रिंग्स का निर्माण कर सकता है, अगर स्ट्रीम किए गए आउटपुट के बजाय तार वांछित या आवश्यक हैं।


1

उपयोग आपके चर के डेटा प्रकार पर निर्भर करेगा।

यदि वे हैं 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);

प्रिंटफ़ प्रारूप संदर्भ पृष्ठ पर युक्तियों को प्रारूपित करने के बारे में अधिक जानकारी: http://www.cplusplus.com/reference/cstdio/printf/

\n लाइन फ़ीड के लिए भागने का क्रम है।

एस्केप सीक्वेंस का उपयोग स्ट्रिंग शाब्दिक और चरित्र शाब्दिक के भीतर कुछ विशेष वर्णों का प्रतिनिधित्व करने के लिए किया जाता है।

स्रोत: http://en.cppreference.com/w/cpp/language/escape

[संपादित करें] - जैसा कि @ जुराज ने उल्लेख किया है, यह अधिकांश एवीआर मॉड्यूल पर उपलब्ध नहीं है। इसलिए मैंने ईएसपी 8266 का उल्लेख किया और आम एवीआर मॉड्यूल के लिए एक प्रिंटफ़ आवरण


यह सच नहीं है। कोई सीरियल क्लास नहीं है। Printf प्रिंट क्लास में होगा, लेकिन यह सबसे ज्यादा इस्तेमाल किए जाने वाले AVR पैकेज में नहीं है
Juraj

@ जुराज आप सही कह रहे हैं, मैंने केवल ESP8266 पर इसका परीक्षण किया है, जिसमें यह ( लिंक ) है और सोचा कि यह आर्किनो कोर से था। तदनुसार अपना उत्तर अपडेट करूंगा
रेमी

यदि संभव हो तो p फंक्शन के लिए मैं एक और डाउनवोट जोड़ूंगा।
जुराज

यह एक पुराना प्रश्न है और मैं पुराने उत्तरों को निर्धारित नहीं कर सकता क्योंकि मुझे नहीं पता कि 2014 में क्या उपलब्ध था। लेकिन अब प्रिंटफ़ कार्यान्वयन के साथ प्रिंट स्ट्रीम में प्रिंट स्ट्रीम लपेटने के लिए पुस्तकालय हैं।
जुराज


-1

से 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

1
कोई भी केवल स्वयं का उपयोगprintf() करने के बजाय ऐसा क्यों करना चाहेगा ?
एडगर बोनेट

-3
int Money_amount = 55;

Serial.print(String("New amount: $" + Money_amount));

आप टर्मिनल पर देखेंगे:

New amount: $55

1
आप एक +ऑपरेटर के साथ एक सी-स्ट्रिंग के लिए एक intatenate नहीं कर सकते ।
gre_gor
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.