Skip to main content

Anytime you define a variable inside a function, it is temporary. It disappears when the function is completed. This is called going out of scope. The "now" variable does not remain valid after the "loop" returns (by falling off the end of the curly bracket). It's value is lost. But that's what you want. You don't need that value to remain after it has been evaluated.

The "startTime" however, because it is declared outside of the "loop" function remains valid between executions. Thus, when the "loop" function is executed again, the "startTime" value is still available and valid.

When a variable is declared outside of any function, it's scope is global. That means that it can be accessed by any function in your program. But the use of global variables is discouraged for the same reason. Because it can be modified by any part of your program, it becomes difficult to keep track of where these modifications take place. It is better to use "globals" sparingly and only for limited specific purposes.

In order to keep this explanation simple, I lied about the scope of the "now" variable. It does not remain valid throughout the "loop" function. For that to be true, you would need to declare "now" at the beginning of the function like this:

...
void loop () {
  unsigned long now;
...

The way I did it in the example, it has scope (is valid) only within the current block of code. Since it isn't used anywhere else, that's OK. I don't recall the exact rules on scope but that value generally goes out of scope at the next closing curly bracket -- "}". If you try to use it anywhere else, the compiler will just shake its head. 

Note also that the "now" variable is not really necessary. I used it just to illustrate and to name what that value represents. The code could have been written this way just as well:

...
if (millis() - startTime >= 5000) {
...

There are lots of ways to write a program. Just use what you know and move on. There are constructs in the C++ language that I never use at all. Keep it simple and understandable for the next guy that has to trudge through your horrible code. Programmers expect to make mistakes all the time. It goes with the territory.

For more information on scope, see this section of the Arduino reference material.

Last edited by Consolidated Leo

Thanks, very good explanation! I didn't realize the 'now' variable would go away after it served it's purpose. I guess it would be good for memory saving with the limited memory of the Uno if one needed to do so? Probably not necessary in my case. I can cobble together some simple programs, but it's these little tips that I have trouble figuring out on my own sometimes. Then there is the part about remembering all the tips or at least trying to... Many times sleeping gives me a clean slate the next morning! 

This is a pretty good article on the Arduino preprocessor. It explains that the first thing that happens to your program when you build it is to run it through the preprocessor. This is a process that handles all the lines in your program that begin with the pound sign (#) character; like #define and #include. These are known as preprocessor directives.

The Arduino preprocessor is a hold-over from the days when the C programming language was first developed at Bell Labs decades ago. It is in fact still referred to as the C preprocessor by it's current supporters; the GNU Software Foundation. This version is widely used by C/C++ developers throughout the world. The official technical documentation can be found here.

The preprocessor is a kind of substitution machine. It takes your original program, substitutes text according to the instructions and definitions laid out by the preprocessor directives and spits out a new version of your program.

For example. The #define directive takes an identifier and a substitution string:

#define LIMIT_SWITCH_PIN 4

Here the identifier is "LIMIT_SWITCH_PIN" and the substitution string is "4". Following this definition, anywhere in your program where the identifier appears, the text string will replace it.

int limitReading = digitalRead(LIMIT_SWITCH_PIN);
becomes
int limitReading = digitalRead(4);

Note that preprocessor directives are not part of the programming language and do not end with a semi-colon.

There is more to #define than simple substitution but you can look into that yourself if you're so inclined. The other directive that is often used in Arduino programs is #include. That's how you tell the build process that you want to use a library:

#include <Servo.h>

The preprocessor will look for the file "Servo.h" in the usual place that libraries are located and pull the text from that file into your program. Again, no semi-colon. The new version of your program spit out by the preprocessor will now have a copy of that file placed where the #include directive appears.

There are other tricks to using the preprocessor that are useful in a different context. But for now, that's all that needs to be said.

Add Reply

Post
×
×
×
×
Link copied to your clipboard.
×
×