Toggle On and Off

The following text and code examples were copied and slightly modified from http://www.ladyada.net/learn/arduino/lesson5.html under http://creativecommons.org/licenses/by-sa/2.5/ as such, this page is subject to the same license. 

Having an LED turn on or off when a button is pressed is quite impressive, but it would be pretty odd if you had to press a button constantly to keep the TV on. What we want is an alternating action switch, where the press-and-release of a button does something, not just press-and-hold. Basically we want to test whether the button was just released, or just pressed.

To do this, we need to keep track of the button input value, to see if its changed. This is called the state of a button. When the state changes (an action occurs), that's when we want to perform an action.

/*
 *  Alternating switch
 */

int switchPin = 2;              // switch is connected to pin 2
int val;                        // variable for reading the pin status
int buttonState;                // variable to hold the last button state

void setup() {
  pinMode(switchPin, INPUT);    // Set the switch pin as input

  Serial.begin(9600);           // Set up serial communication at 9600bps
  buttonState = digitalRead(switchPin);   // read the initial state
}


void loop(){
  val = digitalRead(switchPin);      // read input value and store it in val

  if (val != buttonState) {          // the button state has changed!
    if (val == LOW) {                // check if the button is pressed
      Serial.println("Button just pressed");
    } else {                         // the button is -not- pressed...
      Serial.println("Button just released");
    }
  }

  buttonState = val;                 // save the new state in our variable
}


Upload it to your Arduino and try it out, watching the serial monitor as you press and release the button.
Lets go through the new lines of code:
int buttonState;                // variable to hold the button state
This line isn't too unusual, its just a variable that is going to hold the state of the button. Since we don't know the state of the button when the Arduino is first turned on, we will leave it as unknown (uninitialized).
  buttonState = digitalRead(switchPin);   // read the initial state
In the setup() procedure, we initialize (set the initial/starting value) of the button state variable by reading the button value once we've started up and set the pin to an input.
void loop(){
  val = digitalRead(switchPin);      // read input value and store it in val
OK now to the interesting part. In the loop procedure, we begin by first checking the button pin state and storing it an temporary variable val.
  if (val != buttonState) {          // the button state has changed!
    if (val == LOW) {                // check if the button is pressed
Now we see 2 if statements that are nested, this means that we perform one test and if that test comes out true we go on to perform another test. This is more complex than a simple if statement but not much more different than the kinds of decisions we make all the time.

For example:
  if ( it is raining ) {                // look up, is there water falling on me?
    if ( I have an umbrella ) {         // check my purse
      OpenUmbrella();                   // Perform the umbrella opening procedure
    }
  }
Of course, we can't open the umbrella if we don't have one. And there's no point in checking if we have one if its not raining!

In the first if statement, we check if the current button state (HIGH or LOW) is different than the last time we looked at the button. If it is different (tested by the != inequality operator ) then we execute the next group of statements, enclosed by the {} braces.

Lets move on and examine the new statement we see, which is the if-else statment.
    if (val == LOW) {                // check if the button is pressed
      Serial.println("Button just pressed");
    } else {                         // the button is -not- pressed...
      Serial.println("Button just released");
    }
This statement is easy to understand: before, we would run a test and if that test passed, we would perform the statements in the {} braces. Now we also have an alternative, which is what we should do if the test fails! Now we used to perform two tests, one for (val == LOW) and one for (val == HIGH). This code is equivalent but its a little more straightforward. If its not LOW it must be HIGH.
if
(test statement)
{ statements to perform if test is True}
else { statements to perform if test is not True}
if
val == LOW )
... }
else
... }

In the if-else statement, we simply examine val to deterimine if the last digitalRead() procedure informed us that the button is currently pressed or not pressed.
  buttonState = val;                 // save the new state in our variable
Finally, we make sure that we've updated the button state variable with the current state.

Additional Tasks:
  1. Add in an LED and modify the program to turn it on and off.
  2. Remove or comment out the "buttonState = val;" line. What happens? Why?
Comments