serial.print and printf

I want to be able to print values inside strings like printf. i know that there is sprintf in stdio.h

My problem that the ide understand only serial.print, so i can not type something like this :

Serial.printf("you have %d hours to come to me",time);

and time should be a decimal like 4.5.
The same problem with sprintf.

I am sure that i miss something here any help?

1 Like

To format output you need to use sprintf to put the formatted text in a buffer then use the normal Serial.print commands to output the buffer. You cannot include formatting commands within the Serial.print commands.

You can influence the output of Serial.print a small amount by using parameters after the value to be printed

Serial.print(variable, HEX);

will print the value of the variable in HEX, for instance and you can also include \t, \n and \r in strings to give a tab, newline and carriage return respectively.

can you give me an example of how will you do the example i wrote before with sprintf ans serial.print?

You should start here, I did. http://www.cplusplus.com/reference/cstdio/sprintf/?kw=sprintf
http://www.cplusplus.com/reference/cstdio/printf/?kw=printf
Read about "dtostrf()" in a thread here: "http://arduino.cc/forum/index.php/topic,37391.0.html"
And this from here :
char* dtostrf ( double __val,
signed char __width,
unsigned char __prec,
char * __s
)
The dtostrf() function converts the double value passed in val into an ASCII representation that 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 '.' 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.

From this reference: avr-libc: <stdlib.h>: General utilities

Bob

The same problem with sprintf.

I don't understand what you mean by that - what is wrong with sprintf (apart from not handling "floats"s)?

Actually, no I can't, sorry.

To save code space the the Arduino version of printf, and hence sprintf, does not include the functionality to output floating point values. Sorry to have got your hopes up.

If you search around you will find methods to get round this restriction if you really want/need to. For example Arduino Float to String | dereenigne.org

can you give me an example of how will you do the example i wrote before with sprintf ans serial.print?

sprintf (buffer, "you have %d hours to come to me",time);
Serial.print (buffer);

In the original example

time should be a decimal like 4.5

What will %d do with that ?

Good point - saw the "%d", missed the ".".
Of course, the OP could always multiply the fraction by ten, and keep everything integer.

Me too originally, hence my back pedalling between my first reply and my second

Discussion about it here:

http://arduino.cc/forum/index.php/topic,146638.0.html

Ultimately, you can either use a patch to your Arduino IDE to enable the "%f" format parameter, or you can use one of the few simple workarounds.

kyrpav,
This is not really an IDE issue.

What you wanting it support for the std C library function printf() to be supported by the Print class.
The Print class is what implements the character output within the Serial object.

The modifications to the code to add it isn't that difficult,
however it requires modifying the Print class code that the Arduino team provides
in their core code.
One of the drawbacks of the xxprintf() routines mentioned by others is the lack of floating point support.
Actually, there is floating point support in the AVR libC library xxprintf() functions, it is just that by default
the xxprintf() routines linked in have floating support removed to save code space.
To enable floating support requires using a different version of the xxprintf() routines which requires
setting a linker option to use a different library. And that is where the problem is, the standard/stock IDE currently
does not provide a way to set the command line options to the linker to specify the floating version of the libraries.
(The IDE has the linker options hardcoded inside the java code)
There is a way to patch your libraries and even some other versions of the IDE floating around that have
been patched to allow setting the linker option from the GUI.
If you search around you can find them.


As an alternative, you can use a wrapper with some clever gcc macros
to provide some simple printf() support for your code.
You will still have to live with the floating point deficiency unless you patch your libraries or
get the IDE that allows setting the linker option.

I have attached example code of how to do this.
This code will create a Printf() function that not only supports printf() capability on the serial port, but also
will automagically move your formating strings to progmem space so it does not eat up precious RAM.

--- bill

serialprintf.zip (755 Bytes)

1 Like

What is the max value of hours and mins? Using multiplication, division and remainder may not be the most elegant solution (and my example below is pretty awful) but should be fast.

float val = 4.5
int ival = int(val * 10.0);
char buf[4];
sprintf(buf, "%d.%d", ival/10, ival%10);

kyrpav:
I am sure that i miss something here any help?

Make yourself these two files and #include them in your sketch:

stdinout.cpp

#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <stdio.h>
#include <stdinout.h>

// Function that printf and related will use to print
static int serial_putchar(char c, FILE *f)
{
        if(c == '\n') {
                serial_putchar('\r', f);
        }

        return Serial.write(c) == 1 ? 0 : 1;
}
// Function that scanf and related will use to read
static int serial_getchar(FILE *)
{
        // Wait until character is avilable
        while(Serial.available() <= 0) { ; }

        return Serial.read();
}

static FILE serial_stdinout;

static void setup_stdin_stdout()
{
        // Set up stdout and stdin
        fdev_setup_stream(&serial_stdinout, serial_putchar, serial_getchar, _FDEV_SETUP_RW);
        stdout = &serial_stdinout;
        stdin  = &serial_stdinout;
        stderr = &serial_stdinout;
}

// Initialize the static variable to 0
size_t initializeSTDINOUT::initnum = 0;

// Constructor that calls the function to set up stdin and stdout
initializeSTDINOUT::initializeSTDINOUT()
{
        if(initnum++ == 0) {
                setup_stdin_stdout();
        }
}

stdinout.h

#ifndef _STDINOUT_H
#define _STDINOUT_H

// no need to make an instance of this yourself
class initializeSTDINOUT
{
        static size_t initnum;
public:
        // Constructor
        initializeSTDINOUT();
};

// Call the constructor in each compiled file this header is included in
// static means the names won't collide
static initializeSTDINOUT initializeSTDINOUT_obj;

#endif

This gives you stdin, stdout and stderr.

So, now "printf" and "fprintf(stdout, ..." will work, as will getc, putc, gets, puts, etc...

Be aware though that the %f format will not work because the Arduino IDE doesn't include floating point support to save sketch size. If you want to add the ability to enable or disable floating point support (via a checkbox in File / Preferences), grab this file: https://github.com/krupski/arduino-1.0.3/blob/master/app/pde.jar (click on "view raw" to download it), then REPLACE your arduino-1.0.x/lib/pde.jar with the downloaded version. Be sure to make a backup copy of your original pde.jar file, just in case!

Note that enabling floating point support will make your sketch about 1.5K larger, so leave it disabled unless you need it.

Hope this helps!

Of course you could use something simple like this.

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly: 
  float f = 1.1;
  Serial.print("report at ");
  Serial.print(f,2);
  Serial.println(" toaday");
}

Mark

The streaming library simplifies all that:

http://arduiniana.org/libraries/streaming/

2 Likes

I've never understood the atraction to C++ streaming i/o.
I simply fail to see how C++ i/o streaming is simpler than simple xxprintf format strings.
Consider these simple examples:

printf("High Score: %04d", score);
printf("Time: %02d:%02d.%02d", hour, min, sec);
printf("Voltage: %04.2fv", volts); // volts is a float

These types of things are not easy to do with C++ streaming i/o
but are trivial to do with xxprintf() formatting strings.

--- bill

But where does printf go to?

What is complex about this?

#include <Streaming.h>

int hour = 5, min = 23, sec = 14;

void setup ()
  {
  Serial.begin (115200);
  Serial << "Time: " << hour << ":" << min << ":" << sec << endl;
  }  // end of setup

void loop () { }

The printing line outputs things in sequence, it's pretty easy to follow, and to write. You don't need an external buffer to "sprintf" into.

1 Like

It does to stdout.
As long as you set up your stdout it will go wherever you want
(A serial port, an lcd, a graphical LCD, etc...)
In my case I didn't actually use printf() because I wanted some additional
functionality.

The printing line outputs things in sequence, it's pretty easy to follow, and to write. You don't need an external buffer to "sprintf" into.

The biggest issue that I have with C++ stream i/o is, that it can't format the text like in the examples I showed
that used xxprintf() formatting.
Things like 0 (zero) filling or space/width padding on numbers or strings are not so easy with stream i/o.
As far as an external buffer goes, when things are setup correctly, you won't need an external buffer because
you won't be using sprintf().

One of the things I really like about the Printf() function/wrapper example I provided earlier is that
it also pushed all the literal strings into AVR progmem automatically without the user having to know
or deal with it.

There are so many macro wrappers that can be done when using xxprintf() routines to
aid in debugging because of the variable argument methodology of the xxprintf() routines.
For example, with a simple single macro change, you can have all your debug output now include the
file name and line number within your code or make all the debug output completely disappear
or like in the example I provided, even automatically push all the formatting strings into AVR progmem.
This kind of stuff is difficult if not impossible with stream i/o.

--- bill

1 Like

bperrybap:
One of the things I really like about the Printf() function/wrapper example I provided earlier is that
it also pushed all the literal strings into AVR progmem automatically without the user having to know
or deal with it.
...
This kind of stuff is difficult if not impossible with stream i/o.

You can keep the literals in program memory:

#include <Streaming.h>

int hour = 5, min = 23, sec = 14;

void setup ()
  {
  Serial.begin (115200);
  Serial << F("Time: ") << hour << F(":") << min << F(":") << sec << endl;
  }  // end of setup

void loop () { }