Today I had a code that sometimes is used with an I2C-LC-Display
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4); // adjust to the right I2C of your device
lcd.init(); // initialize the lcd
lcd.backlight(); //Backlight ON if under program control
and
and some other times used with a non-I2C-LC-Display
I understand how this works but I have not yet used it myself.
Before using it myself I want to ask if there are any traps I could fall in
by using compiler-conditions
I guess with this stuff you could write code that is more complicated to analyse than brainf**k because it adds a new level of complexity which lines have been compiled and which not??????
not sure what you mean by "trap". of course ifdefs or conditional code this can be misused or used improperly.
when properly used, it allows code to work on different hardware, both processors or peripherals, which is much better that having entirely separate programs.
when used properly, it should have a minimal affect. for example, some processor/HW dependent code should be isolated to as few functions as possible and code within those functions made processor/HW dependent.
the #error directive can also be used in an #else case if none of the previous conditions apply. For example, what should happen if you code is compiled for Arduino. #error will generate an error as if it were a compiler error, preventing a success compile that may actually not work.
if there's an ifdef for a symbol that is not defined , a #else and #error will generate an error during compilation. you won't need to check at run-time
from work we learned to have a way to identify any version of code the left our lab. we just used date codes (e.g. 210609e). i would find i'm not using the code i just tried compiling.
when testers found problems, we would first ask what version and we often found out they weren't using the correct version.
so when you consider identifying your code, you might consider adding a version as well. you may find it saving you hours of frustration
the PrintFileNameDateTime shall do that. Though the disadvantage is that the source-code-file-timestamp could be modified through simply saving it again.
Setting a firmware-version-code before delivering or publishing is a very common thing.
And after a lot of testing it is worth the effort to manually change the firmware-number.
But I don't do that for each minor or temporarly changes. That's why I use the filename and file-timestamp
best regards Stefan
Typically you would use symbols already defined by the compiler or pass them as arguments during compilation.
Otherwise the order the files are processed can be relevant.
Edit:
As an example in the link below you can find a list of built in macro's for the avr-gcc compiler.
For instance:
__AVR_Device__
Setting -mmcu=device defines this built-in macro which reflects the device’s name. For example, -mmcu=atmega8 defines the built-in macro __AVR_ATmega8__, -mmcu=attiny261a defines __AVR_ATtiny261A__, etc.
The built-in macros’ names follow the scheme __AVR_Device__ where Device is the device name as from the AVR user manual. The difference between Device in the built-in macro and device in -mmcu=device is that the latter is always lowercase.
If device is not a device but only a core architecture like ‘avr51’, this macro is not defined.
So to compile something only on an ATtiny85 you would do the following
#if defined(__AVR_attiny85__)
// some stuff
#endif