Overview of this Chapter
A complete overview of this course can be found here: Course Overview.
What are Functions and Why do we need them?
Theoretically we do not really need functions … however, without functions our code would become super long and completely unreadable. Not to mention; we’d have to write a lot more code.
We have already worked with 2 functions that are required for your Arduino: “setup()” and “loop()”.
But what are functions and why do we need them? Or better said: why do we like them?
A function (also called: subroutine) can be seen as a set of instructions, grouped together, with a specific task in mind.
We can create a function to keep our code more readable, or because we’d like to use that particular task in several locations of our program(s).
It’s called “subroutine” in some languages, because that’s what it is; see it as a little program on it’s own. And as with a regular program, a function can therefor also have other functions defined inside it, and that brings us to another issue to pay attention to: A function has a scope, just like with variables – the “area” in which it can be seen and used!
I realize this is a little bit much to grasp right away, but it is something to keep in mind.
We can define functions that does return a result (value) or does not return a result.
The latter, not returning a result, is called a “procedure” in other programming languages. The language C however calls both just a “function”.
A function, is a group of instructions for a specific task.
When do we define our function?
- When code is repeated more than once in my program
- If my code becomes more readable with functions
- If my code becomes more manageable with functions
- If we’d like to re-use a piece of code for example in other programs
Let’s look at an example of what a function could be – just to grasp the concept.
Say we have a dog, which needs walking 4 times a day: At 8 AM, 12 PM, 5 PM, and at 9 PM.
The task of walking the dog involves:
– Put on a coat
– Put on the leash of the dog
– Go outside
– Walk through the park for 15 minutes
– Go back inside
– Take off the leash of the dog
– Take off your coat.
Now let’s assume our program handles our day when it comes to walking the dog:
if 8 AM then
– Put on a coat
– Put on the leash of the dog
– Go outside
– Walk through the park for 15 minutes
– Go back inside
– Take off the leash of the dog
– Take off your coat.
if 12 PM then
– Put on a coat
– Put on the leash of the dog
– Go outside
– Walk through the park for 15 minutes
– Go back inside
– Take off the leash of the dog
– Take off your coat.
if 5 PM then
– Put on a coat
– Put on the leash of the dog
– Go outside
– Walk through the park for 15 minutes
– Go back inside
– Take off the leash of the dog
– Take off your coat.
if 9 PM then
– Put on a coat
– Put on the leash of the dog
– Go outside
– Walk through the park for 15 minutes
– Go back inside
– Take off the leash of the dog
– Take off your coat.
Our program is pretty long, right? And a lot of repeating code as well …
We could create a function, let’s call it “WalkTheDog()”, and define it as follows.
WalkTheDog():
– Put on a coat
– Put on the leash of the dog
– Go outside
– Walk through the park for 15 minutes
– Go back inside
– Take off the leash of the dog
– Take off your coat.
Now our program would look much simpler:
if 8 AM then
WalkTheDog()
if 12 PM then
WalkTheDog()
if 5 PM then
WalkTheDog()
if 9 PM then
WalkTheDog()
You see, that not only our code has gotten much shorter, but it also has become much more readable – the “function” is called as if it was a regular statement. We in fact expanded our “language”.
In most scenario’s, using your own functions will also result in a smaller compiled program for your Arduino or computer, therefor being more efficient with memory needed on your Arduino (or computer).
But functions have also the advantage that if you made a mistake in your steps of walking the dog, that you only have to modify your code in one spot: the function – which makes your code more manageable. For example, if we forgot to add “Unlock the door” as a step. We just edit the function WalkTheDog() instead of having to edit the code in 4 different spots in the previous code.
Now if we have a function that is more of a generic use, we can even put them in what is called a library and re-use the function in our other programs. But more about “libraries” in a next part.
Please keep in mind that:
- A function is like a little program on it’s own … inside a program
- A function can have functions inside it …
- A function has a “scope” – like we have seen with variables and constants.
Ad Blocking Detected Please consider disabling your ad blocker for our website.
We rely on these ads to be able to run our website.
You can of course support us in other ways (see Support Us on the left).
Creating our own Function(s)
It’s pretty easy to define our own functions in the language C which we use for Arduino programming. The basic structure looks like this:
datatype FunctionName ( FunctionParameters ) {
// function code
}
I hope you remember some of the DataTypes we have mentioned in Part 3 – DataTypes. If not, don’t worry, you can look back if you’d like, but I will also mention some of the details here.
The datatype is defining what kind of data is being returned from the function and unfortunately, not all datatypes are all that suitable for use as a return value for functions. Definitely avoid arrays!
The most common datatypes for a return value are boolean, int, char, float and void (other types will work as well, like double, long and the “unsigned” types).
Obviously, our function needs a FunctionName, and we need to follow the same naming rules as with variables and constants:
Function name:
- Should start with a letter (a, b, …, z, A, B, … , Z) or underscore ( _ )
- Can contain letters
- Can contain underscore(s)
- Can contain numbers
- CAN NOT contain special characters, symbols or spaces
- is case sensitive!
The Function Parameters are zero or more values that we want to pass to the function. The number of values and the datatype of these values however is fixed and defined in our function definition!
In some C dialects you will need to “declare” (announce) or “define” a function before it’s being used in the code. The compiler needs to “know” it exists before it can use it. This appears not to be the case with C on the Arduino, which is why it will not be addressed here.
We have used function parameters before, even though you might not have been fully aware. It’s those values we pass between brackets, for example in this line: Serial.print("Hello");
Here we call the function “print()” from the object “Serial” and we pass the parameter “Hello” (a string). More about objects later.
The following code block, between accolades, is something we have seen before as well in for example the “if” function and the different loop kinds (“for”, “while” and “do … while …”).
This code block groups the instructions for our function.
Let’s start with a simple function:
1 2 3
| void SayHello() {
Serial.println("Hello");
} |
This function, called “SayHello()”, takes no parameters since there is nothing between the () brackets.
It also does not return a value, since we used the special datatype “void” – which means “nothing, thin air, nada”.
The “body” of the function (the code block), holds the instructions for this function, and it just outputs “Hello”.
An example of how we’d use this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void setup() {
// set the speed for the serial monitor:
Serial.begin(9600);
for(int A=1; A<=5; A++) {
SayHello();
}
}
void loop() {
// leave empty for now
}
void SayHello() {
Serial.println("Hello");
} |
Most of this should look familiar, I’d hope anyway …
At the end of the code you see how we defined our “SayHello()” function.
In the “for”-loop you see how we call our function 5 times, which results in an output like this:
Hello
Hello
Hello
Hello
Hello
Easy right?
Passing a Value to a Function
This was a rather simple example, let’s look at an example where we actually pass a parameter, where we use a previous example of turning on 5 lights with a “for”-loop.
For this we create a new function, called “DoLights”, to which we want to pass the light number of the light that needs to be switched on.
We already know that this number is a whole number of datatype “int” (see also the definition of “A” in the “for”-loop).
We also know that it will not return any values, which then get’s us this function:
void DoLights(int LightNumber) {
Serial.print("Switch lights on for light ");
Serial.println(LightNumber);
}
The parameter “LightNumber” is defined as an “int”. You can see that there is a the definition of the variable “LightNumber” inside the function called “DoLights”. When we pass a value for that parameter, the value will be copied into that “new” variable.
Keeping “scope” in mind, “LightNumber” obviously only exists in the function “DoLights”.
Calling our function (line 6) is just the same as the previous example, this time however we pass the value of the variable “A”. The value of “A” is being copied into the variable “LightNumber” – remember that it’s COPIED.
All this combined:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void setup() {
// set the speed for the serial monitor:
Serial.begin(9600);
for(int A=1; A<=5; A++) {
DoLights(A);
}
}
void loop() {
// leave empty for now
}
void DoLights(int LightNumber) {
Serial.print("Switch lights on for light ");
Serial.println(LightNumber);
} |
You see how the variable “LightNumber” is being used in the function?
But this was just an example on how to pass just one value. How does this work if we need to pass multiple values?
As an illustration, we will add a boolean value which we’d like to pass to our function. If this value is true then the lights should go ON, if it’s false the lights should go off.
To do this we need to separate the two values and for this we use a comma ( , ).
Parameters in a function are separated by a comma,
both when defining the function and when calling the function.
As with any value we’d like to pass, we again need to define it’s datatype (boolean) and name (LightOn).
I’ve added an “if” statement, so that the function can accommodate for switching the lights ON or OFF – another cool feature of functions; we can write them in such a way that they can work for more than one scenario.
All this combined:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| void setup() {
// set the speed for the serial monitor:
Serial.begin(9600);
for(int A=1; A<=5; A++) {
DoLights(A, true);
}
for(int A=1; A<=5; A++) {
DoLights(A, false);
}
}
void loop() {
// leave empty for now
}
void DoLights(int LightNumber, boolean LightOn) {
if(LightOn) {
Serial.print("Switch lights ON for light ");
}
else
{
Serial.print("Switch lights OFF for light ");
}
Serial.println(LightNumber);
} |
As you can see, we first run a “for”-loop, of 5 iterations, switching the 5 lights ON.
The values we pass are separated by a comma as well!
In the next “for”-loop, also 5 iterations, we switch the lights OFF.
Your output should look like this:
Switch lights ON for light 1
Switch lights ON for light 2
Switch lights ON for light 3
Switch lights ON for light 4
Switch lights ON for light 5
Switch lights OFF for light 1
Switch lights OFF for light 2
Switch lights OFF for light 3
Switch lights OFF for light 4
Switch lights OFF for light 5
Now obviously, the examples here are not really good ones when it comes to begin more efficient. But when you start creating your first, larger, programs, you will see how functions are an asset for a programmer.
Ad Blocking Detected Please consider disabling your ad blocker for our website.
We rely on these ads to be able to run our website.
You can of course support us in other ways (see Support Us on the left).
Returning a Value from a Function
So we know that a function can “receive” values by using parameters. Now what if we want the function to return an answer or result – for example from a complex calculation?
Remember we used “void” with our previous function definitions? That’s where we define what the returning result will be.
In the function itself however, we do need to actually “return” that type of value, and we use the function “return” for that.
If you define a function which will return a defined datatype, then you will need to use the “return” statement to return a value, which has to be of the same datatype as the defined return value datatype of your function …
An example could be made with one of the previous examples where we calculated “AllMyMoney” by adding what is in our wallet and what is in the bank. A pretty trivial situation, since we can calculate this already more efficient without creating a function, but it’s a good illustration. Obviously, once you start writing you own programs, these functions will contain much more and more complex code than this.
So we created a function “CalculateMyMoney”, which takes two parameters. I intentionally named them differently again, to illustrate that the values of the 2 variables (PocketMoney and Savings) are being COPIED to the variables names we defined in the function. It would have been fine to give the parameter variable names the same names, if you recall the “scope” of variables: the variables in the function are not the same variables as the ones outside of the function.
In the function we add these 2 values and return the result “Total”. This “return” value is then assigned to the variable “AllMyMoney”.
Go ahead and try this code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| void setup() {
// set the speed for the serial monitor:
Serial.begin(9600);
// define our variables
int PocketMoney;
int Savings;
int AllMyMoney;
// assign the values
PocketMoney = 4;
Savings = 12;
AllMyMoney = CalculateMyMoney(PocketMoney, Savings);
// print the values to the serial monitor
Serial.print("PocketMoney = ");
Serial.println(PocketMoney);
Serial.print("Savings = ");
Serial.println(Savings);
Serial.print("AllMyMoney = ");
Serial.println(AllMyMoney);
}
void loop() {
// leave empty for now
}
int CalculateMyMoney(int Wallet, int Bank) {
int Total;
Total = Wallet + Bank;
return Total;
} |
A function with a returning value, could be seen as a variable. So where ever we can use a value, or a variable, we could also use the function that returns a value, which I’ll illustrate in this slightly modified version. Look at line 21 … we’ve just placed the function call right there as a “parameter” for the “Serial.println()
” … and that works! So we do not need to first assign a returning value to a variable.
If you need the result of a function more often, then storing it in a variable makes perfect sense. After all: calling the function will exectute it’s code again, which would be redundant if we would need the same answer more than once.
A function with return value, can take the place of a regular value or variable …
Each time we call a function, it’s code will be executed. So if you need the result more than once, consider storing the value in a variable instead of calling the function repeatedly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| void setup() {
// set the speed for the serial monitor:
Serial.begin(9600);
// define our variables
int PocketMoney;
int Savings;
// assign the values
PocketMoney = 4;
Savings = 12;
// print the values to the serial monitor
Serial.print("PocketMoney = ");
Serial.println(PocketMoney);
Serial.print("Savings = ");
Serial.println(Savings);
Serial.print("AllMyMoney = ");
Serial.println( CalculateMyMoney(PocketMoney, Savings) ); }
void loop() {
// leave empty for now
}
int CalculateMyMoney(int Wallet, int Bank) {
int Total;
Total = Wallet + Bank;
return Total;
} |
At this point I strongly recommend playing with functions. Make up a function yourself, with or without return value, and do some experimenting.
Functions calling Themselves (Recursion)
This paragraph maybe be too complicated for beginners – feel free to skip it if you feel it’s too much for you.
A function can actually call itself, this is called “Recursion“.
You must be thinking that we ended up in crazy town – well, do not worry if recursion is a little bit too much for you. It is a little much for any beginner and even some experienced programmers.
So for this course we will leave it be for what it is: something you will not be using until you get more experienced with programming.
Recursion can be a very powerful tool, to write a limited amount of code yet produce stunning results. For example certain graphics can be generated with recursion like the tree below or the so called Sierpinski triangle. (image source: Wikipedia – Tree by Brentsmith101, Sierpinski by Wereon).
These a drawn by utilizing Recursion.
Recursive Tree
Sierpinski Triangle – Triangle in triangle
If you’re interested anyway … here a quick and simple example that is less complicated as the two images above.
Let’s say we want to add all whole numbers, for all numbers between 1 and 5. So we want to know how much 1+2+3+4+5 is (15).
Obviously we can do this very simple by either entering that manually, or by using a “for”-loop, but today we want to be difficult so we use this scenario as our recursion example.
We are going to create a function that starts at “5” and adds the number below that (4), then add the number below that (3), etc etc. until we added 1.
1 2 3 4 5 6
| int AddOneLess(int Number){
if(Number==0)
return Number;
else
return Number+AddOneLess(Number-1);
} |
So what this function does is, take the “Number” value. If this number is zero, then return zero. If the number is not zero, then take that number and call the “AddOneLess” function for the number minus 1.
Weird right?
In other words: this function will start with a given number, and keeps adding each time the previous number until it reached zero (0).
Let me display this differently by using this example code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void setup() {
// set the speed for the serial monitor:
Serial.begin(9600);
Serial.println(AddOneLess(5));
}
void loop() {
// leave empty for now
}
int AddOneLess(int Number){
if(Number==0)
return Number;
else
return Number+AddOneLess(Number-1);
} |
First we call AddOneLess(5).
The value of “Number” is not zero, so we do 5 + “AddOneLess(5-1)”, and there is NO return value yet since we now went into the AddOneLess(5-1) function call.
This second call, is where the value of “Number” is 4, and still not zero so we add 4 + “AddOneLess(4-1)” and we’re calling AddOneLess again, so no return value yet.
This results in the third call where the value of “Number” is 3 and still not zero so we add 3 + “AddOneLess(3-1)” – no return value yet.
This results in the fourth call where the value of “Number” is 2 and still not zero so we add 2 + “AddOneLess(2-1)” – no return value yet.
This results in the fifth call where the value of “Number” is 1 and still not zero so we add 1 + “AddOneLess(1-1)” – no return value yet.
The sixth call however the value of “Number” is 0 (zero), so we return “zero”.
However ,… we return zero in the “scope” of the fifth call, we went one step back, where the value of “Number” is 1, and where we say: return the value of “Number” and the return value of calling “AddOneLess(1-1)”.
So the fifth call returns 1 (value of “Number”) + 0 (return value of AddOneLess(1-1) ) = 1.
Now we return to the scope of the fourth call, where “Number” had the value 2, and which returns the value of “Number” + the return value of “AddOneLess(2-1)”, so: 2 + 1 = 3.
Returning to the scope of the third call, “Number” has a value of 3, and the return value = 3 + 3 (return from “AddOneLess(3-1)”) = 6.
When getting back to the second call, “Number” has a value of 4, so the return value = 4 + 6 = 10;
And coming back to the original call, “Number” is 5, and the return of the “AddOneLess(5-1)” has become 10. So this call returns 5 + 10 = 15.
Nice and confusing right?
Maybe it makes more sense to show it this way:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 1st call: AddOneLess(5) // in the setup() function
2nd call: AddOneLess(4) // in the AddOneLess(5) function call
3rd call: AddOneLess(3) // in the AddOneLess(4) function call
4th call: AddOneLess(2) // in the AddOneLess(3) function call
5th call: AddOneLess(1) // in the AddOneLess(2) function call
6th call: AddOneLess(0) // in the AddOneLess(1) function call, Number will now be zero!
5th call: Return = Number + result 6th call = 1 + 0 = 1
4th call: Return = Number + result 5th call = 2 + 1 = 3
3th call: Return = Number + result 4th call = 3 + 3 = 6
2nd call: Return = Number + result 3th call = 4 + 6 = 10
1st call: Return = Number + result 5th call = 5 + 10 = 15
Final return: = 15 |
I know this is complicated to grasp for the first time, so no worries if this is way over your head. I really had to think hard about even putting this explanation in here, but for all completeness I’ve added it anyway. Just remember that a function can call itself and that it will not interfere with previous calls. Each function call will get it’s own “scope”.
Just a rule of thumb to keep in mind when using recursion: Always make sure there is an “exit” condition in the function so the function does not keep going forever and crash your Arduino or computer … after all, for each call a scope is being stored in memory and your Arduino does have a limited amount of that.
When creating Recursive functions:
ALWAYS make sure the function has an “exit” condition to leave the function.
If you have questions, just ask them below in the comment section, and keep in mind: There are no stupid questions! We all had to start at some point!
Next chapter: Arduino Programming for Beginners – Part 7: Strings
Comments
There are 28 comments. You can read them below.
You can post your own comments by using the form below, or reply to existing comments by using the "Reply" button.
Hi Hans. I know in this chapter we learn to create our own Functions but i just want to ask whats the real difference between these two.
If i m right with the logic ;
Code 2 makes A to count start from 1 and execute serial.print and serial.println statements together like a “Flow-After” and then goes to top and do this for 2,3,4 and 5 too. Because its a (count) For Statement. This creates a Count!
in Code 1 we make again a For statement but for the result we want the sayHello() function to be run and we defined function sayHello() as a text value to be printed. This creates a Repeat!
So one is a Repeat and other is a Count but i cldnt understand the real difference and also i have another question; We define sayHello() function AFTER the statement of usage of it! Shldnt we First define it and Then call it? Why sayHello() function is UNDER the statement? (Even at the Last, after void loop)
Code 1 ;
void setup() {
Serial.begin(9600);
for(int A=1; A<=5; A++) {
SayHello();
}
}
void SayHello() {
Serial.println(“Hello”);
}
Code 2;
int A ;
for(A=1; A<=5; A++) {
Serial.print(“Switch lights on for light “);
Serial.println(A);
}
Stan
Hi Stan,
both code 1 and 2 are a loop, where we repeat something 5 times. You can call it repeat or loop – but in both cases you’re using a so called for-loop which counts and executes code between { and }. The only difference between these 2 examples is that in Code 1 you execute a function you made yourself, and in code 2 you execute the code straight.
The advantage of using a function is when you see it being used more than once,… or when the code get’s very large and hard to read.
The first one (code that is being used more than once elsewhere in your program) is the most common one. However, when the code between { and } in the for-loop becomes very extensive, it can be beneficial to split it in “tasks” (meaning: functions), just so it becomes more readable and easier to debug in the future.
As for the definition of the function being at the end; it is more correct to “declare” the function first, write the rest of the code and then actually write the code of the function. For example:
This would be the proper way – this way we tell the compiler up front that when it sees the function “SayHello” that this function does not have a return value (void) and does not take any parameters. The actual implementation follows later.
This forward declaration is seemingly not needed for the Arduino compiler.
Other languages (like Pascal) are much more strict and require a forward declarion. That’s why a language like Pascal is a better language to learn programming, since it forces you to work correctly. C (and derivates from C, like C++, C#, Java, etc.) allow quite often that the programmer can work a lot more sloppy – which causes sometimes unexpected results that can be hard to debug.
hans
Real sorry Hans. I didnt get what i this ;
void SayHello(); // declare function
We never use (;) right after double brackets (). Whats to declare? We declared at the bottom already! :(
Stan
Well, that’s why I left it out of the tutorial .
The declaration basically tells the compiler: if you run into this function, before you found the real function, then this is how it should work and be used. Since more and more modern compilers look through the entire code first, it would already have seen the function the way you defined it. So don’t worry too much about it just yet …
hans
Oh umm okay. So i can use my homemade function um for example in an if..then.. function but declare my function After if..then..function. and its ok.. true?
Stan
This my First Code that i wrote on my own!!! No copy no research just thought and built.. And thats a very big step(start) for me and i m so happy. Because Hans is my teacher who has a brillant way to explain things! So i wanted to dedicate my First code to Hans..( my fav number is 7 😆)
void setup () {
Serial.begin(9600);
for(int myFirstCode=1; myFirstCode<=7; myFirstCode++) {
Serial.print(“Hurray Hans for “);
Serial.println(myFirstCode);
}
}
Applause goes to Hans the Golden Man ! 👏👏👏🤗
Stan
Haha … very cool! (your first code)
Yes usually you can use your homemade function like that
hans
Hehe yes i know its not even a code for u Master. More like a Replacing maybe. Sure. But i opened new sketch and decided and did. Therefore i got the logic and the codes for example For-loop. Comeon. Thats a step for me ; not to memorise but to write whit Thinking ! 😊
Stan
Stan i think you’re doing great! I mean that!
Not many people keep trying like you do.
hans
The avr-g++ C++ compiler that arduino uses does need forward declaration.
To make it easier for beginners the IDE does auto generate forward declaration code and puts it into your C++ code before sending it to the avr-g++ C++ compiler.
Dr.Smart
Thanks for that insight Dr.Smart – I did not think about that. Good to know
Hans
I dont get how this works. We dont declare LightNumber in anywhere so we call it. And also in last line we write serialprintLn. How? We must not weite it into accolades? I dont get. Something dont suit the things i did learn in previous lessons
Stan
Hi Stan!
LightNumber is declared in the “void DoLights(int LightNumber, boolean LightOn) {” line.
Serial.println is the same as Serial.println however it adds a carriage return at the end (ie. the next time we send something to the Sreial, it will start on a new line).
Please let me know what is going wrong? This should work just fine.
And please let me know where you get confused … what is conflicting with what you’re learned in previous lessons so I can improve the lessons .
hans
U got me wrotng, master. I know printLn makes a new begining. I was trying to say why serial.println command is out of if.else statement.. its must be inside? No? Because we want to print the result so we need to say it inside same accolades as we did in previous lessons such as for loops.
And other thing i cldnt express clearly is ;
In this code
for(int A=1; A<=5; A++) {
DoLights(A, true);
}
We declare A integer and in ur cprebuilt function it just says LightNumber.. in library A==LightNumber? I didnt get how these two is being understand same in C
Stan
We declare A integer in loop and LightNumber integer prebuilt function it just says LightNumber.. in library A==LightNumber? I didnt get how these two is being understand same in C.we dont use LightNumber word in loop. How it takes data as LightNumber
Stan
The Serial.println is placed outside of the if…else… part because in the if…else… we decide if we want to print that the lights are ON or OFF. After that (which applies to both scenario’s) we want to print the light number.
This would do the same:
See how we have to repeat “Serial.println(LightNumber);”? By getting it outside of the if…then… , it will be applied automatically for any case.
As for the A versus LightNumber variable; in the for-loop in void setup(), the variable “A” is known and set, then the value of the variable “A” is passed to the function “DoLights”.
The function DoLights takes 2 parameters, which we call LightNumber and LightOn. No matter where the value is coming from, within the DoLights function, these variables hold the values passed to the function. It doesn’t matter if we type “4” for the LightNumber or use the variable A (which holds the value “4”).
Make sense?
hans
So why qe xant do this then? Why we use 2 different Names for the same value? This cld be better. No?
void DoLights(int A, boolean) {
Code bloxl etc.}
Stan
The use of 2 different names is actually very common.
The meaning or reference of the variable in for example void setup() might be different.
The function on the other hand uses the variables for this explicit purpose.
So in the setup() we just created a random variable name “A” for counting. This could also be “Counter”, “lightCounter” or whichever name you’d like to use, since we are in a loop and we are counting.
In the function it is very clear what the variable should represent: the LigthNumber.
The other thing is that if you’d use the same names (which would work as well), that this would actually contribute to more confusion, since they really are not the same variable. One might think that changing the value of LightNumber in the function might change it in setup() as well – which it doesn’t!
hans
Umm okay. Its about ENGLISH.. sorry. I better see it via Trying to create a function and see by myself.
Stan
Trying is always a good approach
hans
Dear Hans,
I have only just discovered your wonderful introductory Arduino website. Of the many introductions to Arduino I have looked at, yours is by far the clearest and best explained. Many thanks for taking the trouble to think through the various key ideas so systematically and to present them in such an accessible way.
I particularly appreciate your section on functions. It led me to consider different ways that functions can be used, especially the distinction between (i) functions that do not return a result (where the datatype is ‘void’) and (ii) functions that do return a result (where the data type is something other than ‘void’, e.g. ‘int’). I will now try to explain what seems to me to be important implications of this distinction for those writing Arduino sketches.
My understanding is that in both these cases, the function is called when needed (such as from the main loop of the sketch). However, only in the case of the return scenario does the calling part of the sketch become ‘aware’ of the consequences of the called function (that is, of the output of the called function). The subsequent part of the sketch (after the return from the function) can use the value returned in the processing carried out by its further lines of code.
In contrast, where the data type is ‘void’, the called function causes something to take place external to the sketch (such as a LED being turned on) so the rest of the sketch remains unaware of this. consequently its subsequent processing activity is unaffected by the function having been called.
So, a function that has a return (and the necessary parameters to allow it to return something after having been called) is the ‘servant’ of the main loop but non-return (I.e., ‘void’ ) functions do not directly serve the main loop. Rather, the void type of function typically serves purposes such as providing output to components attached to the Arduino.
Does this make sense or have I not understood things properly? I would very much appreciate your reactions and clarification on this.
Regards
RicRic
Ric
Hi Ric,
thank you for the very kind words and compliments! It’s very much appreciated!
Your view on functions does make sense, and it looks like you got the gist of it just fine.
The only things I’d like to add is this:
1) Functions can call other functions and technically loop() and setup() are function on their own.
To illustrate this, a function can call yet another function, or even itself (recursion).
2) “Awareness” of things that happen in a function would suggest that anything changed or done in a (void) function would not affect the “function” where the function was called from. But this is not always the case, for example with global variables.
To example 2) better, say we have a function
There is no return, and “a” is not defined. So this would cause an error, unless we define a global variable;
The function “AddTwo” will not return a value (void), but will change the global variable “a”.
So each time AddTwo is called, which would be a lot in this example, the global variable “a” will increase by 2 (until it hits the max capacity of the variable type “int”).
Hope this explains it a little more in depth
hans
Dear Hans,
Thanks very much for your speedy and most helpful reply.
The two additional aspects you explained nicely expand on the possible roles that functions can play in Arduino sketches.
It is interesting and useful to think about a hierarchical organization of processing in which a higher order function calls other ‘subservient’ functions. Now I must go back and have another look at your section on function recursion!
I can also see from your reply that ‘scope’ is a really important concept to be kept in mind.
Cheers
Ric
Ric
Hi Ric!
Indeed, well spotted: “scope” plays an important role as well.
Note: using global variables is something you’d want to do sparingly – the more global variables you have, the more confusing it can get when same or similar named variables are used in functions.
The good thing is that Arduino Sketches are typically rather simple. But if you later switch to different systems, code can become huge and confusion will kick in
hans
Do you walk your dog in the “part” or in the “park”?
I think you have a previously undiscovered typo.
C2carey
Hi C2carey!
Yeah, that is a pretty good blunder right there hahaha – Thanks for catching that!
I’ve update the text …
hans
Hi! I’d just like to ask if you have this tutorial in PDF form. This is so good that I’d love to keep it in my laptop or phone for offline use. Though don’t feel obligated to do so, I just would be interested. Thank you!
Blade
Hi Blade,
I totally understand the desire to have printed material, even if it’s just to lay next to you while working on something and/or make notes withe the text (a reason why I prefer text over a YouTube video).
I have implemented a specific make up for when the page is being printed. So just print the page to a PDF.
This is supported under macOS and Windows 10 natively – in the printer dialog you’ll have to select a PDF printer or select “Save as PDF” (depending on the Operating System and/or browser you’re using).
Note: The comments will be included as well. To exclude those, scroll through the preview and determine the page where comments start. Then in the printer dialog, set a custom number of pages. I just tried it with this page and it showed 34 (!) pages, but the comments (always forced to start on a new page) start at page 18 in my browser (this may be different on your system), So to create a PDF without the comments, I set the page range to “1-17”, which results in a clean PDF document.
Please let me know if you run into any issues.
I’ve only tested a few pages with this setup, so any feedback on the results is much appreciated.
Hans