Learning to use Functions

1 or more people on this forum pointed out to me that I should use functions instead of writing everything multiples times.

So, time for me to learn functions... :)

I already hit a very big question mark;

I always understood that the sketch is being run from top to bottom, executing void setup once and the loop over and over again.

That is why I do not understand the tutorial below:

https://startingelectronics.org/software/arduino/learn-to-program-course/15-functions/

They call the function in SETUP and create it in LOOP.

HOW? The first and only time SETUP is run, the function does not exist and after that they looping the creation of the function.

It just doesnt make sense to me. Sorry for being a noob but I have a very steep learning curve and just want to understand.

Thanks!

No it's not created in loop(), it's created outside loop() below it.

C purists would put the creation of dashedLine() (or at least its empty prototype) above setup() so that setup() knows about it. But I gather the IDE does some helpful voodoo for us, and behind the scenes scans ahead so to speak, and knows dashedLine() is there before setup() needs it.

Oh ok, I see. (duh).

But the sketch only reaches that point after SETUP?

What is the order that IDE "reads" the sketch? VooDoo indeed ;-)

Sareno: Oh ok, I see. (duh).

But the sketch only reaches that point after SETUP?

What is the order that IDE "reads" the sketch? VooDoo indeed ;-)

My understanding is that the pre-processor looks ahead at compile time, so when it makes the executable it knows where it put the functions in memory. Then when setup() runs, and calls dashedLine() it knows where to go already.

But afaik, not all C compilers are that helpful, and if you don't put your functions "above" the point where they get called from, it will indeed complain. Arduino is written for us hobbyists, who don't necessarily want to become C gurus, so it eases the way for us.

edit: don't forget this is a compiled language, so when it makes one big digital blob of your code it knows where everything is. The fact that setup() is above dashedLine() in the source is irrelevant by that stage. If it was an interpreted language, where it executes from the top down without having a big blob already, that's different.

I always understood that the sketch is being run from top to bottom

That would be completely incorrect. Code outside of your sketch (a function called main()) calls setup(), and then calls loop() repeatedly. Those functions need not be in order in your source code. You should be able to find MANY examples were "utility" functions are defined in sketches before setup() and loop() - its a popular style (sometimes sort-of known as "bottom-up programming") because of the way that C used to require that a function be defined or declared before it was used. (in modern times, most functions in large C programs will get declared in .h files anyway, and the Arduino Environment will generate declarations for you automatically.)

Don't worry about that. Just take the habit of writing a function A that will be called by another function B before that function B, where B can also be setup or loop. For example:

void functionA () {}
void functionB () { functionA(); }
void setup () {}
void loop () { functionB(); }

At the hardware level, on an AVR (it works differently for different types of CPU), the execution after a RESET starts at very beginning of program memory (programCounter = 0) The compiler arranges for that to be a jump to the "C Startup Code", which does some primitive initialization (by name, more or less), and then goes to the main() function. In Arduino, main() does additional initialization and calls setup() (main, setup, and loop are all just functions.) After calling setup(), main() has an infinite loop that calls loop() over and over again (with a bit of extra code.)

All of this is done with numeric address that the compiler figures out from the names when you build the sketch. So only the "start at 0" is a hard requirement. Sort of:

start at 0 jump to 68, where the C startup happens to be. call to 200, where main() lives. call to 600, where setup() lives. loop, calling 400, where loop() happens to be.

(some of this is lies. Because Arduino has a bootloader in there as well.)

12Stepper: My understanding is that the pre-processor looks ahead at compile time, so when it makes the executable it knows where it put the functions in memory. Then when setup() runs, and calls dashedLine() it knows where to go already.

It's not so complicated as that. The way it works is the Arduino sketch preprocessor generates function prototypes for any function in a .ino file that doesn't already have a manually created function prototype and inserts those prototypes at the top of the file (being careful to put them in the right place and order). It then compiles the .ino files as a standard C++ file, using a standard C++ compiler.

But the whole point of it doing that is so that beginners don't need to think about function prototypes. So my advice to Sareno is to not worry about this function prototype thing. All you need to know is that you can define functions in any order you like. This is useful because it allows you to organize your sketch as you wish.

Sareno, you are correct that the code in the functions is executed from top to bottom. However, the functions themselves are only executed as they are called. If you define a function in your sketch and never call it in the code, then the function's code is never exectuted. So then what about the setup() and loop() functions? Well, these are actually called by a special function named main() that's hidden away in the Arduino core library. main() is the only function that will automatically be executed. The main() function calls the setup() and loop functions. It looks something like this:

int main() {
  setup();

  for (;;) {
    loop();
  }

  return 0;
}

They are executed in the order they are called, first setup(), then loop() over and over forever. You could just as well write a sketch where loop() is defined before setup() and setup() will still be called before loop()

Wow, Thank you for this feedback.

I have a very ambitious project and love learning this stuff. Thanks!

Sareno: I have a very ambitious project and love learning this stuff. Thanks!

There will be state machines in the mix too, most likely.

Yes, there will be. :slight_smile: