LED Toggle with a Push-Button Switch

This new circuit is an evolution of the LED blinker circuit and program. Instead of using a delay to alternately turn the LED on and off, we are going to use a push-button to signal the system to toggle an LED on or off.

Hooking Up a Push-Button Switch to the Arduino

A push-button switch is a very simple electro-mechanical device that has a spring-loaded contact, keeping the circuit open, that is unconnected, until the button is pressed, forcing a metal piece to bridge internal contacts thus closing the electrical circuit and allowing current to flow through. The circuit re-opens as the pressure on the push button is released, preventing current from flowing.

Floating Inputs

Let’s connect normally open push-buttons as in the following diagram.

PushButton

While the button is pushed, the circuit works. S2 is connected to the power supply, providing a HIGH value to the input pin; S1 is connected to ground, providing a LOW value to the input pin. When the push-button is not depressed, what is the value at the input pin? It is undefined, neither HIGH or LOW, or possibly fluctuating between the two values as the unconnected input acts like an antenna, picking up signals from the surrounding electromagnetic noise. This situation is known as floating inputs and must be corrected.

There is a solution. As shown in the following diagram, we can connect a resistor to ground, called a pull-down resistor, for the switch connected to the power supply; or connect a resistor to the power supply, called a pull-up resistor, for the switch connected to the ground. These resistors will ensure that the value at the input pin is always in a known state.

Pull-up Pull-down
Pull-up and pull-down resistors

The value of R can be very high as the Arduino’s digital pin input impedance, that is its opposition to current when a voltage is applied, is very high.  My current SparkFun kit has 10K resistors that will do the job. Setting R to 10K will limit the current to 0.5mA (remember, V = RI, I = V/R) when the switch is closed, allowing current to flow. The Arduino offers an input pin mode that programmatically attaches a 20K pull-up resistor to the input pin, limiting the current to 0.25 mA when the switch is closed. This mode, of course, only works if the push-button is connected to ground.

The LED Toggle Circuit

The circuit that we will use is shown in the diagram below. The push-button switch is connected to the Arduino‘s input pin 12 and to a 10K pull-up resistor. The LED‘s anode is connected to digital pin 13 and its cathode, to ground through a 330Ω current limiting resistor, exactly as was done in the LED blinker circuit.

LED Toggle
LED Toggle’s complete circuit

One thing that must be said about push-buttons is that because they are electromechanical devices, the electrical contact is not instantaneous and electrical noise is produced every time the switch is closed or opened. This is caused by the way spring-loaded metal pieces bounce as they make contact with metal connectors closing the circuit within the switch. This bouncing of metal against metal makes the contact close and open repeatedly for a few milliseconds. This happens as the switch closes and as it opens. There are debouncing electronic circuits that can be used to counteract this effect. In this post, we will only use a software solution explained as part of the program below.

Breadboarding

The following picture depicts how to connect the different parts using a solderless breadboard, jumper wires, an LED, a push button, a 10K resistor and a 330Ω resistor.

LED Toggle_bb

The LED Toggle Program

You can copy the following code directly in the Arduino IDE.

Following the usual header, you will find definitions for the INPORT, input port value, and DEBOUNCE_DELAY, the time in milliseconds to allow the switch to stabilize after it changes state when it closes or opens. Finally, the Boolean value outputValue holds the on and off LED values, HIGH for turned on and LOW for turned off.

First, we prepare the board circuitry in the setup() function. The pin mode for pin INPORT is set to INPUT, which will allow us to read the switch value. Digital I/O pins on the Arduino board can be set to either output a value or input a value, not both at the same time. The circuit described previously uses a 10K pull-up resistor. We could have specified the pin to be INPUT_PULLUP instead, which would have programmatically installed a 20K pull-up resistor at the digital input pin. The pin mode for pin LED_BUILTIN is set to OUTPUT, allowing the program to output HIGH or LOW values to the LED circuitry. Within setup(), the outputValue is set to LOW and sent to the output pin, thus extinguishing the LED.

/* Light Toggle
   Uses an LED connected to pin LED_BUILTIN as a light
   source toggled on and off at the press of a button.
   This sketch was written by Michel Lagacé, 2018-09-16
   This code is in the public domain. */

// Button value will be read from pin 12
#define INPORT 12

// Time to wait in milliseconds to consider switch debounced
#define DEBOUNCE_DELAY 10

// LED state kept across loops
static bool outputValue;

// Setup the board.
void setup() {
    pinMode(INPORT, INPUT);
    pinMode(LED_BUILTIN,OUTPUT);
    outputValue = LOW;
    digitalWrite(LED_BUILTIN,outputValue);
}

// Wait for an edge and return state
bool waitForEdge() {
    bool startValue = digitalRead(INPORT);
    bool newValue = startValue;
    while (newValue == startValue) {
        newValue = digitalRead(INPORT);
    }
    delay(DEBOUNCE_DELAY);
    return newValue;
}

// Repeat forever
void loop() {
    // Wait for a rising or falling edge
    bool value = waitForEdge();

    // Toggle output on dropping edge (input is LOW when button is pressed)
    if (!value) {
        outputValue = !outputValue;
        digitalWrite(LED_BUILTIN, outputValue);
    }
}

The waitForEdge() function waits until the switch value changes from HIGH to LOW or LOW to HIGH and then returns the new switch value. The function first reads the current switch value using the digitalRead() built-in function. It then sets the newValue variable to be the same as the value just read and loops, using a while loop, until the value of the switch becomes different from the first value read. The program then waits for DEBOUNCE_DELAY milliseconds to let the switch settle. I have measured the duration of the bounce noise produced by a micro push-button switch and found that it was never more than approximately 4 milliseconds. I believe that it is therefore safe to let the switch settle for twice that amount of time. Since the switch cannot be depressed manually for more than 50 times per second, it is also safe to assume that a 10 millisecond wait will not prevent normal operation of the switch. The limitation that a 10 millisecond delay imposes is that we will not be allowed to close and open the switch within a 20 millisecond lapse of time, having to wait 10 milliseconds when the switch is closed and another 10 milliseconds when the switch is open. The waitForEdge() function returns the last switch value read.

The while loop works similarly to the for loop seen in the Morse code generator. It executes the code contained between the curly braces until the specified condition is not met, or false. Unlike the for loop, the while loop lacks initializer and post-processing statements. it has the following structure:

    while (condition) {
        // Execute the code within the curly braces
    }

Finally, the main loop() function repeatedly waits for a switch value change through a call to the waitForEdge() function. If the returned value is LOW, that is the push-button has been depressed making the!value condition true, the LED outputValue is inverted, or toggled, and then output to digital pin LED_BUILTIN.

What Next?

This circuit shows how one can read a digital value using the digitalRead() function, how switch noise can be removed with a debouncing delay, and how the while loop control structure works. You can experiment with the circuit and program to see first what happens if you remove the pull-up resistor and move your hand around the circuit. The LED will turn off or on unexpectedly without you having touched the switch. You can also try to touch the open digital input attached to the switch with your finger. The LED will start flickering as your body acts as an antenna and picks up the 50 or 60 Hz electromagnetic signals surrounding us. As another experiment, comment out the delay() line within the waitForEdge() function and depress the switch repeatedly. At some point, the LED will remain as it was, without toggling, or will briefly flicker, quickly turning on and off.

Published by

Michel Lagacé

40 years working in the high technology sector, I now share tips and tricks on software and electronics. I also write in my spare time.

2 thoughts on “LED Toggle with a Push-Button Switch”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s