6 – Conditional statements and buttons

Objectives

• Digital Logic and Boolean Algebra.
• Conditional statements. The if-else statement block.
• Buttons, push-button switches and pull up resistors.
• Debouncing.

Bill of materials

 Arduino Uno or equivalent. We can use any other Arduino board in this chapter. We will also need a PC computer with the Arduino IDE properly installed and set up. A solderless Breadboard. A LED diode. A push-button switch. Two 330 Ohm resistors . Some jumper wires

DIGITAL LOGIC AND BOOLEAN ALGEBRA

In the previous chapter we introduced the boolean data type, emphasizing that it can only hold two kind of values: true or false. To those not accustomed to boolean algebra, it might seem excessive to dedicate a data type to something so simple, although, in practice, much of the programming instructions are based or depend on this data type.

The practical reason for this is that we often have to make decisions to choose one path or another depending on whether a given condition is met. This condition must be evaluated to logic true or logic false, that is, to a boolean data type.

For example, in chapter 4 we used the for statement and we stated that the iteration through the loop continues while some condition is met. This condition must be evaluated to logic true or false, that is, to a boolean data type.

There are a lot of instructions based on boolean data types (as conditional instructions, that we will later see in this chapter), but in a very explicit way all current computing is based on digital logic of only two values. We usually call them 0 and 1 but we can rightfully call them true and false instead.

Modern computers work applying the boolean algebra to boolean variables by using a complete set of logical operators, as the logical NOT( that we saw in the previous chapter), as well as logical operator as AND, OR, + and .

THE IF STATEMENT BLOCK

In this chapter we are going to introduce some new C++ instructions that will allow us to take decisions in order to choose between two alternatives: the if and if-else statement blocks.

The if statement block is very easy to use, we only have to pass it between braces a variable or condition that can evaluated to either logic true or false. If the relational test is logic true, then the block following the if test is executed.

Otherwise, the else statement block is executed, if any.
if there isn’t any else statement, then the block that follows the if statement is executed or not, depending on the condition. After that, the program resumes the sequence of instructions beyond the if statement block.

```
if (condition)
{
statement 1 ;
statement 2 ;
................
}
else
{
statement 20 ;
statement 21 ;
..............
}
```

Remember that in the circuit of the previous chapter we also had a push-button switch and a LED diode. In this chapter we will go on working with the same circuit. We could keep the same setup() function and write the loop() function in a different way to make the LED diode turn on and off when pressing the push-button switch.

```     void loop()
{
if (value)
digitalWrite( LED, HIGH) ;
else
digitalWrite( LED, LOW) ;
}```

The first line reads the push-button switch status and assign its value to a boolean variable. After that, we choose whether to turn on or off the LED diode depending on if this value is a logic true or false.

• Remember that a block is just a sequence of statements written between braces. There is only a particular case in which we can omit the braces: if, and only if, the block consists of only one instruction, as in our case.
• We can use an if-else statement block without the else statement, if needed, since it is optional.

COMING BACK TO BUTTONS

Let’s try a different program. We want now the push-button switch to act as a switch, that is, we want the LED diode to turn on when it is pressed once and to turn off the next time is pressed. We can try something like the following and we recommend you to test it in your Arduino:

```
int LED = 10 ;
int button = 6 ;
bool state = false ;
void setup()
{
pinMode( LED, OUTPUT) ;
pinMode( boton , INPUT_PULLUP) ;
digitalWrite(LED , LOW) ;                        // We turn off the LED at the beginning
}
void loop()
{
bool  value =  digitalRead(button) ;            // We read the push-button switch: false  =  LOW
if ( value == false )                           // The push-button switch has been pressed
{
state = ! state;                      // We reverse the status
digitalWrite(LED, state) ;            // We write the new value
}
}```

The idea is to define a variable called status at the beginning to store the LED status. The loop() function tests whether the push-button switch has been pressed and if so, reverses its status. After that, it writes the status in the LED pin. If the LED was on, then it switches off and it switches off otherwise.

Although is seems to be a perfect plan, in practice it won’t work. In the time it took us to press and release the button our humble Arduino is able to read the push-button switch and reverse the LED status a few thousand times.

So, if Arduino reads the push-button switch an even number of times it will leave it as it were and will reverse it if it reads the push-button switch an odd number of times. In practice, The LED status will become random and if you repeatedly press the button will see that the result is unpredictable.

Another source of problems is that in the real world a switch doesn’t change from one state to another in a perfect way but it usually bounces, causing several very quick connections and disconnections before reaching an stable state. This is called bouncing and the procedure used to solve it is called debouncing in electronic slang.

There are two kinds of debouncing methods: hardware and software. The hardware method is achieved by means of a capacitor and a resistor. The software method is more often used because it is cheaper. In the software method we only have to slow Arduino down a bit , once it detects that the push-button switch has been pressed, and make it wait a time interval between 50 and 250 milliseconds, so it can give us time to release the button.

```     void loop()
{
bool  value =  digitalRead(button) ;         // We read the push-button switch: false = LOW
if ( value == false )                         // The push-button switch has been pressed
{
state = ! state ;                     // We reverse the status
digitalWrite(LED, state) ;            // We write the new value
delay(250) ;
}
}```

• Very important: Note that we have written (value == false) in the condition, with a double equal sign. In C++ the comparison operator uses a double equal sign (==), while the assignment operator only uses one. At the beginning this is a common source of mistakes for inexperienced newbies.

The 250 millisecond time interval is long enough to press and release the push-button switch easily. If you try this variant you will see that the LED reverses its status whenever is pressed, unless you take too long to release the button.

But… what if you leave the push-button switch pressed?

The LED simply reverses its status at a 250 ms (milliseconds) rate and so we have another variant to the blink LED example.
If we want to keep the push-button switch pressed without perceiving this disturbing effect we have to enhance the program a little more:

```

int LED = 10 ;
int button = 6 ;
bool state = true ;
bool previous_state = true ;

void setup()
{
pinMode(button, INPUT_PULLUP);        // We have removed R3
pinMode(LED, OUTPUT);
}

void loop()
{
if (state != previous_state)        // Something has changed: the push-button switch has been pressed or released
{
if (state == LOW)            // We change the status of the LED when pressing, not when releasing
previous_state = state;     // We store the last value of the status variable
}
}```

We already stated that to test whether two values are equal we use a double equal sign, ==. Otherwise, to test whether they are not equal we use !=.

This is the list of the relational operators:

• Equal to: ==
• Not equal to: !=
• Greater than: >
• Greater than or equal to: >=
• Less than: <
• Less than or equal to: <=

It is worth commenting that, despite its apparent innocence, buttons have an amazing ability to make us life difficult. In practice, this combination of bounces and the need to solve them, together with the use of pull up resistors to ensure a correct reading, can make it much more complicated than it seems, unless the problem is not slowly and calmly studied.

Finally, we can build a logical condition by means of the logical operators AND, OR and NOT, whose symbols are respectively: &&, || and !.

If we use a circuit with two push-button switches, with its corresponding pull up resistors plus a LED diode, depending on the chosen behaviour we can specify three different conditions:

• If ( button1 && button2) Both push-button switches are not pressed
• If ( !( button1 && button2)) Both push-button switches are pressed
• If(button1 || button2 ) At least one of them, or both, are pressed .

Summary

• We have seen the if-else statement block.
• We have seen several programs related to push-button switches and we have learnt how to cope with switch debouncing.
• We have introduced the relational and comparison logic operators.
• We keep on writing small programs to develop the needed way of thinking to be able to write our own applications.