Page 1 of 1

Arduino Programming for Beginners – Part 4: Decisions

Arduino Programming for Beginners – Part 4: Decisions
   1

In this article we will talk about making decisions (if … then … or switch … case …). Decisions are very important in our program to react to changing data or events, or to go through a list (loop) of data or events. We call that Control Flow – meaning code is being executed in a different order based on conditions.

This is the fourth part of a series of articles I’ve written to get beginners started with Arduino Programming in the programming language C, which I’ve written with the intend to teach my 13 year old nephew (Bram) to get started with the Arduino. After all, he wants to build a robot, but without some basic knowledge about programming, he won’t get far ….

Besides an introduction into the language C, the default language used for Arduino Programming, “Arduino Programming for Beginners” will also touch topics like how to setup an Arduino, get a developers environment running, and look at a few basic electronic parts which we connect to our Arduino.




Overview of this Chapter

  A complete overview of this course can be found here: Course Overview.

Making Decisions in your Code

In the previous chapter we have briefly looked at Comparison Operators, which allow us to compare two pieces of data. After that we also looked at Boolean Operators, so we can see if certain conditions are met. Both of these are of great use in this section: Making Decisions in your code.

Making decisions in our code is useful when we want to execute particular code, only when a certain situation occurs. This is what is called “control flow” or in other words: controlling how we go through the program and execute pieces that we need.

Let’s say we want to write a program that switches the lights on when it’s dark outside, and off when it’s not light outside.
In our code we would first check if it’s actually dark. If it is dark then we need to run the code to switch the lights on. If it is not dark then we need to switch the lights off. Did you notice the “if … then …” in this text?

The “if…then…” is a very common construct, which you will find in most other programming languages as well.

If … then …

The most common way to make a decision in your code is probably the so called “if … then …”, which is what they call “Conditional Statements“. Code that only will be executed if certain condition(s) have been met.

Let’s look at 2 examples before we go into detail.

Say we have lights that go on automatically when it’s dark. The conditional statement would be something like this:

if DarkOutside then SwitchLightsOn

Or if we want to detect that we’re running out of cash:

if MoneyInWallet=0 then GoToTheATM

I’m sure you get the idea when and “if … then …” can be useful in our program. Your program is to respond to something that might or might not change, or you’d like your program to be suitable for more than one scenario. That “something” can be the value of a variable, or for example a sensor detecting changing, or a switch being set.

The proper syntax (way of writing) would be:


1
2
3
4
5
6
if ( condition ) {
  // do what is needed if condition is met
}
else {
  // do this is the condition is not met
}

As you can see, we set the condition between brackets, and let it follow by a code block (between accolades) which needs to be executed when the set condition has been met.

The “else” statement in an “if … then …” is always placed at the end, as the last “condition”. It basically says “if all fails then do this” …

The optional (lines 4, 5 and 6) “else” allows us to define what to do when a condition has not been met. Here again, the “else” is followed by a similar code block. These lines are optional, so if you want your program to only act when a condition is met, then lines 4, 5, and 6 can be omitted, so we get something like this:


1
2
3
if ( condition ) {
  // do what is needed if condition is met
}

The “condition” is typically using a comparison operator which would result in either true or false, look back in the previous chapter if you forgot, but I’ll summarize the comparison operators here one more time;

Comparison Operatos
 Symbol  Purpose
==  is Equal to
!=  is not Equal to
<  less than
>  greater than
<=  less than or equal to
>=  greater than or equal to

The most common mistake in Comparison Operators is:
using “=” where you should be using “==” to see if two values are equal.

Just a tip that will be handy in the future: The condition has to result in either a true or a false. This means that instead of a condition we could also just enter a boolean here. The following example will always execute the “if” code block:


1
2
3
if ( true ) {
  // do what is needed if condition is met
}

The example we will go through now, will use the money example we used before.

We will look at what we have in our pocket, and what we have in our savings. If all our money goes below “$5” then we want to see an alert that we need to get our hands on more cash. Let’s look at our code for that – remember our previous example in the previous chapter when we were talking about variables.


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
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 = 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);

  if(AllMyMoney<5) {
    Serial.println("Oh oh,... we are low on cash!!");
  }
  else {
    Serial.println("It's all good ... no worries.");
  }
}

void loop() {
  // leave empty for now
}

The fun starts at line 25 where we check to see of the value of the variable “AllMyMoney” is less than (<) 5. If the condition is met, a message will be displayed “Oh oh,… we are low on cash!!“. If the condition has NOT been met, the message will be “It’s all good … no worries.“.

Copy and paste the code in the Arduino IDE and compile and upload it to the Arduino. Because the condition in line 25 is not being met, your Arduino will ignore the “if” code block and execute the “else” code block and the response will be:

PocketMoney = 4
Savings = 12
AllMyMoney = 16
It's all good ... no worries.

No change the code in line 12, and set our savings to zero and compile and upload again to your Arduino: Savings = 0;

The condition in line 25 is now being met, which means that the “if” code block will be executed and the “else” code block will be ignored. Our output will look like this:

PocketMoney = 4
Savings = 0
AllMyMoney = 4
Oh oh,... we are low on cash!!

If you’d like to omit the “else” part, and only want to see a warning when our funds are low, your code would look like this:


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
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 = 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);

  if(AllMyMoney<5) {
    Serial.println("Oh oh,... we are low on cash!!");
  }
}

void loop() {
  // leave empty for now
}

The “if … then …” statement however can be expanded with as many “if … then …”‘s as you’d like.

Think of the following example:

if AllMyMoney=0 then panic else if AllMyMoney<5 then get more money else stay cool.

When stacking “if .. then … else if … then … else if … then” like this, your Arduino will go through the conditions one at a time. Once it found a matching condition, it will execute the code block that goes with that condition and EXIT the entire “if … then …” stack.

“if … then …” statements can be built with multiple “if … then …” constructs.
Once one of the conditions has been met, the entire construct will be seen as “done and dealt with” … following “if …then …” (in the same construct) will be ignored.

An example:


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
37
38
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 = 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);

  if(AllMyMoney==0) {
    Serial.println("PANIC!!");
  } else if(AllMyMoney<5) {
    Serial.println("Oh oh,... we are low on cash!!");
  } else if(AllMyMoney>10) {
    Serial.println("Woohoo - we are rich!!");
  } else {
    Serial.println("It's all good ... no worries.");
  }
}

void loop() {
  // leave empty for now
}

This code will:
– print “PANIC!!” if AllMyMoney = 0, or
– print “Oh oh,… we are low on cash!!” when AllMyMoney is less than 5, or
– “Woohoo – we are rich!!” when AllMoney is greater than 10, or
– in all other situations print “It’s all good … no worries.”.

Going through Multiple “if … then … else if …”

A few things to notice in this code – and you have to pay attention to this to understand why certain things work the way they work!

Anif … then ..” construct will be exited once a condition has been met.

All following conditions will be IGNORED !!!!

In the example, AllMyMoney = 16, so the first 2 conditions FAIL.
The 3rd condition however SUCCEEDS, so the “Whoohoo – we are rich!!” message will be displayed.
Since a working condition was found, the last “else” will be ignored.
Makes sense right?

OK, now let’s change lines 11 and 12 to:


11
12
  PocketMoney = 0;
  Savings = 0;

So AllMyMoney ends up to be zero (0).

When going through the “if … then …” statements, we will notice something interesting – which causes a lot of bugs in programs.

So AllMyMoney = 0.
This means that the first condition SUCCEEDS, and the message “PANIC!!” will be displayed.
However, condition 2 (AllMyMoney less than 5) is true as well, but … it will not be executed.

Once a condition has been met, the “if … then …” will be considered “done and dealt with” and will be exited. Meaning that the other conditions will not even be checked, and this is done intentionally.

If you would not know this, or forgot about it, then you’d see an unexpected result if you would have expected the message “Oh oh,… we are low on cash!!” as well. So it’s important to go through these constructs in your mind and consider what will happen with overlapping conditions.

With overlapping I mean: two or more conditions can be met, only the first one that is being met, will actually be executed.

So what would we need to do, to get both conditions to trigger a message?
Well, basically we need to take apart the complex “if … then …” construct and make them individual constructs, which typically comes with a complication when you’ve used an “else” at the end.

I’ve written a small example, which takes our complex “if … then …” construct apart, like so:


25
26
27
28
29
30
31
32
33
34
35
  if(AllMyMoney==0) {
    Serial.println("PANIC!!");
  }

  if(AllMyMoney<5) {
    Serial.println("Oh oh,... we are low on cash!!");
  }

  if(AllMyMoney>10) {
    Serial.println("Woohoo - we are rich!!");
  }

We basically made individual “if … then …” constructs. You see: there is no “else” mentioned anywhere.
However, the lack of “else” comes with a little problem.

In our original program we said:

If AllMyMoney == 0 then “Panic”else if AllMyMoney < 5 then “Oh Oh”else if AllMyMoney > 10 then “Woohoo”else “no worries”.

But in the broken up “if … then …” construct, we have covered everything but the else statement:

If AllMyMoney == 0 then “Panic”.
If AllMyMoney < 5 then “Oh Oh”.
If AllMyMoney > 10 then “Woohoo”.

We cannot add “else” to any of these 3, since it would trigger even when it’s not needed. Look at what would happen if we added “else” with all of these 3 conditions:

If AllMyMoney == 0 then “Panic” else “No worries”.
If AllMyMoney < 5 then “Oh Oh” else “No worries”.
If AllMyMoney > 10 then “Woohoo”else “No worries”.

If AllMyMoney would be 8, then we would see “No worries” 3 times, since all 3 conditions would fail.
If AllMyMoney would be 0, then we would see “Panic” and twice “No worries” – which would not be correct.
If AllMyMoney would be 4, then we would see “No worries” twice and one “Oh Oh” – that would not be correct either, right?

So when would that “else” situation need to trigger?

More Complex “if … then …” Conditions

If we look at our conditions then we see a “range” for each condition, and some of these “ranges” overlap.
So 0 and values less than 5 are covered in the first 2 conditions – these two overlap! (0 is smaller than 5!)
Values greater than 10 are also covered, in the 3rd condition.

So where is the gap?

Values equal or greater than (>=) 5 AND less than or equal to (<=) 10 are not covered.

Step by step, assuming integer numbers:

Condition 1 covers “0” (zero).
Condition 2 covers “0, 1, 2, 3, 4” (less than 5 – which excludes 5!).
Condition 3 covers “11, 12, 13, … infinity” (greater than 10 – which excludes 10!).

See the gap now? The gap is “5 ,6 ,7 ,8 ,9 ,10”.

So these are numbers equal or greater than (>=) 5 AND less than or equal to (<=) 10.

This is where boolean operators from the previous chapter come in:

Boolean Operator
 Symbol  Purpose
 &&  AND
 ||  OR
 !  NOT

So the gap is for every number that is greater than or equal to 5, which in code looks like this: AllMyMoney >= 5 .

But these numbers are also limited since they cannot exceed “10”, so the condition would be: AllMyMoney <= 10 .

But BOTH of these need to be true for these numbers in our gap. Se we need to make sure that BOTH conditions are met.

One option could be using and “if…then…” within an “if…then…”, like so:


if(AllMijMoney>=5) {
  if(AllMijMoney<=10) {
    // do this
  }
}

But this can become very messy very quickly …

Now let’s look at the Boolean Operator table and listen to this: the gap consist of the values that are >=5 and <=10. Right?

The keyword here is “and“, so let’s look at the “and” table from the previous chapter:

And Results
 Condition1  Condition2  Result of Conditon1 AND Condition2
 true  true  = true
 true  false  = false
 false  true  = false
 false  false  = false

I rewrote that a little, instead of “value” typed “condition”.

So both conditions need to be true for this gap to occur. In code: AllMyMoney >= 5 && AllMyMoney <= 10.

Writing it like that however causes a problem when you are trying to read it. When and where are we applying the AND operator, and when are we comparing? Also note that when you start working with on another system, or when you start working in a different language, that this actually might cause error messages when compiling, or give unexpected results when you run the program.

Therefor we put the conditions between brackets. The code between brackets will be executed first and the result will replace what is between brackets. After that the “and” is applied.

Code between round brackets, in a statement, will be executed first.

So we write it like this: (AllMyMoney >= 5) && (AllMyMoney <= 10)

Which at run time will determine the outcome of “AllMyMoney >= 5” and “AllMyMoney <= 10” and replace that with the result of that. So as an example ew say that AllMyMoney = 6, then the following steps will be done:

Step 1: (AllMyMoney >= 5) && (AllMyMoney <= 10) and “AllMyMoney=6”
Step 2: (true) && (AllMyMoney <= 10)
Step 3: (true) && (true)

which results in true && true which (according to our table above) is “true“.

So our modified code would be:


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
37
38
39
40
41
42
43
44
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 = 0;
  Savings = 4;
  AllMyMoney = 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);

  if(AllMyMoney==0) {
    Serial.println("PANIC!!");
  }

  if(AllMyMoney<5) {
    Serial.println("Oh oh,... we are low on cash!!");
  }

  if(AllMyMoney>10) {
    Serial.println("Woohoo - we are rich!!");
  }

  if( (AllMyMoney>=5) && (AllMyMoney<=10) ){
    Serial.println("It's all good ... no worries.");
  }
}

void loop() {
  // leave empty for now
}

I highly recommend playing with the values in lines 11 and 12, and later in the conditions as of line 25.

The use of brackets

Just touching brackets one more time, since they are very important in the order in which complex statements (calculations and comparisons) – so called nested brackets.

When conditions become very complicated, we might end up using a lot of brackets, even brackets enclosing other brackets. This is done to make sure that a condition or calculation is evaluated in the correct order. We will not need those kind of constructs just yet, but it’s good to know, like with math, that we first do the most inner brackets.

Let take an example: (  (  (c1) && (c2) ) || ( (c3) && (c4) ) )
Each c-number represents as condition.

The Arduino will first determine the outcome of the most inner brackets (1 in the drawing), the red ones, which are condition c1, then c2, then c3 and then c4 and replace them with the outcomes, which would make it: ( ( o1 && o2 ) || ( o3 && o4 ) )
(where the o-number stands for the outcome)

It will then go to one bracket level further out, the green ones (2 in the drawing), which will result in: ( o12 || o34 ).
(where o12 is the result of o1 && o2, and o34 the result of o3 && o4).

Then finally it will do the most outer brackets (3 in the drawing), the blue ones, which results in: o1234
(where o1234 is the finally result of o12 || o34).

All this visualized in a drawing, would look something like this:

 

Using Brackets - Processed from inside out

Using Brackets – Processed from inside out

If this was a little over your head, no worries …. let’s look at a calculation example.

Note: Please keep in mind that this example will be handled by Arduino correctly, even without brackets. We use this example solely to illustrate how brackets work.

A = 3 * 4 + 12 / 4 + 6 * 3

If we wouldn’t think anything of it, and would maintain no priority over these calculations then the answer could be:

A = 12 + 12 / 4 + 6 * 3
A = 24 / 4 + 6 * 3
A = 6 + 6 * 3
A = 12 * 3
A = 36

Or should we have done it this way:

A = 12 + 12 / 4 + 6 * 3
A = 12 + 12 / 10 * 3
A = 12 + 12 / 30
A = 24 / 30
A = 0.8

As you can guess: none of the are the right answer. With normal calculations we have rules that tell us un what order we need to execute each step, visualized with brackets this would be.

Keep in mind: with calculations, multiplication and division, go before addition and subtraction!

A = ( (3 * 4) + (12 / 4) + (6 * 3) )

If we now follow the same method; starting with the deepest nested brackets, then we would get this:

A = ( (12) + (12 / 4) + (6 * 3) )
A = ( (12) + (3) + (6 * 3) )
A = ( (12) + (3) + (18) )
A = ( 15 + 18 )
A = 33

And this is the correct answer. You see how the answer depends on the order in which we work?
And that’s where the brackets come in – with brackets we can force a order to work the way we want it, and it can improve readability.

Code between brackets, will be evaluated first.
Starting from the inner most brackets, working our way outwards,
until no brackets are left.

Switch … case …

The “switch … case …” construct is a little bit bit more complex, but very practical in situations where we need a lot of “if” statements.

Like if statements, the “switch … case …” statement, does control the flow of programs, which allows you to specify specific code to be executed based on conditions that are being met or not. This statement works a little bit different than an “if” statement.

The “if” statement allows us to define our conditions with any of the comparison operators, and use boolean values.
The “switch” statement however, only works with “equal to”.

Let’s look at an “if” example, which can be replaced with a switch statement.


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
37
38
39
40
41
42
43
44
45
void setup() {
  // set the speed for the serial monitor:
  Serial.begin(9600);
 
  // define our variable
  int A = 5;
 
  if(A==1) {
    Serial.println("A = 1");
  }
  else if(A==2) {
    Serial.println("A = 2");
  }
  else if(A==3) {
    Serial.println("A = 3");
  }
  else if(A==4) {
    Serial.println("A = 4");
  }
  else if(A==5) {
    Serial.println("A = 5");
  }
  else if(A==6) {
    Serial.println("A = 6");
  }
  else if(A==7) {
    Serial.println("A = 7");
  }
  else if(A==8) {
    Serial.println("A = 8");
  }
  else if(A==9) {
    Serial.println("A = 9");
  }
  else if(A==10) {
    Serial.println("A = 10");
  }
  else {
    Serial.println("A less than 1 or greater than 10");
  }  
}

void loop() {
  // leave empty for now
}

This code would result in: A = 5

That’s a lot of “if” statements, right?
And yes, this can be written much more efficient. But we’re only using it to illustrate how “switch” works.

The usual way of using the “switch” statement looks like this:


switch (variable) {
    case value1:
      //do something when variable equals value1
      break;
    case value2:
      //do something when variabel equals value2
      break;

    ... // etc.

    default:
      // if nothing matches, do this ... (optional)
    break;
  }

So the “switch” statement, takes the current value of “variable” and compares that value with the value mentioned in each of the “case” statements, to see if the following code needs to be executed. The optional “default:” statement (you are not required to use it) will be executed when none of the “case” values have been met.

Now let’s look at the same code, now using the “switch” statement:


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
void setup() {
  // set the speed for the serial monitor:
  Serial.begin(9600);
 
  // define our variable
  int A = 5;

  switch(A) {
    case 1: Serial.println("A = 1");
    case 2: Serial.println("A = 2");
    case 3: Serial.println("A = 3");
    case 4: Serial.println("A = 4");
    case 5: Serial.println("A = 5");
    case 6: Serial.println("A = 6");
    case 7: Serial.println("A = 7");
    case 8: Serial.println("A = 8");
    case 9: Serial.println("A = 9");
    case 10: Serial.println("A = 10");
    default: Serial.println("A less than 1 or greater than 10");
  }  
}

void loop() {
  // leave empty for now
}

I intentionally made a mistake in this code, so do not take this as the way to do it!

The output is an unexpected:

A = 5
A = 6
A = 7
A = 8
A = 9
A = 10
A less than 1 or greater than 10

The reason for this is that the “switch” statement will look for a “case” that is true and execute all the code after that.
So when A=5, all statements as of “case 5:” will be executed.

This can be practical in some cases, but in most cases we’d like it to stop once it completed the code for “case 5:”. This is done with the “break” statement after the last statement of each of the cases.

Do not forget the “break” statement with each “case” if you want to limit code execution to only one of the “case” statements.

Our modified code will look like this:


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
void setup() {
  // set the speed for the serial monitor:
  Serial.begin(9600);
 
  // define our variable
  int A = 5;

  switch(A) {
    case 1: Serial.println("A = 1");
            break;
    case 2: Serial.println("A = 2");
            break;
    case 3: Serial.println("A = 3");
            break;
    case 4: Serial.println("A = 4");
            break;
    case 5: Serial.println("A = 5");
            break;
    case 6: Serial.println("A = 6");
            break;
    case 7: Serial.println("A = 7");
            break;
    case 8: Serial.println("A = 8");
            break;
    case 9: Serial.println("A = 9");
            break;
    case 10: Serial.println("A = 10");
            break;
    default: Serial.println("A less than 1 or greater than 10");
  }  
}

void loop() {
  // leave empty for now
}

To see how “default” works, you could change line 6 to A = 11;  (for example) which will make it that all “case” statements fail, and “switch” will execute the “default” statement. If one would have left out the “default” statement, and none of the cases were found, then simply nothing happens.

Using “default” with the “switch” statement is optional

The “switch” statement is not used often, at least not as often as the “if” statement.
Also keep in mind that the case values are best placed in logical order – it makes the code more readable and you will not be facing potentially unexpected results.

Keep case values in a logical order, if possible,
for improved readability and prevention of unexpected results

 

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 5: Going in Loops

Donation options


Donations are very much appreciated, but not required. Donations will be used for web-hosting expenses, project hardware or a motivational boost (a drink or snack). Thank you very much for those have donated already! It's truly AwEsOmE to see that folks like our articles and small applications.

Comments


There is only one comment, you can read it below.
You can post your own comments by using the form below, or reply to existing comments by using the "Reply" button.



Your Comment …

Friendly request to not post large files here (like source codes, log files or config files). Please use the Forum for that purpose.

Please share:
*
*
Notify me about new comments (email).
       You can also use your RSS reader to track comments.


Tweaking4All uses the free Gravatar service for Avatar display.
Tweaking4All will never share your email address with others.