IF statement before setup

Hello Forum,

I wrote a sketch that I use on more than one device, but in this sketch there are several if statements that need to change specific to each device.

Currently before uploading the sketch to different devices I have to go through and comment out some if statements and de-comment the correct if statements that deals with that specific device.

What I’ve done now is to have a variable “unitname” with the value “P1”, “P2”, “P3” etc. This specifies which unit is being used. I changed my code so that all the if statements that follow in the sketch will automatically come into play correctly as long as the correct value for “unitname” is specified at the top of the sketch.

The challenge I have to is give the correct values to a few variables upon initialisation, their values depending on what the unit name is.

So my question, can I run an if statement when initialising variables?

Something like this:

if (unit == "P1")
  float homeDegrees = 200.04;
if (unit == "P2")
  float homeDegrees = 30.04;

The above syntax obviously does not work above setup, where all the global variables are defined. I can do this later in the sketch, but it would be nice to have it done before setup and get it over with.

Is this possible?

You cannot have program statements outside of a function but you can have preprocessor directives such as #if, #ifdef and #endif outside of functions. Using these would allow you to #define values at the start of the program and have the program automatically adjust to the value(s) given

A Google search or a search of this forum should reveal all

heinburgh:

if (unit == "P1")

float homeDegrees = 200.04;
if (unit == "P2")
 float homeDegrees = 30.04;

maybe use ifdef preprocessor ie

//initially define your P
#define P 1

#if P==1
const float homeDegrees = 200.04;
#elif P==2
const float homeDegrees = 30.04;
#else
const float homeDegrees = 20; //whatever value you using for P3
#endif

Thanks!

I'd be tempted to store the unitname in EEPROM. Then the code on each device can be identical and when you make a code change, you don't have to fiddle around making manual changes to P as you upload the new version to each device.

Doesn't all this preprocessor stuff happen at compile time? The compiler won't know what's in the EEPROM.

Indeed. I'm suggesting forgetting the preprocessor and just run a set of if statements at the top of the setup function. I'd rather sacrifice some space (code and RAM) for the benefit of having the exact same code on each device.

wildbill:
Indeed. I'm suggesting forgetting the preprocessor and just run a set of if statements at the top of the setup function. I'd rather sacrifice some space (code and RAM) for the benefit of having the exact same code on each device.

That's smooth. I'll write a function that executes in the beginning of setup, asking if a new unit name should be saved - if no serial input for 5 seconds, it continues to read whatever name is in eeprom. If the sketch is to be loaded to a new unit, simply enter the new unit's name during setup and the sketch does it all from there.

Great idea, thanks

It would depend on whether you know the platform ahead of compilation, which in all but the most generic cases you must. The compiler needs to be instructed which board package to pull in and this information is available to the pre-processor. The code can be the same for every installation, no need for changes. Given that the board definition is available, you can conditionally compile without changing anything. This is an example that alters the pointers to the USART ISR and defines the on-board LED based on Uno or Mega,

#if (defined (__AVR_ATmega328P__) || defined (__AVR_ATmega328__))
    #define UNO
    #define LED_PORT        PORTB
    #define LED_PIN         PB5
    char BOARD[]      = {"m328p"};
#elif defined (__AVR_ATmega2560__)
    #define MEGA
    #define USART_RX_vect   USART0_RX_vect
    #define USART_UDRE_vect USART0_UDRE_vect
    #define LED_PORT        PORTB
    #define LED_PIN         PB7
    char BOARD[]      = {"m2560"};
#elif defined (__AVR_ATmega168__)
    #define UNO
    #define LED_PORT        PORTB
    #define LED_PIN         PB5
    char BOARD[]      = {"m168"};
#else
    #warning "device type not defined"
#endif

Another, selectively constructs a struct based on a defined BUFLGTH by users' code prior to inclusion,

typedef struct                  // FIFO
{
    byte    available;
    #if BUFLGTH == 8
        byte data[8];
        byte next:   3;
        byte first:  3;
        byte unused: 2;
    #endif
    #if BUFLGTH == 16
        byte data[16];
        byte next:   4;
        byte first:  4;
    #endif
    #if BUFLGTH == 32
        byte data[32];
        uint16_t next:   5;
        uint16_t first:  5;
        uint16_t unused: 6;
    #endif
.
.
.

If, on the other hand, you are looking for a table of values to choose from and these are constant, think about storing them in Flash with PROGMEM.

On the third hand, if you're talking about persistent data that may be altered through a configuration or setup operation, EEPROM is the way to go.

Confused yet?

DKWatson:
Confused yet?

You lost me mid first sentence.

But certainly something worth looking into, I'll see if I can wrap my mind around it.

Thanks!

If you look into the actual instructions issued to the compiler you see a switch similar to -mmcu=atmega328p. If you're compiling from the command line you need to include this, or one like it depending on the board. From within the IDE, it's done for you based on your board selection.

Once specified and the board package is included for that processor, there exists a definition in that file such as #define AVR_ATmega328P.

You can now test for this definition in your code with pre-processing directives;
#ifdef AVR_ATmega328P
// do something
#endif
and whatever the 'something' is gets done during compilation. If the test fails, the statements between if/endif are ignored. They add no weight to your compiled code and only take up space in your editor.