13 min read

In this article by Syed Omar Faruk Towaha, the author of the book Learning C for Arduino, we will learn about functions and file handling with Arduino. We learned about loops and conditions. Let’s begin out journey into Functions with Arduino.

(For more resources related to this topic, see here.)

Functions

Do you know how to make instant coffee? Don’t worry; I know. You will need some water, instant coffee, sugar, and milk or creamer. Remember, we want to drink coffee, but we are doing something that makes coffee. This procedure can be defined as a function of coffee making. Let’s finish making coffee now. The steps can be written as follows:

  1. Boil some water.
  2. Put some coffee inside a mug.
  3. Add some sugar.
  4. Pour in boiled water.
  5. Add some milk.

    And finally, your coffee is ready! Let’s write a pseudo code for this function:

    function coffee (water, coffee, sugar, milk) {
      add coffee beans;
      add sugar;
      pour boiled water;
      add milk;
      return coffee;
    }
    

In our pseudo code we have four items (we would call them parameters) to make coffee. We did something with our ingredients, and finally, we got our coffee, right? Now, if anybody wants to get coffee, he/she will have to do the same function (in programming, we will call it calling a function) again. Let’s move into the types of functions.

Types of functions

A function returns something, or a value, which is called the return value. The return values can be of several types, some of which are listed here:

  • Integers
  • Float
  • Double
  • Character
  • Void
  • Boolean

Another term, argument, refers to something that is passed to the function and calculated or used inside the function. In our previous example, the ingredients passed to our coffee-making process can be called arguments (sugar, milk, and so on), and we finally got the coffee, which is the return value of the function.

By definition, there are two types of functions. They are, a system-defined function and a user-defined function. In our Arduino code, we have often seen the following structure:

void setup() {
}
void loop() {
}

setup() and loop() are also functions. The return type of these functions is void. Don’t worry, we will discuss the type of function soon. The setup() and loop() functions are system-defined functions. There are a number of system-defined functions. The user-defined functions cannot be named after them.

Before going deeper into function types, let’s learn the syntax of a function. Functions can be as follows:

void functionName()
{
    //statements
}
Or like
void functionName(arg1, arg2, arg3)
{
    //statements 
}

So, what’s the difference? Well, the first function has no arguments, but the second function does.

There are four types of function, depending on the return type and arguments. They are as follows:

  • A function with no arguments and no return value
  • A function with no arguments and a return value
  • A function with arguments and no return value
  • A function with arguments and a return value

Now, the question is, can the arguments be of any type? Yes, they can be of any type, depending on the function. They can be Boolean, integers, floats, or characters. They can be a mixture of data types too. We will look at some examples later. Now, let’s define and look at examples of the four types of function we just defined.

Function with no arguments and no return value, these functions do not accept arguments. The return type of these functions is void, which means the function returns nothing. Let me clear this up. As we learned earlier, a function must be named by something. The naming of a function will follow the rule for the variable naming. If we have a name for a function, we need to define its type also. It’s the basic rule for defining a function. So, if we are not sure of our function’s type (what type of job it will do), then it is safe to use the void keyword in front of our function, where void means no data type, as in the following function:

void myFunction(){
//statements
}

Inside the function, we may do all the things we need. Say we want to print I love Arduino! ten times if the function is called. So, our function must have a loop that continues for ten times and then stops. So, our function can be written as follows:

void myFunction() {
  int i;

  for (i = 0; i < 10; i++) {
    Serial.println(“I love Arduino!“);
  }
}

The preceding function does not have a return value. But if we call the function from our main function (from the setup() function; we may also call it from the loop() function, unless we do not want an infinite loop), the function will print I love Arduino! ten times. No matter how many times we call, it will print ten times for each call.

Let’s write the full code and look at the output. The full code is as follows:

void myFunction() {
  int i;

  for (i = 0; i < 10; i++) {
    Serial.println(“I love Arduino!“);
  }

}
void setup() {
  Serial.begin(9600);
  myFunction(); // We called our function
  Serial.println(“................“); //This will print some dots
  myFunction(); // We called our function again
}

void loop() {
  // put your main code here, to run repeatedly:

}

In the code, we placed our function (myFunction) after the loop() function. It is a good practice to declare the custom function before the setup() loop. Inside our setup() function, we called the function, then printed a few dots, and finally, we called our function again. You can guess what will happen. Yes, I love Arduino! will be printed ten times, then a few dots will be printed, and finally, I love Arduino! will be printed ten times. Let’s look at the output on the serial monitor:

Learning C for Arduino

Yes. Your assumption is correct!

Function with no arguments and a return value

In this type of function, no arguments are passed, but they return a value. You need to remember that the return value depends on the type of the function. If you declare a function as an integer function, the return value’s type will have to have be an integer also. If you declare a function as a character, the return type must be a character. This is true for all other data types as well.

Let’s look at an example. We will declare an integer function, where we will define a few integers. We will add them and store them to another integer, and finally, return the addition. The function may look as follows:

int addNum() {
  int a = 3, b = 5, c = 6, addition;
  addition = a + b + c;
  return addition;
}

The preceding function should return 14. Let’s store the function’s return value to another integer type of variable in the setup() function and print in on the serial monitor.

The full code will be as follows:

void setup() {
  Serial.begin(9600);
  int fromFunction = addNum(); // added values to an integer
  Serial.println(fromFunction); // printed the integer
}

void loop() {

}

int addNum() {
  int a = 3, b = 5, c = 6, addition; //declared some integers
  addition = a + b + c; // added them and stored into another integers
  return addition; // Returned the addition.
}

The output will look as follows:

Learning C for Arduino

Function with arguments and no return value

This type of function processes some arguments inside the function, but does not return anything directly. We can do the calculations inside the function, or print something, but there will be no return value.

Say we need find out the sum of two integers. We may define a number of variables to store them, and then print the sum. But with the help of a function, we can just pass two integers through a function; then, inside the function, all we need to do is sum them and store them in another variable. Then we will print the value. Every time we call the function and pass our values through it, we will get the sum of the integers we pass. Let’s define a function that will show the sum of the two integers passed through the function. We will call the function sumOfTwo(), and since there is no return value, we will define the function as void. The function should look as follows:

void sumOfTwo(int a, int b) {
  int sum = a + b;
  Serial.print(“The sum is “ );
  Serial.println(sum);
}

Whenever we call this function with proper arguments, the function will print the sum of the number we pass through the function. Let’s look at the output first; then we will discuss the code:

We pass the arguments to a function, separating them with commas. The sequence of the arguments must not be messed up while we call the function. Because the arguments of a function may be of different types, if we mess up while calling, the program may not compile and will not execute correctly:

Say a function looks as follows:

void myInitialAndAge(int age, char initial) {
  Serial.print(“My age is “);
  Serial.println(age);
  Serial.print(“And my initial is “);
  Serial.print(initial);
}

Now, we must call the function like so: myInitialAndAge(6,’T’); , where 6 is my age and T is my initial. We should not do it as follows: myInitialAndAge(‘T’, 6);.

Learning C for Arduino

We called the function and passed two values through it (12 and 24). We got the output as The sum is 36. Isn’t it amazing? Let’s go a little bit deeper. In our function, we declared our two arguments (a and b) as integers. Inside the whole function, the values (12 and 24) we passed through the function are as follows:

a = 12 and b =24;

If we called the function this sumOfTwo(24, 12), the values of the variables would be as follows:

a = 24 and b = 12;

I hope you can now understand the sequence of arguments of a function. How about an experiment? Call the sumOfTwo() function five times in the setup() function, with different values of a and b, and compare the outputs.

Function with arguments and a return value

This type of function will have both the arguments and the return value. Inside the function, there will be some processing or calculations using the arguments, and later, there would be an outcome, which we want as a return value. Since this type of function will return a value, the function must have a type. Let‘s look at an example.

We will write a function that will check if a number is prime or not. From your math class, you may remember that a prime number is a natural number greater than 1 that has no positive divisors other than 1 and itself.

The basic logic behind checking whether a number is prime or not is to check all the numbers starting from 2 to the number before the number itself by dividing the number. Not clear? Ok, let’s check if 9 is a prime number. No, it is not a prime number. Why? Because it can be divided by 3. And according to the definition, the prime number cannot be divisible by any number other than 1 and the number itself.

So, we will check if 9 is divisible by 2. No, it is not. Then we will divide by 3 and yes, it is divisible. So, 9 is not a prime number, according to our logic. Let’s check if 13 is a prime number. We will check if the number is divisible by 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, and 12. No, the number is not divisible by any of those numbers. We may also shorten our checking by only checking the number that is half of the number we are checking. Look at the following code:

int primeChecker(int n) // n is our number which will be checked
{
  int i; // Driver variable for the loop

  for (i = 2; i <= n / 2; i++) // Continued the loop till n/2
  {
    if (n % i == 0) // If no reminder
      return 1; // It is not prime
  }

  return 0; // else it is prime
}

The code is quite simple. If the remainder is equal to zero, our number is fully divisible by a number other than 1 and itself, so it is not a prime number. If there is any remainder, the number is a prime number. Let’s write the full code and look at the output for the following numbers:

23

65

235

4,543

4,241

The full source code to check if the numbers are prime or not is as follows:

void setup() {
  Serial.begin(9600);
  primeChecker(23); // We called our function passing our number to test. 
  primeChecker(65);
  primeChecker(235);
  primeChecker(4543);
  primeChecker(4241);
}

void loop() {
}

int primeChecker(int n)
{
  int i; //driver variable for the loop

  for (i = 2; i <= n / 2; ++i) //loop continued until the half of the numebr
  {
    if (n % i == 0)
      return Serial.println(“Not a prime number“); // returned the number status
  }

  return Serial.println(“A prime number“);
}

This is a very simple code. We just called our primeChecker() function and passed our numbers. Inside our primeChecker() function, we wrote the logic to check our number. Now let’s look at the output:

Learning C for Arduino

From the output, we can see that, other than 23 and 4,241, none of the numbers are prime.

Let’s look at an example, where we will write four functions: add(), sub(), mul(), and divi(). Into these functions, we will pass two numbers, and print the value on the serial monitor. The four functions can be defined as follows:

float sum(float a, float b) {
  float sum = a + b;
  return sum;
}

float sub(float a, float b) {
  float sub = a - b;
  return sub;
}
float mul(float a, float b) {
  float mul = a * b;
  return mul;
}
float divi(float a, float b) {
  float divi = a / b;
  return divi;
}

Now write the rest of the code, which will give the following outputs:

Learning C for Arduino

Usages of functions

You may wonder which type of function we should use. The answer is simple. The usages of the functions are dependent on the operations of the programs. But whatever the function is, I would suggest to do only a single task with a function. Do not do multiple tasks inside a function. This will usually speed up your processing time and the calculation time of the code.

You may also want to know why we even need to use functions. Well, there a number of uses of functions, as follows:

  • Functions help programmers write more organized code
  • Functions help to reduce errors by simplifying code
  • Functions make the whole code smaller
  • Functions create an opportunity to use the code multiple times

Exercise

To extend your knowledge of functions, you may want to do the following exercise:

  • Write a program to check if a number is even or odd. (Hint: you may remember the % operator).
  • Write a function that will find the largest number among four numbers. The numbers will be passed as arguments through the function. (Hint: use if-else conditions).
  • Suppose you work in a garment factory. They need to know the area of a cloth. The area can be in float. They will provide you the length and height of the cloth. Now write a program using functions to find out the area of the cloth. (Use basic calculation in the user-defined function).

Summary

This article gave us a hint about the functions that Arduino perform. With this information we can create even more programs that is supportive in nature with Arduino.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here