Over the years, I have written firmware for test equipment, that has used the Arduino microcontroller for the central processor of the unit. A useful thing to do is to know the date and time the firmware on the device was compiled—either so that it can be displayed on an attached screen, or sent over the serial console.
The Arduino compiler (a sort of c compiler or c++ compiler) has a couple of macros or Compiler Directives that can be used to capture the date and time that it was run, these are __DATE__ and __TIME___. The compiler expands These two compiler directives when it is run, replacing the placeholders with the value from the computer on which the Arduino source code was compiled. I use #define to store these in the compiled hex file. Because the value should be immutable, and never need to be updated by my program, I can use define.
One of the advantages of using definitions is that they don’t take up memory space.
/// These are found and replaced by the compiler, so they don't take any memory space.
#define CompileDate __DATE__
#define CompileTime __TIME__
Compiling the code at 20:50 on the 11th of June 2024 will replace CompileDate with the value “Jun 11 2024” and CompileTime with the value “20:50:01” anywhere in the referenced code.
Copyright year
Similar to getting the compilation date and time for keeping track of which version of the software your device is running, you can get just the four-digit year value and can print it when required, annoyingly I can’t seem to get it from the same compiler directive and have it compiled in when I compile the Arduino sketch.
/// This stores CompileDate in a string
String CompileYear = CompileDate;
I find this useful when wanting to return the copyright year.
Compiling it all together
Near the top of my code, I have the following block, that initialises these values for a project.
/// These are found and replaced by the compiler.
#define CompileDate __DATE__
#define CompileTime __TIME__
String CompileYear = CompileDate;
/// These are for returning copyright information, and storing this information in the code.
const String Copyright = "Philip McGaw"; ///< Copyright company / person's name.
String Product = "ProjectName"; ///< Project name. (Updated when I make a release).
int Hardware_Rev = -1; ///< Placeholder - Takes the value of the VERSION_PINS.
String Serial_Number = "-1"; ///< Placeholder - This is the serial number of the microprocessor.
const int Software_Version = 1; ///< Firmware version. (Updated when I make a release).
The hardware revision is managed using two resistor dividers between VCC and GND, I will cover this more in a second post, and will also cover the serial number part in a different post.
Reading it out
This is an example of the code allowing the data to be sent out via the serial port.
CompileYear = CompileYear.substring(7, 11); ///< Cuts the string so it just contains the year.
Serial.println((String) "© " + Copyright + " " + CompileYear + " - " + Product);
Serial.println((String) "Software Version: \t\t" + Software_Version + " (" + CompileDate + " " + CompileTime + ")");
Serial.println((String) "Hardware Version: \t\t" + Hardware_Rev);
Serial.println((String) "Serial Number: \t\t\t" + Serial_Number);
Serial_Number and Hardware_Rev should both be -1, as they are not set in the code above.
7 thoughts on “Storing when an Arduino sketch was Compiled”
I do this with all my code. I dump the project name I gave it, it’s last revision number, and the date. It does help for sure.
Do you have it automated?
That is a very interesting post. I hope you will post the two others posts soon. Since these three topics are so interrelated, I can imagine that a single article covering all three topics would be very valuable.
There’s a number of standard predefined macros that are pretty useful. I always include the following as the first line in the setup() function of any Arduino code I write:
Serial.println(__FILE__ __DATE__);
Which will print the name and location of the .ino sketch and the date/time at which it was uploaded to the board.
Then, whenever I find a stray Arduino lying about, I can just plug it in, load up the Serial monitor, andI can see exactly what sketch and version it is running.
Do you know if there is a list of them all?
These are the standard ones defined by the GNU C compiler: https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
Then there are the platform-specific defines that enable you to target certain board artchitectures, e.g.:
#if defined(AVR_ATmega1280) || defined(AVR_ATmega2560);…
So nothing really in addition that is very helpful.