Arduino Forum

Using Arduino => Programming Questions => Topic started by: samtal on Dec 12, 2017, 08:36 am

Title: String concatenation for Serial.print
Post by: samtal on Dec 12, 2017, 08:36 am
Hi,

Arduino Mega1280, Arduino standard IDE, include string lib.

To efficiently print out mixed data, I convert all data items into one concatenated string and send the string to the serial port.
This works nicely, except that I can not control the output format for an individual item as I could do in single item Serial.print(value, HEX).
Please see attached example.

Is there a way to format printout of individual concatenated items in a string?
Thx
 
Title: Re: String concatenation for Serial.print
Post by: krupski on Dec 12, 2017, 09:07 am
Hi,

Arduino Mega1280, Arduino standard IDE, include string lib.

To efficiently print out mixed data, I convert all data items into one concatenated string and send the string to the serial port.
This works nicely, except that I can not control the output format for an individual item as I could do in single item Serial.print(value, HEX).
Please see attached example.

Is there a way to format printout of individual concatenated items in a string?
Thx
 
Use a buffer and the  sprintf  function.

Example

Code: [Select]

char buf [64]; // must be large enough for the whole string
int voltage; // variable to get a value from a voltage source (example)

// this is the code that generates the string to print
void loop (void) {
    sprintf (buf, "The voltage is currently %3d volts DC\r\n", voltage);
    Serial.print (buf);
    delay (1000); // print out voltage once a second
}


Assuming that the voltage is changing, you will see something like this in your serial monitor:

The voltage is currently  15 volts DC
The voltage is currently  14 volts DC
The voltage is currently  13 volts DC
The voltage is currently  12 volts DC
The voltage is currently  13 volts DC
The voltage is currently  14 volts DC
The voltage is currently  15 volts DC

See? The variable "voltage" is "sent to" the "%3d" format string and replaces it (the "3" means "make room for 3 digits" and the "d" means "the variable is an integer".

The %3 does this:
  0
  1
....
  9
 10
 11
...
 99
100
101

See how they line up?

Hope this helps.
Title: Re: String concatenation for Serial.print
Post by: sterretje on Dec 12, 2017, 09:31 am
To efficiently print out mixed data, I convert all data items into one concatenated string and send the string to the serial port.
Please define 'efficient'.
Title: Re: String concatenation for Serial.print
Post by: UKHeliBob on Dec 12, 2017, 09:46 am
Please define 'efficient'.

My thoughts entirely.

Put the print statements in a suitably function and call it when required so that the main program looks neat and tidy and screen space is not "wasted" with a series of print statements.
Title: Re: String concatenation for Serial.print
Post by: samtal on Dec 12, 2017, 04:05 pm
With 'efficient' I mean efficient in the serial port.
Instead of sending each line with a Serial.print command that has significant overhead, concatenating all data into one string and one print command cuts much of that overhead.

As to the last comment by Brattain Member, I did not relate to efficiency in the editor text.
The program lines are in one printout function. Of course, the lines in my example could be written as one line, but I like it my way, for clarity.

To the main point: My question was related to large number mixed values concatenating and formatting. Saving into a buffer can be an option, but not a nice one, and I need to test it to make sure I can format each individual value differently.

Title: Re: String concatenation for Serial.print
Post by: Delta_G on Dec 12, 2017, 04:26 pm
Your combining them has more overhead than just printing them one after another.  All print has to do is dump the data into a buffer.  Where it is concatenated like you want.  So you're basically making it do that twice.  Now which is really more efficient?
Title: Re: String concatenation for Serial.print
Post by: Delta_G on Dec 12, 2017, 04:29 pm
Quote
Saving into a buffer can be an option, but not a nice one
If you're not keeping it in some buffer then where are you concatenating it?  I think you have a general misunderstanding of what's going on here.  Perhaps you should describe what you actually want to see happen and let someone tell you what's the best and most efficient method to do it. 
Title: Re: String concatenation for Serial.print
Post by: -dev on Dec 12, 2017, 04:32 pm
Quote
Please define 'efficient'.
Indeed.

There is no reason to build one giant string and then print it all out at once.  There is no overhead associated with Serial.print that you can avoid by building one giant string.  Printing each piece by itself is actually much more efficient:

*  The Arduino can be printing the first part of the message while it formats the next parts.

*  No additional RAM is needed to contain any part of the printed string.  Only your variables will use RAM.

*  The characters to be printed are not copied into and out of this extra buffer; they are given directly to the Serial port object.

*  This avoids the additional processing required by String operations *and* avoids the numerous issues with String usage, especially long-term stability (read this (https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/)).

Using sprintf also has disadvantages:

*  You must be very careful that the destination char buffer has enough room.  If you don't count right, the sprintf function will write past the end of the buffer, corrupting memory.  I don't know why people don't recommend snprintf (http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#ga77070c245d4ca4f7ec7d7144260fb875) to avoid this common problem.

*  The sprintf function is really a mini "interpreter".  It interprets the format string at run time and "executes" the various % formatting functions.  This is much slower than calling

    Serial.print( v, HEX )

*  Since the interpretation occurs at run-time, there is no compiler warning about trying to print an integer when you pass in a character (or any other mismatch between the % formatter and the argument you pass).

*  This format interpreter code is fairly long, adding about 1000 bytes to the executable size.  Because the format string can contain many different types, code for all types must be included in the executable.  When you use the print functions for individual pieces, the linker eliminates all the functions for types that you don't need.

*  Floating-point number are not supported by default.

For comparison, here are 3 short sketches that use each technique:

Code: (giant String) [Select]
void setup()
{
  Serial.begin( 9600 );
}

String string;
volatile int value;  // a trick to make sure the optimizer doesn't cheat  :)

// this is the code that generates the string to print
void loop (void) {
    value = millis() & 0xFF;

    unsigned long start = micros();

    string = "The value is currently 0x";
    string += hexDigit( value >> 4 );
    string += hexDigit( value );
    string += " units\r\n";

    Serial.print( string );

    Serial.print( micros() - start );
    Serial.println( F("us") );

    delay (1000); // print out value once a second
}

char hexDigit( int v )
{
  v &= 0x0F; // just the lower 4 bits
  if (v < 10)
    return '0' + v;
  else
    return 'A' + (v-10);
}

Code: (sprintf into buffer) [Select]
void setup()
{
  Serial.begin( 9600 );
}

char buf [64]; // must be large enough for the whole string
volatile int value;

// this is the code that generates the string to print
void loop (void) {
    value = millis() & 0xFF;

    unsigned long start = micros();

    sprintf (buf, "The value is currently 0x%02X units\r\n", value);
    Serial.print (buf);

    Serial.print( micros() - start );
    Serial.println( F("us") );

    delay (1000); // print out value once a second
}

Code: (piece-wise Serial.print) [Select]
volatile int value;

char hexDigit( int v )
{
  v &= 0x0F; // just the lower 4 bits
  if (v < 10)
    return '0' + v;
  else
    return 'A' + (v-10);
}

void printValue( int v )
{
    Serial.print( F("The value is currently 0x") );
    Serial.write( hexDigit( value >> 4 ) );
    Serial.write( hexDigit( value ) );
    Serial.println( F(" units") );
}

void setup()
{
  Serial.begin( 9600 );
}

void loop () {
    value = millis() & 0xFF;

    unsigned long start = micros();

    printValue( value );

    Serial.print( micros() - start );
    Serial.println( F("us") );

    delay (1000); // print out voltage once a second
}

The String version takes 370us to execute and uses 4384 bytes of program space and ~320 bytes of RAM (270 + ~50 bytes on the heap).
The sprintf version takes 560us to execute and uses 3868 bytes of program space and 300 bytes of RAM.
The piece-wise version takes 320us to execute and uses 2498 bytes of program space and 202 bytes of RAM.

Your choice, of course.  ;)

Cheers,
/dev
Title: Re: String concatenation for Serial.print
Post by: UKHeliBob on Dec 12, 2017, 04:34 pm
Quote
As to the last comment by Brattain Member, I did not relate to efficiency in the editor text.
The program lines are in one printout function. Of course, the lines in my example could be written as one line, but I like it my way, for clarity.
If you are referring to my post then I am not suggesting that you put all of the print statements in one line, but I would certainly avoid using Strings as you do as it would lead to memory fragmentation.

I am not convinced that there is any significant overhead in using Serial.print more than once.  The baud rate of the Serial interface determines how fast each byte is sent and each byte is sent individually whether the data is all in one buffer, such as would be the case were sprintf() were used, whether it all in one String (or string) or whether several individual prints are done each with a different part of the data.
Title: Re: String concatenation for Serial.print
Post by: sterretje on Dec 12, 2017, 04:35 pm
Adding to all that

At the moment that the software output buffer for the serial port is full, your code will stall / block. That will be the case when using several print statements as well as in your approach.

If you use Serial.availableForWrite() and check if there is space to send some characters, you can prevent that from happening. Send a small chunk, check if there is enough space for the next chunk and send that etc. If there is not enough space, do something else.

With your approach, you can't.
Title: Re: String concatenation for Serial.print
Post by: krupski on Dec 13, 2017, 10:23 pm
To the main point: My question was related to large number mixed values concatenating and formatting. Saving into a buffer can be an option, but not a nice one, and I need to test it to make sure I can format each individual value differently.
Why is using a buffer not a "nice option"?  No matter how you print something, a temporary buffer is used,  Note that if you declare a buffer in a function, it's ram usage exists only as long as the function runs. The memory is freed when the function is complete.

What we all should be using is C's standard  "printf"  , but in keeping with the Arduino policy of not supporting essential functions in order to save half a dozen bytes, we are forced to either use a bunch of  "Serial.print (this)"  and  "Serial.print (that)"  functions, ad-nauseaum,  in order to print a simple, single line of text on the terminal or  sprintf  and a buffer.

And, because of the fear of using a few more bytes of memory by using standard in, standard out and standard error, burned into everyone's mind by people who don't have a clue what they are talking about, Arduino users won't even use a simple library that automatically provides stdin/out/err access claiming every reason from "uses a few more bytes" to "it blocks" to "it will stop the sun from shining" to "the IDE doesn't support it" (when, of course, the IDE doesn't support ANYTHING... AVR-GCC does and indeed AVR-GCC does support all C/C++ functions) and instead happily go on typing ridiculous stuff like this:

Code: [Select]

int volts = 120;

Serial.print ("Voltage: ");

if (volts < 10) {
    Serial.print (" "); // align columns
}

if (volts < 100) {
    Serial.print (" "); // align 100's place
}

Serial.print (volts);

Serial.print (" VDC");

Serial.print ('\r'); // goto...
Serial.print ('\n'); // ...new line because the Print library doesn't even
    // know how to translate a Unix newline into a CR/LF.

 
When they COULD just do this:

Code: [Select]

int volts = 120;
fprintf (stdout, "Voltage: %3d VDC\n", volts);


Don't know why... maybe there's some perverse pleasure in repeatedly ramming one's head into the wall.... ?

And, if the user doesn't want to install a simple library to make things 1000% easier, the next best method is to use a temporary buffer and  "sprintf"  which is almost as good (but not AS good) as using printf directly.

While we're at it, the Arduino developers, in their wisdom(?) not only disable floating point print support without providing the option of using it if desired, they also espouse the use of "dtostrf" which is complicated, not understood by a lot of people, doesn't fully support "printf style" formatting and requires the user to provide a temporary buffer for it (and the user is responsible for making sure the buffer is large enough).

Everyone shies away from floating point because it uses a few dozen more bytes of memory, but the fact that "dtostrf" also consumes program and ram space doesn't seem to bother anyone.

I feel sorry for any Arduino user who ends up programming for a living, because they will forever be hampered by all the convoluted or just plain wrong "facts" they learned from the "experts".  Learning something new is tough enough without having to also UNLEARN the wrong stuff the "experts" taught them.

...and don't even get me started on the absurdity of worrying about a function "blocking" when the code is single tasking/ single threaded and running on a toy microcontroller with a quarter meg or less of memory (or, nuttiness in the other direction...) setting up a bunch of interrupt handlers to read the state of a switch or blink an LED on and off...   (http://www.gunsnet.net/images/smilies/dizzy.gif)
Title: Re: String concatenation for Serial.print
Post by: krupski on Dec 13, 2017, 10:31 pm
Indeed.

There is no reason to build one giant string and then print it all out at once.   [1] There is no overhead associated with Serial.print that you can avoid by building one giant string.  [2] Printing each piece by itself is actually much more efficient:

*  [3] The Arduino can be printing the first part of the message while it formats the next parts.
I know that "boldly asserted is half proven", but I would love to see some proof (links, whatever) to back up those 3 assertions (because you are wrong on all 3 counts).
Title: Re: String concatenation for Serial.print
Post by: DrAzzy on Dec 13, 2017, 11:28 pm
I know that "boldly asserted is half proven", but I would love to see some proof (links, whatever) to back up those 3 assertions (because you are wrong on all 3 counts).
Well, he did show three example programs using the different techniques, and the version with the giant string, and the one with sprintf both used about 50% more ram, 100% more flash, and executed more slowly. What sort of proof are you looking for?
Title: Re: String concatenation for Serial.print
Post by: Delta_G on Dec 13, 2017, 11:50 pm
I know that "boldly asserted is half proven", but I would love to see some proof (links, whatever) to back up those 3 assertions (because you are wrong on all 3 counts).
Asking for proof and claiming he's wrong... with no proof.  -dev showed the code and results.  What more proof do you want?  What proof have you other than your general distaste for the Arduino community?   Does your version with printf produce smaller or faster code?  Prove it. 
Title: Re: String concatenation for Serial.print
Post by: westfw on Dec 14, 2017, 01:38 am
There are cases where pre-buffering print() output might be useful.  AFAIK, neither Ethernet.print() nor USBSerial.print() does anything intelligent in terms of avoiding the "one message per print statement" problem, and you could potentially improve throughput quite a lot.  Normal HardwareSerial.print() would gain very little, though; in additional to there being no smarts for "aggregating" small output requests, there also aren't any smarts for optimizing large requests.
Title: Re: String concatenation for Serial.print
Post by: samtal on Dec 14, 2017, 08:12 am
Hi all,
As the originator of this thread, I am overwhelmed with the magnitude of replies to a question I thought was a simple one.
It looks almost like opening a Pandora's box.
Nevertheless, reading through all the replies and discussions I think I have the answer to my question, namely that concatenating print values is not the best way to go with Arduino, or at least it will not yield any advantage.

I will keep trying and testing my specific app, but this issue is of secondary importance to me at this time.
Thanks to all contributors who made me somewhat smarter......   
Title: Re: String concatenation for Serial.print
Post by: -dev on Dec 14, 2017, 04:24 pm
Quote
AFAIK...
USBSerial (aka Serial on a Leonardo) ultimately sends the bytes one at a time (https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/USBCore.cpp#L296), so there is no advantage.

If the OP were using a W5100 (they're not), and if TCP "fragmentation" were an issue, simply derive a class (https://arduino.stackexchange.com/questions/29358/how-avoid-tcp-packet-fragmentation) from EthernetClient.  Basically, the selected answer in that link adds the same RAM buffer used by the sprintf approach (I would also override the other virtual write method).  It would use extra RAM like the sprintf technique, but would not have the other sprintf disadvantages.

Quote
Normal HardwareSerial.print() would gain very little, though; in additional to there being no smarts for "aggregating" small output requests, there also aren't any smarts for optimizing large requests.
There is nothing to gain.  HardwareSerial puts each byte into an output buffer (https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp#L242), and that buffer is emptied by transmit interrupts (in the background).  This "output stream pump" is primed by the first character, earlier in that method (https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp#L216).

For skeptics, this how the Arduino can continue doing other work (in the foreground) while those characters are gradually pumped out.  

@samtal, glad to help!
Title: Re: String concatenation for Serial.print
Post by: westfw on Dec 15, 2017, 12:28 am
Quote
USBSerial (aka Serial on a Leonardo) ultimately sends the bytes one at a time (https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/USBCore.cpp#L296), so there is no advantage.
It's not the Send8() calls that are a problem - they just copy data from the user arguments to USB buffer.  But the ReleaseTX() call a few lines later, in conjunction with the block on USB_SendSpace() before the byte loop.  This is what releases the data (in the USB buffer) so that the USB hardware can send it.  But there are only two USB Buffers, so once you've queued them to USB hardware to send, the code has to sit around and wait for the USB transaction(s) to complete.  Because of the way USB works, this is relatively slow (~1ms)
I've attached a test program that does 5000 individual single-byte Serial.print() calls or 100 50-byte Serial.print() calls, and times how long it takes.   For an Nano (with HardwareSerial, at 115200bps) the times are nearly identical - 420 vs 425 ms (about what you'd expect.  11520/5000 = .434)
On a Leonardo (using USB Serial), you get 135 vs 15ms.  The "big" prints result in much better performance.
(now those actual numbers on Leonardo don't quite fit my "1 message per ms" explanation, so that wasn't quite right.  However...)



Code: [Select]

void setup() {
  Serial.begin(115200);
  while (!Serial)
    ;
}

void loop() {
  uint32_t startt, endt;

  delay(1000);
  startt = millis();
  for (int i = 0; i < 5000; i++) {
    Serial.print(" ");
  }
  endt = millis();
  Serial.println();
  Serial.print("Write 5000 individual bytes in ");
  Serial.print(endt - startt);
  Serial.println(" milliseconds. \n");
  Serial.flush();

  startt = millis();
  for (int i = 0; i < 100; i++) {
    Serial.print("                      25                       50\r");
  }
  Serial.flush();

  endt = millis();
  Serial.println();
  Serial.print("Write 100 50 byte chunks in ");
  Serial.print(endt - startt);
  Serial.println(" milliseconds. \n");
  Serial.flush();

  while (Serial.read() < 0)
    ;
}
Title: Re: String concatenation for Serial.print
Post by: -dev on Dec 15, 2017, 12:58 am
Interesting!  Some advantage, then.  Thanks for tracing the rest of the call stack.  :)

Makes me  wonder why they didn't use a ring buffer like everything else.  But if I had a nickel for every time I wondered that...
Title: Re: String concatenation for Serial.print
Post by: westfw on Dec 15, 2017, 01:13 am
packetizing interactive byte-stream IO is a relatively complex problem; ripe for many tradeoffs...
Title: Re: String concatenation for Serial.print
Post by: krupski on Dec 15, 2017, 09:15 am
Asking for proof and claiming he's wrong... with no proof.  -dev showed the code and results.  What more proof do you want?  What proof have you other than your general distaste for the Arduino community?   Does your version with printf produce smaller or faster code?  Prove it.  
I have no "distaste" for the Arduino community. Why on earth would I get on this forum and spend 95% of my time here answering questions or explaining how something works?

As far as my "assertions", let me explain each one:


Quote
(from -dev):
There is no reason to build one giant string and then print it all out at once.   [1] There is no overhead associated with Serial.print that you can avoid by building one giant string.  [2] Printing each piece by itself is actually much more efficient:

*  [3] The Arduino can be printing the first part of the message while it formats the next parts.
#1: There is overhead associated with every and any call of a C function. Parameters have to be placed on the stack, as well as return address and other info.  Calling a function 10 times with a small chunk of data is most certainly slower than calling the function with all the data at once (because you avoid the overhead of calling the function 9 times more than necessary).

#2: Wrong - same reason as #1.

#3: This statement is misleading. Although the Arduino hardware serial code does use a ring buffer and interrupts, the statement made by -dev makes it sound as though serial data will be output from the ring buffer even if the CPU is busy elsewhere (for example stuck in a blocking delay(nnn) call or in the middle of parsing the format specifiers of another string).

Now, I suppose I could write a simple sketch and show actual numbers, but I felt that there was no need since everyone knows (I assume) that calling a C function involves "behind the scenes" activity which obviously consumes more time if the function is called repeatedly.

I can do this if you wish.......

Title: Re: String concatenation for Serial.print
Post by: krupski on Dec 15, 2017, 09:30 am
Does your version with printf produce smaller or faster code?  Prove it.  
Forgot to address this part.

There is no such thing as "my version" of printf. I simply enable the use of existing functionality that the AVR-GCC compiler provides.

This saves me the headaches of using multiple "Serial.print" calls and makes for easier reading of the source code itself.

My IDE also has a checkbox which allows me at edit/compile time to enable or disable floating point support.  Yes I know that it uses some resources, but when the sketch is compiled and floating point only adds 1.5K to my 24K sketch and it all fits with room to spare in an UNO or a MEGA, why should I beat my head against the wall to use "dtostrf" and all the extra work that involves?

Now, I don't know if enabling native floating point uses less or more resources than dtostrf and it's required buffer, but the difference can't be all that much and since I have room to spare anyway, why not?

My big gripe is with the DEVELOPERS of the Arduino IDE system.  Sure, I understand that they want to conserve resources... I get it. But why not place an OPTION in Preferences to enable or disable certain features?

Want floating point? Just tick the checkbox.
Want to use printf? Just tick the checkbox.
Need every last bit of memory? Un-tick the checkbox.

But, GIVE THE USERS THE CHOICE AND CONTROL!!!

We can turn line numbering on or off, we can choose to auto-rename a sketch from .PDE to .INO, we can do a lot of other [sarcasm] really important [/sarcasm] things in Preferences.

But, control the things that EVERYONE HERE asks about? Nope, can't do it. WHY?

If you and I had a dollar for every time someone asked why trying to print a number only results in a question mark or how to get dtostrf working, we could afford to have others write our code!  :)

(although what fun would that be?)

Title: Re: String concatenation for Serial.print
Post by: krupski on Dec 15, 2017, 10:00 am
Hi all,
As the originator of this thread, I am overwhelmed with the magnitude of replies to a question I thought was a simple one.
It looks almost like opening a Pandora's box.
Please don't worry about anything. You didn't open a "Pandora's box", nor did you ask anything wrong.

In fact, the "Pandora's box" is mostly my fault, for I get quite passionate about seeing users have problems with their programming which result from the fact that many simple, standard features and functions in C are disabled by the Arduino developers.

Now, I understand the need to minimize memory and resource usage in a small microcontroller environment, and for many cases, the disabled functions will indeed save some space.

What I gripe about is not that these features are disabled but that there is no built in ability for a user to simply "click" the feature on or off.

I've modified my Arduino IDE to provide these options (as well as a few others) so I know that programming-wise, it's trivial. Any Arduino IDE developer could add these options to the newest IDE in less than a day (probably before lunch time).

In lieu of being to optionally enable these features, there are "alternatives" for example using the function "dtostrf" to take a floating point number and convert it into a user supplied buffer, enabling the user to print fractional numbers.

Unfortunately, the sequence of events (as most everyone here has seen dozens to hundreds of times), goes like this:

(1) User writes a program to display a temperature.
(2) To his surprise, any temperature is displayed as a question mark ('?').
(3) User checks and re-checks his code. Darn it looks fine!!!
(4) User checks the C documentation online and finds that, yes indeed he's doing it right.
(5) User then logs on here and asks about the problem.
(6) User gets a flurry of responses ranging from "It can't be done" to "It's disabled to save memory" to "Use the dtostrf function".
(7) Ah-ha! One positive reply... user CAN do it with dtostrf.
(8) User goes online looking in C documentation for how to use dtostrf.
(9) Darn! Can't seem to find anything. Back to the Arduino forum.
(10) User finds out that dtostrf is an AVR specific function.
(11) User looks at the Arduino documentation. Nothing found. ARGHHHHHH!!!
(12) User checks online for the docs. AH! Success!
(13) User reads the information.....

The dtostrf() function converts the double value passed in val
into an ASCII representationthat will be stored under s. The
caller is responsible for providing sufficient storage in s.

Conversion is done in the format "[-]d.ddd". The minimum field
width of the output string (including the possible'.' and the
possible sign for negative values) is given in width, and prec
determines the number of digits after the decimal sign.

width is signed value, negative for left adjustment.

The dtostrf() function returns the pointer to the converted string s.

Yeah OK.... um what the heck does THAT mean?

(14) Another post to this forum yields a few terse examples which user tries.
(15) After a few tries, the user figures out what "provide sufficient storage" means... :)
(16) .....it goes on and on.......

OR!!!!!!!!! The user SHOULD be able to simply click the "Enable floating point" checkbox in Preferences, then do this:
Code: [Select]

printf ("The temperature is %5.1f degrees C\n", temperature);


...and have his sketch JUST WORK.

In fact, the above "scenario" I went through myself when I first started with the Arduino. I was not a noob... I had years of previous experience in programming assembler in Motorola and Intel, as well as programming in C and C++.

I was rather ticked off to find out how much time I wasted with that "floating point problem" and it ticks me off to see others go through the same thing simply because nobody will take a 1/2 hour and add a few options to the IDE that people ACTUALLY NEED.

That's when I get all revved up and write stuff like this.

So, please don't feel as though you did anything wrong or started any problems. You did not, and I sure hope you will continue to ask us anything you need - please feel free.

-- Roger
Title: Re: String concatenation for Serial.print
Post by: westfw on Dec 15, 2017, 11:32 am
Of course, floating point support for Serial.print() DID get added.  In a relatively nonStandard way that is not as powerful as printf(), but is just about as big.
Title: Re: String concatenation for Serial.print
Post by: -dev on Dec 15, 2017, 03:58 pm
Quote from: krupski
#1: There is overhead associated with every and any call of a C function.
I would probably agree that 10 calls with 2 arguments takes longer than 1 call with 12 arguments.  I'm not sure, because there is some increased overhead due to the varargs (https://en.wikipedia.org/wiki/Variadic_function) calling convention of sprintf

Regardless, the measurements show that the piece-wise overhead is much, much less than the time used by the other techniques (String and sprintf).  Most of it has to do with the run-time interpretation of the format string.

Quote
#2: Wrong - same reason as #1.
The numbers seem to show that piece-wise if most efficient.  I don't know how to discuss something with you if you don't look at the objective numbers.  If you don't understand the measurement sketches, just ask a question.

Quote
#3: This statement is misleading... /dev makes it sound as though serial data will be output from the ring buffer even if the CPU is busy elsewhere (for example stuck in a blocking delay(nnn) call or in the middle of parsing the format specifiers of another string).
Serial data will be output from the ring buffer even if the CPU is doing a delay or formatting another piece.  That's how interrupts work.  I marvel that you don't know this, even after I provided links to the source.  Continuing  to argue the point fits the definition of Willful Ignorance (https://rationalwiki.org/wiki/Willful_ignorance).

Quote
Now, I suppose I could write a simple sketch and show actual numbers

I can do this if you wish.......
Yes, please.  This is the essence of forum discussion.  If you disagree, you have to support the argument with something that everybody can reproduce.  Subjective ranting does not nullify the objective measurements.  Show us your actual numbers, and maybe we'll all start using sprintf.
Title: Re: String concatenation for Serial.print
Post by: Delta_G on Dec 15, 2017, 04:54 pm
Quote
There is no such thing as "my version" of printf.
I didn't say "of" I said "with".  The OP was asking about function overhead and efficiency.  Does your version of code using printf instead of a chain of print calls result in more compact or more efficient code?  Does it meet the requirements of the OP?  Or does it just make for less typing which wasn't what he was asking for. 
Title: Re: String concatenation for Serial.print
Post by: krupski on Dec 15, 2017, 09:04 pm
Of course, floating point support for Serial.print() DID get added.  In a relatively nonStandard way that is not as powerful as printf(), but is just about as big.

What I really mean is floating point AND standard in/out/err streams... enabled or disabled by the user, via a checkbox in Preferences.

Another thing that you may or may not know is that there are TWO separate "modules" connected with AVR-GCC floating point support.

One handles printf, fprintf, etc... and the other handles scanf, fscanf, etc...

The second one (the scanf support) is a resource hog and (as far as I know) provides very little benefit to the programmer. The first one (printf) adds only about 1.5K to a sketch and is the one most people would probably use.

So, in my Preferences, I have two "floating point" checkboxes... one for printf (which I use all the time) and one for scanf (which I have never used so far).
Title: Re: String concatenation for Serial.print
Post by: krupski on Dec 15, 2017, 09:18 pm
Yes, please [run the test sketches].  This is the essence of forum discussion.  If you disagree, you have to support the argument with something that everybody can reproduce.  Subjective ranting does not nullify the objective measurements.  Show us your actual numbers, and maybe we'll all start using sprintf.
OK, not sure what I'm supposed to be seeing here, but this is the output of your first sketch (only change I made was to set the serial baud rate to 115200 'cause that's what I always use).

The value is currently 0x57 units
274us
The value is currently 0x05 units
240us
The value is currently 0xB3 units
240us
The value is currently 0x60 units
242us
The value is currently 0x0E units
242us


Second test sketch results (at 115200 baud):

The value is currently 0x57 units
324us
The value is currently 0x05 units
326us
The value is currently 0xB3 units
328us
The value is currently 0x61 units
326us
The value is currently 0x0F units
326us
The value is currently 0xBD units
326us

Third test sketch:

The value is currently 0x57 units
206us
The value is currently 0x05 units
206us
The value is currently 0xB3 units
208us
The value is currently 0x60 units
206us
The value is currently 0x0E units
210us
The value is currently 0xBC units
210us



Does this look right? I have no idea what I'm supposed to be seeing.......
Title: Re: String concatenation for Serial.print
Post by: krupski on Dec 15, 2017, 09:44 pm
I didn't say "of" I said "with".  The OP was asking about function overhead and efficiency.  Does your version of code using printf instead of a chain of print calls result in more compact or more efficient code?  Does it meet the requirements of the OP?  Or does it just make for less typing which wasn't what he was asking for.  
Oh I see. I guess I misunderstood your question initially.

Using printf requires setting up small (3 or 4 line) functions to read and write the device (such as Serial or LCD, etc...) then "connect" them to the standard input/output/error streams using the "fdevopen()" function.

Of course, this adds a little bit to both the sketch size (i.e. flash) and sram usage.

Is the resulting code "more compact"? Most probably not. Is the code "more efficient"? What does that mean?  In order to answer that question, I would have to make a test sketch that printed the same thing using one method and the other method and compare execution speed, resource use, etc....

And, is this all there is to the concept of "efficiency"? What about the fact that I can write, debug and finish the code a lot quicker because I don't have to fight multiple print calls?  IMHO, that also counts as "efficiency".

I didn't do this because I don't care one bit if my program takes 300 microseconds to run or 310 microseconds, nor do I care if the program ends up being 22K or 25K in size.

But I DO care about being able to write standard code and have it work the way that I expect it to... usually the first time... as opposed to using a whole bunch of "print" calls and then going back and editing tiny glitches (such as a missing space between a message and a variable display).

I don't understand why everyone is so concerned about microseconds and a few extra K of flash?

If the resulting sketch grew too large to fit then, yeah, fine cut some corners to make it fit. No objections from me.

But when the compiled program takes 22K and I've got almost 256K to load it into, I simply don't care about optimizing down to the last byte. In fact, I may use -O3 instead of -Os... just to drive everyone crazy!  :)
Title: Re: String concatenation for Serial.print
Post by: westfw on Dec 16, 2017, 03:57 am
Quote
There is overhead associated with every and any call of a C function. Parameters have to be placed on the stack, as well as return address and other info.  Calling a function 10 times with a small chunk of data is most certainly slower than calling the function with all the data at once
Maybe.  Most avr-gcc function calls use registers for passing the arguments, up to the point where there are too many arguments to fit in the registers allocated to that purpose.  So calling a function with three arguments several times may in fact be faster than calling a function with six arguments (JUST due to function-call overhead.)  And then both Serial.print() and printf() (every stdio-based hack I've seen for Arduino) end up calling Serial.write() one byte at a time, anyway.   But Serial.write() on AVR arduinos is "light weight" compared to a "real computer" where it might be an operating system call with hundreds of cycles of additional overhead. (but see also my previous message WRT USB and TCP.)  So it gets really complicated trying to micro-optimize this sort of thing.



Quote
I don't understand why everyone is so concerned about microseconds and a few extra K of flash?
One problem is that avr-libc has highly optimized code that implement both stdio "streams" (which are not actually file-system based), and floating point, and floating point output (via __ftoa_engine; recently discussed in another thread.)  So adding printf() adds maybe 1.5k, and adding the floating point version of printf maybe another 2k, and 4k on a chip with 32k of flash isn't really very painful.  (but remember that the first Arduino only had 6k of flash...)
However, other processor architectures aren't as lucky; you don't really appreciate avr-libc until you're forced to use something else.   newlib-nano (used on most 32bit chips) has something like 12k in the integer-only printf(), and 30k+ if you add floating point by using plain newlib instead (which also adds a lot of bloat to stdio/etc.)   That may still be irrelevant on a Due with 512k of flash, but there are smaller ARMs...
So it's not just the actual behavior on AVR that causes printf() to be avoided, but all of it's "reputation" earned on other platforms...

(hmm:  https://github.com/arduino/ArduinoCore-sam/issues/47 (https://github.com/arduino/ArduinoCore-sam/issues/47))



Quote
Any Arduino IDE developer could add these options to the newest IDE in less than a day
Adding options is a whole can of worms.  Atmel Studio has options for this sort of thing; it's a bewildering score or so of panels with strange names that it carefully documents as being equivalent to incomprehensible gcc options :-(

Title: Re: String concatenation for Serial.print
Post by: TonyWilk on Dec 16, 2017, 09:20 am
I found it a pain to type multiple Serial.print()'s for debug output so came up with 'Sprint'.

It just does a real cut-down printf():

Code: [Select]
//
// Example of 'Sprint' - a cut-down printf()
// - saves time typing in debug output for Serial.print
// TonyWilk


//-----------------------------
// Serial.print helper function
// - a real cut-down printf()
//
void Sprint( char *fmt, ... )
{
  char c;
  va_list args;
  va_start( args, fmt );
  while( (c=*fmt) != 0 ){
    switch( c )
    {
    case '%':
      c= *(++fmt);
      switch( c )
      {
      case 'd': Serial.print( va_arg(args,int) ); break;
      case 'f': Serial.print( va_arg(args,double) ); break;
      case 'h': Serial.print( va_arg(args,int), HEX ); break;
      case 'c': Serial.print( (char)va_arg(args,int) ); break;
      case 's': Serial.print( va_arg(args, char *) ); break;
      default:  break;
      }
      break;
    case '\\':
      c= *(++fmt);
      if( c == 'n' )
        Serial.println();
      else
        Serial.print( c );
      break;
    default:
      Serial.print( c );
      break;
    }
    ++fmt;
  }
  va_end( args );
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(19200);
  Serial.println("boot...");
  char *astring= "test string";

  Sprint("This is an example...\n");
  Sprint("int:%d, float:%f, hex:0x%h, char: '%c', string:\"%s\".\nThe end\n",
          42, 123.45, 0xFACE, 'x', astring );
}

void loop() {
  // put your main code here, to run repeatedly:

}


Efficient? well, it's a lot easier to type in "int:%d, float:%f, hex:0x%h\n" than the equivalent in separate statements and it doesn't need yet another buffer (like printf() would).

Anyway, I find it handy.

Yours,
  TonyWilk

P.S. dunno how portable this is across all Arduinos, I dimply remember something about the types used with va_arg causing me some bother. I run only run Arduino Pro Mini (AtMega328).
Title: Re: String concatenation for Serial.print
Post by: Delta_G on Dec 16, 2017, 07:00 pm
I didn't do this because I don't care one bit if my program takes 300 microseconds to run or 310 microseconds, nor do I care if the program ends up being 22K or 25K in size.

But I DO care about being able to write standard code and have it work the way that I expect it to... usually the first time... as opposed to using a whole bunch of "print" calls and then going back and editing tiny glitches (such as a missing space between a message and a variable display).

I don't understand why everyone is so concerned about microseconds and a few extra K of flash?
You seem awfully concerned with yourself here.  The OP was asking about code size and execution efficiency.  That's the only reason I was suggesting that they be used as metric in this case. 
Title: Re: String concatenation for Serial.print
Post by: -dev on Dec 17, 2017, 04:12 pm
Regarding the question about the example sketches:

Quote
Does this look right? I have no idea what I'm supposed to be seeing.......
Yes, each sketch prints a few things, based on your original example sketch in reply #1.  To get a "random" value for printing, it takes the lower 8 bits of the current micros clock:

    value = millis() & 0xFF;

Each sketch grabs the current micros clock value before the print:

    unsigned long start = micros();

and calculates the elapsed time after the print:

    micros() - start

It then prints that elapsed time so you can see how long the print formatting took.  This time is not affected by the baud rate, because all characters are simply added to the Serial output buffer.  Interrupts will eventually send them over the USB, where the Serial Monitor window will eventually read and display them on the PC.

The delay statement at the end gives the interrupts time to empty the output buffer, in the background.

To measure the RAM and program size, get the numbers from the IDE build window.
To measure the execution speed, upload and run each sketch.  The execution time varies by a few TIMER0 ticks (±4us).

Regarding the piece-wise printing technique, I share your annoyance:

Quote
This saves me the headaches of using multiple "Serial.print" calls and makes for easier reading of the source code itself.
... and...

Quote
I found it a pain to type multiple Serial.print()'s
We have discussed this before. (http://forum.arduino.cc/index.php?topic=442691.msg3050710#msg3050710)  If your metric is lines of code, then instead of individual prints:

    Serial.print( "RAM string" );
    Serial.print( f );
    Serial.print( ',' );
    Serial.println( i, HEX );

...use the streaming operators (aka "stream insertion"):

    Serial << "RAM string " << f << ',' << _HEX(i) << endl;

(See correction note below.)

This single line of code can be used in place of printf, and does not use RAM buffers at all.  In fact, it actually resolves to individual Serial.print calls through the magic of C++ templates.  It has the same RAM, speed and program size performance as the piece-wise print technique.  Here is the sketch for comparison:

Code: ("Streaming operators") [Select]
#include <Streaming.h>

volatile int value;

char hexDigit( int v )
{
  v &= 0x0F; // just the lower 4 bits
  if (v < 10)
    return '0' + v;
  else
    return 'A' + (v-10);
}

void setup()
{
  Serial.begin( 9600 );
}

void loop () {
    value = millis() & 0xFF;

    unsigned long start = micros();

    Serial << F("The value is currently 0x") << hexDigit( value >> 4 ) << hexDigit( value ) << F(" units") << endl;

    Serial.print( micros() - start );
    Serial.println( F("us") );

    delay (1000); // print out voltage once a second
}

For more information, see

*  A commonly-used streaming template (http://arduiniana.org/libraries/streaming/) for the Arduino, with similar discussion about multiple print statements.

*  The wikipedia page about C++ operators (https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B) has a footnote (https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#cite_ref-bitshift_3-0) about the << operator also being used for I/O streams.

*  The wikipedia page about C++ I/O (https://en.wikipedia.org/wiki/Input/output_(C%2B%2B)) has a section about formatting modifiers and manipulator (e.g., HEX and endl in the example above).

Notes:

*  The Arduino streaming template does not implement all modifiers and manipulators, but it would not be difficult to fill in the blanks.  You can also provide the missing bits locally, inside your sketch.

*  The Arduino does not really implement the standard I/O stream (with good reason).  The Print and Stream classes are poorly-partitioned versions of ostream, istream and/or iostream (further distractions here (http://en.cppreference.com/w/cpp/io)).
Title: Re: String concatenation for Serial.print
Post by: -dev on Dec 18, 2017, 05:07 pm
Sorry, I have a correction.  This does not work:

    Serial << "RAM string " << f << ',' << HEX << i << endl;

It does in Cosa (https://github.com/mikaelpatel/Cosa), but not in the standard Arduino core.  With the Streaming library, you have to do this

    Serial << "RAM string " << f << ',' << _HEX(i) << endl;

Noted above.
Title: Re: String concatenation for Serial.print
Post by: krupski on Dec 18, 2017, 07:05 pm
And then both Serial.print() and printf() (every stdio-based hack I've seen for Arduino) end up calling Serial.write() one byte at a time, anyway.
I'm not sure that I would consider using a standard AVR-GCC function (fdevopen) a "hack". Anyway, you are right, stdout and stderr do indeed call "xxx.write()" once for each character.  To that I ask "so what?" Are we worrying about data transfer speed?  If so, then why do most people use Serial.begin (9600)?

Getting back to printf and standard IO streams, it's equally easy to connect different devices to different streams. For example, you can connect stdin to serial and stdout/stderr to an LCD display... or even better connect input to serial, output to an LCD and error to a DIFFERENT LCD so that program text and errors display on different screens.

Look how ridiculously simple it is (Stdinout.cpp):
Code: [Select]
#include <Stdinout.h>

// connect stdin, stdout and stderr to same device
void STDINOUT::open (Print &iostr)
{
    open (iostr, iostr, iostr);
}

// connect stdin to input device, stdout and stderr to output device
void STDINOUT::open (Print &inpstr, Print &outstr)
{
    open (inpstr, outstr, outstr);
}

// connect each stream to it's own device
void STDINOUT::open (Print &inpstr, Print &outstr, Print &errstr)
{
    close();  // close any that may be open

    stdin = fdevopen (NULL, _getchar0);
    _stream_ptr0 = (Stream *) &inpstr;

    stdout = fdevopen (_putchar1, NULL);
    _stream_ptr1 = &outstr;

    stderr = fdevopen (_putchar2, NULL);
    _stream_ptr2 = &errstr;
}

// disconnect stdio from stream(s)
void STDINOUT::close (void)
{
    fclose (stdin);
    stdin = NULL;
    _stream_ptr0 = NULL;

    fclose (stdout);
    stdout = NULL;
    _stream_ptr1 = NULL;

    fclose (stderr);
    stderr = NULL;
    _stream_ptr2 = NULL;
}

// Function that fgetc, fread, scanf and related
// will use to read a char from stdin
int STDINOUT::_getchar0 (FILE *fp)
{
    while (! (_stream_ptr0->available()));  // wait until a character is available...
    return (_stream_ptr0->read());  // ...then grab it and return
}

// function that printf and related will use
// to write a char to stdout
int STDINOUT::_putchar1 (char c, FILE *fp)
{
    if (c == '\n') { // \n sends crlf
        stream_ptr1->write ((uint8_t) '\r'); // send C/R
    }

    stream_ptr1->write ((uint8_t) c); // send one character to device
    return 0;
}

// function that printf and related will use
// to write a char to stderr
int STDINOUT::_putchar2 (char c, FILE *fp)
{
    if (c == '\n') { // \n sends crlf
        stream_ptr2->write ((uint8_t) '\r'); // send C/R
    }

    stream_ptr2->write ((uint8_t) c); // send one character to device
    return 0;
}

STDINOUT STDIO; // Preinstantiate STDIO object


Stdinout.h:
Code: [Select]
#ifndef STD_IN_OUT_H
#define STD_IN_OUT_H

#include <Stream.h>

static Stream *_stream_ptr0 = NULL; // stdin stream pointer
static Print *_stream_ptr1 = NULL; // stdout stream pointer
static Print *_stream_ptr2 = NULL; // stderr stream pointer

class STDINOUT
{
    public:
        void open (Print &);
        void open (Print &, Print &);
        void open (Print &, Print &, Print &);
        void close (void);
    private:
        static int _getchar0 (FILE *); // char read for stdin
        static int _putchar1 (char, FILE *); // char write for stdout
        static int _putchar2 (char, FILE *); // char write for stderr
};

extern STDINOUT STDIO; // Expose STDIO object

#endif // #ifndef STD_IN_OUT_H


This simple code, or Serial.print on top of Serial.print on top of Serial.print... ad-nauseaum?
Title: Re: String concatenation for Serial.print
Post by: krupski on Dec 18, 2017, 07:50 pm
Regarding the piece-wise printing technique, I share your annoyance:
I just did a test (not sure how valid it is).

Anyway, this sketch:
Code: [Select]
void loop (void)
{
    // nuthin
}

void setup (void)
{
    Serial.begin (115200);
    Serial.println ("Now is the time for all good men to come to the aid of the party");
}


compiled uses 3578 bytes of flash and 337 bytes of sram (which seems like a lot for a "nothing" program).....

Using Stdinout:
Code: [Select]
#include <Stdinout.h>
void loop (void)
{
    // nuthin
}

void setup (void)
{
    Serial.begin (115200);
    STDIO.open (Serial);
    printf ("Now is the time for all good men to come to the aid of the party\n");
}


compiled it uses 4668 bytes of flash and 358 bytes of sram.

Using printf takes 1090 more bytes of flash and 21 more bytes of sram.

Now, real floating point vs dtostrf:
Code: [Select]
void loop (void)
{
    // nuthin
}

void setup (void)
{
    char buf [16];
    double d;
    Serial.begin (115200);

    d = 123.456789;
    dtostrf (d, 8, 2, buf);
    Serial.println (buf);

    d = 12.3456789;
    dtostrf (d, 8, 2, buf);
    Serial.println (buf);

}


prints this:

123.46
 12.35

resources used: flash 5080 bytes, sram 273 bytes.


Code: [Select]
void loop (void)
{
    // nuthin
}

void setup (void)
{
    char buf [32];
    double d;
    Serial.begin (115200);

    d = 123.456789;
    sprintf (buf, "%8.2f", d);
    Serial.println (buf);

    d = 12.3456789;
    sprintf (buf, "%8.2f", d);
    Serial.println (buf);
}


prints this:

123.46
 12.35

resources used: flash: 6608 bytes, sram: 279 bytes

Difference: 1528 bytes more flash, 6 bytes more sram.

About 1K for printf and about 1.5K for real floating point. Really, I don't think that's bad (IMHO).  :)

Title: Re: String concatenation for Serial.print
Post by: Delta_G on Dec 18, 2017, 08:58 pm
Not bad depending on what you're going for.  Convenience or code size.  I'd like to remind that the OP in this case was concerned with code size and efficiency.  So your answer may be right in some scenarios but is a loser at the metric requested. 
Title: Re: String concatenation for Serial.print
Post by: TonyWilk on Dec 18, 2017, 11:01 pm
Not bad depending on what you're going for.  Convenience or code size.  I'd like to remind that the OP in this case was concerned with code size and efficiency.  So your answer may be right in some scenarios but is a loser at the metric requested.  
Yes, although 'code size and efficiency' is somewhat dependant on requirements; simple debug output is one thing, formatting several lines for an LCD is another.

e.g. I have a project which needs no text output, apart from debug, and is at the point where sprintf() won't fit, so I (obviously) like my mini-printf function because it avoids the overhead in both RAM/ROM of using sprintf(), agrees with my (unreasonable?) loathing of streaming operators, is identical in timing to multiple Serial.print()'s but has the overhead of the function itself (but thereafter is more ROM 'efficient' than multiple calls of Serial.print) which I live with for the convenience.

Now, if 'efficiency' included 'neatness', 'readability' or 'convenience'... there'd be more points of view than programmers :)

Yours,
 TonyWilk
Title: Re: String concatenation for Serial.print
Post by: Delta_G on Dec 18, 2017, 11:44 pm
Point being that there's no *right* answer to the question of which is best.  Only which is best for this particular situation or that one.  And in this particular situation the OP asked about something particular.  All the people going on and on like their solution is the only solution anyone would ever need are deluding themselves. 
Title: Re: String concatenation for Serial.print
Post by: TonyWilk on Dec 19, 2017, 01:02 am
Point being that there's no *right* answer to the question of which is best.  Only which is best for this particular situation or that one.  And in this particular situation the OP asked about something particular.  All the people going on and on like their solution is the only solution anyone would ever need are deluding themselves.  
Completely agree with this.

Yours,
 TonyWilk
Title: Re: String concatenation for Serial.print
Post by: krupski on Dec 19, 2017, 09:19 am
Yes, although 'code size and efficiency' is somewhat dependant on requirements; simple debug output is one thing, formatting several lines for an LCD is another.
When I did 68HC11 assembler programming, I had good luck formatting and printing text on an LCD display simply by making a "virtual" LCD screen in ram, then placing characters and numbers where I wanted them, then called a simple block copy subroutine to copy the "virtual" LCD screen to the real one.

The 68HC11, BTW, only has 256 bytes of SRAM, 512 bytes of EEPROM and a 64K address space (shared by eeprom, sram and registers).

Now THAT'S a processor where you need to watch each and every byte!

Title: Re: String concatenation for Serial.print
Post by: krupski on Dec 19, 2017, 09:22 am
Not bad depending on what you're going for.  Convenience or code size.  I'd like to remind that the OP in this case was concerned with code size and efficiency.
Ah, but what is "efficiency"? Ease of writing code? Easy to read and debug source? Small, compact machine code? Tight, fast running loops?

"Efficiency" can mean many different things.

Title: Re: String concatenation for Serial.print
Post by: TonyWilk on Dec 19, 2017, 10:55 am
Now THAT'S a processor where you need to watch each and every byte!
Getting off-topic now...
Ah yes, programmers these days think they're hard done by with Kilobytes of memory.

Many moons ago I worked for Texas Instruments and then National Semiconductor (now joined) on very early micros. The NatSemi COP400 series was a 4-bit processor with a huge 64 NIBBLES of RAM. You didn't even have a byte to watch.

Can't exactly say those were the good old days tho' :)

Yours,
  TonyWilk
 
Title: Re: String concatenation for Serial.print
Post by: westfw on Dec 19, 2017, 11:17 am
Attiny13, which is sort-of supported by tinycore, has 1k flash and 64byes RAM.
Fortunately, it doesn't have. Serial port, either, so the choice between serial.print and printf is a bit moot.

I would have thought that the atmega48, with 4K flash, would have gotten more attention, but I guess the mega8 passed I in price
Title: Re: String concatenation for Serial.print
Post by: Delta_G on Dec 19, 2017, 03:20 pm
Ah, but what is "efficiency"? Ease of writing code? Easy to read and debug source? Small, compact machine code? Tight, fast running loops?

"Efficiency" can mean many different things.


Efficiency can mean many things.  In this case it was explicitly laid out that the OP was not concerned with it being efficient to write but rather efficient for the processor to run. See reply #4 where the OP made that quite clear.  Seems you're so distracted by your rant about why the IDE doesn't include some feature that you desire that you've completely forgotten that we are answering a concrete question with explicit parameters for which your answer is still wrong.  Changing the question makes it different sure.  But for the question here as asked and clarified in #4 adding extra overhead to have the processor format the text is the opposite of what the OP asked.  You can rant and rave about all the reasons why YOU like this way or that way better.  But the question we are answering isn't about what you like but about which method is less work for the processor.