printf in arudino works.
December 21st, 2010
I’ve always had to deal with the fact that printf() is missing from the arduino environment. I would have to come up with these huge blocks of code consisting of multiple Serial.print() commands to put together a simple message. Well, no more! It seems that printf works just fine, and for some unknown reason, it’s just not used or talked about.
In order for it to work, you only need to specify a target for STDOUT by adding this function..
int my_putc( char c, FILE *t) { Serial.write( c ); }
and inside the setup() function you need to point to that function
void setup() {
…
fdevopen( &my_putc, 0);
}
That it! Now printf() works!
Serial.println("START"); fdevopen( &my_putc, 0); printf("hello, world!");
Why this isn’t documented, I have no idea!
Hi,
Great idea. I tried it and it works pretty good. I am having trouble printing floats though. Any ideas?
Thanks,
Paul
Yeah, I noticed that two. The problem is that printing floats use a lot more code space so they have two different libraries, one with float support and one without. In AVR studio, you get to pick it by linking one of these two libs:
libprintf_flt.a (float support)
libprintf_min.a (no float support)
In addition you need to add “-Wl,-u,vfprintf -lprintf_flt” to the linker options. Unfortunately, so much of how the arduino compiles is behind the scenes that I’m not sure how to set the libs and linking options.
Total noob here, I needed to add Serial.begin(9600); as well to make this work.
Reza, thanks for posting this fdevopen fix for printf.
I successfully got an Arduino sketch to build with floating point support linked into stdio. But it didn’t generate any serial I/O and I settled for sprintf-ing my formatted data to a buffer and then serial.print-ing the resulting string.
(Btw, where does STDOUT go by default in the Arduino/avr-Libc environment?)
The Arduino build process isn’t as obscure as it first appears. The IDE just doesn’t provide a convenient way to modify it.
Under File->Preferences, turn on “Verbose” output for both “compilation” and “upload”.
Now when you build and upload your sketch, the text in the status window will contain the command lines used to build and upload the program.
You can copy and paste from the window, extract the relevant lines, and modify them to make your own custom build script.
The build process goes like this:
1. avr-gcc to build a SketchName.cpp.elf object file.
2. avr-objcopy builds a SketchName.cpp.eep file from the .elf file.
3. avr-objcopy builds a Sketchname.cpp.hex file from the .elf file.
4. avrdude uploads the .hex file to the Atmega chip.
After you get the sketch built conventionally, with the IDE, its Temp directory will be full of various object files.
I re-built my sketch, from the Windows command line, adding the following to the avr-gcc invocation:
-Wl,-u,vfprintf,-lprintf_flt,-lm
(Those commas are probably important. See this AVR Libc manual section:
http://www.nongnu.org/avr-libc/user-manual/using_tools.html#using_pass_ld_opts )
That was inserted between the first and second existing arguments:
“avr-gcc -Os -Wl,–gc-sections” Wl OPTIONS HERE “-mmcu=atmega328p”.
And I changed the name of the .elf file from SketchName.cpp.elf to NewName.elf.
Then I changed the filenames in the avr-objcopy commands to match.
And I uploaded my NewName.hex file by similarly modifying the filename in the avrdude command.
So, it CAN be done. I just wish the IDE made it easier.
@ArdArg Thanks for the replay and sorry for the delay in my finding it.
STDOUT by default goes to whatever function you configure with fdevopen(). If nothing is configured then it gets dropped.