It may be that everyone here already knows this technique, but I'll risk a repeat here.
During development, we all use Serial.print() to help debug our code. When things seem stable, we go back and remove the debug code...only to find out a few days later that we need the debug code...again. My solution is to leave this "scaffolding code" in the source file, but toggle it out for the release version. To do this, add:
#define DEBUG 1
at the top of the source (sketch) file. Where you have debug code, surround it with another preprocessor directive:
As long a DEBUG is define, the debug statements are compiled into the current sketch. However, changing the first line to:
//#define DEBUG 1
makes the preprocessor define for DEBUG disappear by commenting it out. Since it is no longer defined in the program, anything between the #ifdef and #endif is no longer part of the source file from the compiler's point of view. This makes it easy to add and remove debug code. On my most recent project, the code size was about 11.8K with the #define for DEBUG, and 8.2K when it was undefined (I seem to write a lot of buggy code).
Yep, that would work too. Question: Wouldn't this macro approach require the #ifdef-#else-#endif to surround every statement in a block of debug statements? If so, the macro approach would require more typing, right?
I should point out that I've been using this approach (though not exactly these macros) for the last 15 years or so, in applications and systems software, from Linux device drivers to mobile phones.
The Linux macros were even more advanced, and allowed selective masking and unmasking of individual routines' debugs at run-time.
It's worth spending some time on a simple debug header file that you can use anywhere.
With multi-line macros (don't forget the backslash) you can do all sorts of stuff.
On a memory-limited Arduino, this may not be so useful, but you can print lots of useful info, so a simple:
DEBUG_PRINT ("I'm here");
could get printed as:
"my_program.c::myFn line 1451 @ 1121 milliseconds I'm here"
by using FILE, FUNCTION, LINE and "millis" and a few prints.
Save this as sketchbook/libraries/DebugUtils/DebugUtils.h and restart Arduino IDE. You can then click on Tools -> Import library.
The FILE constant doesn't print just the file name, but also the relative path to it. This is something that should be addressed, but I don't know how at the moment.
Building on the above comments, here's my improved version which supports the DEBUG flag.
DebugUtils.h:
/*
DebugUtils.h - Simple debugging utilities.
Copyright (C) 2011 Fabio Varesano <fabio at varesano dot net>
Ideas taken from:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1271517197
This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEBUGUTILS_H
#define DEBUGUTILS_H
#include <WProgram.h>
#ifdef DEBUG
#define DEBUG_PRINT(str) \
Serial.print(millis()); \
Serial.print(": "); \
Serial.print(__PRETTY_FUNCTION__); \
Serial.print(' '); \
Serial.print(__FILE__); \
Serial.print(':'); \
Serial.print(__LINE__); \
Serial.print(' '); \
Serial.println(str);
#else
#define DEBUG_PRINT(str)
#endif
#endif
In your code, you'll have to insert
#define DEBUG
#include "DebugUtils.h"
Then simply use DEBUG_PRINT("message"); to print your debugging message.
Or if you don't want the debug messages to appear simply comment out the DEBUG definition
//#define DEBUG
#include "DebugUtils.h"
And you won't need to comment out any DEBUG_PRINT calls.
yeah.. that file became part of a project I'm working on which won't be public until the next year. That's why my text editor added that lines. I wouldn't claim any copyright on something I just copy and pasted from here.
I have something I can describe but not post (code ownership issues). I have functions to do diagnostic printing and I sprinkle them all over the place and leave them there. I monitor the serial port for a command to turn diagnostics on. I also have a command that can be received via xBee on a different serial port (on a MEGA) to turn them on. When turned on, they begin printing to the port they were enabled from. So I might be running code and wonder why it is acting oddly, run a terminal emulator connected to a USB explorer with an xBee and send the Arduino a command to start giving me diagnostic output. A major advantage to this approach is that I can enable diagnostics after I get it in some odd state. I also have a verbose switch, so some o my diagnostics I change to only show when in verbose mode. I also implemented some general purpose diagnostic commands to read or set any pin or get current values from some of my modules. It took some work to get this operational and it pretty much requires a MEGA as the development board, but it makes life so much easier.