I recently came up with a handful of small macros that have been helpful in debugging, enough to warrant me creating a small 'MacroTools.h' file I've been including in my projects.
It's only small but I intend to add to it and was inspired by the start of a video I saw on competitive programming. This guy was #define'ing and typedef'ing all sorts like vectors of vectors of pairs of ints to be like vvpii() and all sorts.
Do you have any macro / #define tools or utilities you like to use often from program to program?
The trace... I quite often find it very helpful when debugging to check that the program flow has reached a certain place or not (function, constructor etc). I used to litter the code with
I make very little use of macros. You will note the use of I, me and mine when ppl talk about them and
it can make code hard to read if they aren’t entirely obvious. I read more than I write.
I’ve had to work some code where the original author, a not-C programmer, had rigged up all kindsa macros so his code looked like Pascal or whatever not-C language he’d rather have been using.
It was impressive the extent to which he could…. but very annoying and rude.
With tiny programs on small systems I prefer to write in C and leave libraries and frameworks and RTOSs and macros of any complexity for places where they are more like essential.
Debugging macros is probably the one place where I bend the rule. Since code I write never has any bugs, I have found it unnecessary to roll my own set of those, and they are easily seen for what they are as I read other ppls code.
You might not, but the Arduino Core and probably every library you use will
So you do use them, just passively! If it's good enough for them, and it makes my life easier, then I'm happy to use them. Typing out that 'trace' even once was a pain!
I do have some #ifdef's in some places. Notice that the effect of an ifdef to guard against multiple includes has a very LOCAL effect. It does not really influence the code that follows...
st3v3n92 So you do use them, just passively! If it's good enough for them, and it makes my life easier, then I'm happy to use them. Typing out that 'trace' even once was a pain!
Using existing macros is a different thing than creating them.
no they are known as "conditional compilation directives" but they usually work in conjunction with a macro (although the expression they deal with just has to be a constant expression)
Macros can be useful for writing code which can be compiled for different processors, but these would probably be too specific to be candidates for inclusion in a general macro toolbox.
// start of macros dbg and dbgi
#define dbg(myFixedText, variableName) \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope
#define dbgi(myFixedText, variableName,timeInterval) \
do { \
static unsigned long intervalStartTime; \
if ( millis() - intervalStartTime >= timeInterval ){ \
intervalStartTime = millis(); \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName); \
} \
} while (false);
// usage: dbgi("2:my fixed text",myVariable,1000);
// myVariable can be any variable or expression that is defined in scope
// third parameter is the time in milliseconds that must pass by until the next time a
// Serial.print is executed
// end of macros dbg and dbgi
void PrintFileNameDateTime() {
Serial.println( F("Code running comes from file ") );
Serial.println( F(__FILE__));
Serial.print( F(" compiled ") );
Serial.print(F(__DATE__));
Serial.print( F(" ") );
Serial.println(F(__TIME__));
}
boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - periodStartTime >= TimePeriod )
{
periodStartTime = currentMillis; // set new expireTime
return true; // more time than TimePeriod) has elapsed since last time if-condition was true
}
else return false; // not expired
}
unsigned long MyTestTimer = 0; // variables MUST be of type unsigned long
const byte OnBoard_LED = 2;
void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
static unsigned long MyBlinkTimer;
pinMode(IO_Pin, OUTPUT);
if ( TimePeriodIsOver(MyBlinkTimer,BlinkPeriod) ) {
digitalWrite(IO_Pin,!digitalRead(IO_Pin) );
}
}
void setup() {
Serial.begin(115200);
Serial.println( F("Setup-Start") );
PrintFileNameDateTime();
}
void loop() {
BlinkHeartBeatLED(OnBoard_LED,500);
if ( TimePeriodIsOver(MyTestTimer,1000) ) {
}
}