Arduino functions: write it once, call it anywhere
Or see every lesson.
- 455parts on the bench
- 43boards running now
- 1.00xreal time, on every board
A function is a named block of code you can run from anywhere in your sketch by writing its name. void flash(int pin, int times) is a function that flashes any pin any number of times, so instead of copying the same four lines for every LED, you write flash(13, 1), flash(12, 2) and flash(11, 3). setup() and loop() are functions too; you have been writing them all along.
The circuit above has three lamps on pins 13, 12 and 11, driven by exactly that function. Press Run. The serial monitor prints "three lamps, one flash function", then "pin 13 flashes 1 times", "pin 12 flashes 2 times" and "pin 11 flashes 3 times", and each lamp does what its line says.
Below is the shape of a function, functions that hand back an answer, why changing a parameter does nothing to the caller, where functions can and cannot go, and the error messages for each mistake.
Want the step-by-step version? The lesson "Write it once" walks through this with checkpoints.
Open the lessonThe shape of a function
A function has a return type, a name, and its parameters in brackets, then its body in braces. In void flash(int pin, int times, int onMs), void says it hands nothing back, flash is the name, and the three ints are the numbers the caller must give it. Inside, pin, times and onMs are ordinary variables holding whatever the caller passed.
The two small functions after it answer a question instead of doing a job. lampFor(round) returns the pin for a round and timesFor(round) returns how many flashes, and loop() uses their answers. Change return round + 1; to return round + 2; and every lamp flashes once more.
void flash(int pin, int times, int onMs) {
for (int i = 0; i < times; i++) {
digitalWrite(pin, HIGH);
delay(onMs);
digitalWrite(pin, LOW);
delay(onMs);
}
}
int lampFor(int round) {
if (round == 0) return LAMP_A;
if (round == 1) return LAMP_B;
return LAMP_C;
}
int timesFor(int round) {
return round + 1;
}Return a value
Any type other than void means the function hands back a value of that type, and return is how. The caller can print it, store it or use it in a sum. Below, twice(21) printed 42.
Notice that twice() is written after setup(), which calls it. In plain C++ that is an error, because the compiler reads from the top and has not seen twice yet. The Arduino IDE quietly adds a declaration for every function in a .ino file at the top before compiling, and Mokxi does the same, so in your sketch the order does not matter.
void setup() {
Serial.begin(9600);
Serial.println(twice(21));
}
void loop() {
}
int twice(int x) {
return x * 2;
}Parameters are copies
A parameter is a copy of what the caller passed. addOne(score) below adds one to its own copy and throws it away, so score still printed 5 afterwards. Most of the time that is exactly what you want: a function cannot quietly change your variables.
When you do want it to, put & after the type. void addOneRef(int &n) takes a reference, which is the caller’s own variable under another name, and after addOneRef(score) it printed 6. A reference is also the usual way to get two answers out of one function: minMax(7, 3, lo, hi) filled in both and printed "3 7".
void addOne(int n) {
n = n + 1;
}
void addOneRef(int &n) {
n = n + 1;
}
void setup() {
Serial.begin(9600);
int score = 5;
addOne(score);
Serial.println(score);
addOneRef(score);
Serial.println(score);
}
void loop() {
}Where functions go, and the errors when they do not
A function goes outside every other function, at the top level of the file, usually after loop() or above setup(). Keep each one short and give it a name that says what it does, such as readTemperature() or flashError(), and loop() starts to read like a list of steps. Write one inside setup() and the build stops. Mokxi compiles with clang, whose words are function definition is not allowed here; the Arduino IDE’s GCC says a function-definition is not allowed here before '{' token. It nearly always means a closing brace is missing above, so the compiler thinks you are still inside setup(). Count your braces.
A function that promises a value must return one on every path. int f(int x) { if (x > 0) return 1; } builds, with a warning: non-void function does not return a value in all control paths. Call f(-5) and you get whatever happened to be left behind, which here printed 1. Add a return at the end, even if it is return 0;.
Functions in a separate .cpp tab do not get the automatic declarations a .ino file does. We moved a function into a tab called more.cpp and the sketch stopped with use of undeclared identifier 'helper'. Put a declaration, void helper();, in a header such as more.h and #include "more.h" at the top of the sketch, and it builds.
Questions
What does void mean in Arduino?
That a function hands nothing back. void setup() and void loop() do a job and return no value. A function that answers a question has a type instead, such as int or float, and ends with return.
Do I have to declare a function before I use it in Arduino?
Not in a .ino file: the Arduino IDE adds the declarations for you before compiling, and so does Mokxi, so a function can be written below the code that calls it. In a .cpp file you do, usually in a header.
How do I return two values from a function?
Pass two variables by reference, with & after the type, and set them inside the function. Or return a struct holding both. The minMax() example on this page fills in a low and a high this way.
Why does changing a parameter not change my variable?
Because a parameter is a copy. Changing it changes the copy only. Declare the parameter as a reference, int &n instead of int n, if the function is meant to change the caller’s variable.
What does "a function-definition is not allowed here" mean?
That a function is being defined inside another one, almost always because a closing brace is missing above it. Find the function before the error and check every { has its }.
Can an Arduino function return an array?
Not as an array. A function can return a pointer, but returning the address of a local array is a bug: the build goes through with the warning address of stack memory associated with local variable 'a' returned, because the array is gone once the function ends. Pass the array in as a parameter and fill it, or return a struct that holds the values.
Keep going
Where the facts on this page come from
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.