Introduction: Counting Switch Bounces

About: Lifelong Maker and Educator.

We tend to think of switches as either on or off. However, mechanical switches are mechanical devices and as such, are susceptible to bouncing. Bouncing occurs when a switch changes position and proceeds to bounce off of (or momentarily lose contact with) its electrical contact. This has the effect of sending multiple, short duration pulses on the switch line before it settle on its new position. In a light switch, this is no big deal because these bounces are complete within such a short time that it is imperceptible. However, in digital circuits, this could look as if the switch is being cycled on and off dozens of times.How bad is this problem? Let's conduct an experiment to find out.

Supplies

Arduino Uno (or another variant)

LED with current limiting resistor (I like 1k) - to indicate test condition

Pushbutton - to start a new test

Breadboard and hookup wire

1k ohm external pullup resistor

Assortment of switches to test

Step 1: Background

We will build our interface to include a switch to tell the software that we are ready to conduct a test and an LED to indicate when the computer is ready. We want to ensure we capture as many of the bounces as we can. However, these may happen extremely rapidly. Because of this, we will use and External Interrupt on the Arduino. An interrupt is a way that a computer is signaled to stop what it is doing and do something else. Think about the mouse on your computer. Since all software doesn't know when you will be moving your mouse, they would all need to have some sort of periodic checking to ensure they capture these movements. Instead, your mouse generates an interrupt to tell the system that it has moved. This way, all the movement is captured, and the software doesn't need to execute code that would mostly just be a waste of time since your mouse doesn't always move. By hooking our switch to one of the external interrupt pins on the Arduino (pin 3) we can set it up to count the number of transitions of the pin from HIGH to LOW and thus measure the number of bounces.

Step 2: Construct the Circuit

Lay the circuit out however you wish (I used a convenient breadboard proto shield). The pushbutton switch will be used to tell the software to ready itself for a test run. The LED will signal that the computer is ready to start. And the test switch will be connected to the test connection with an external 1k ohm pullup resistor. I like using an external resistor for this rather than the Arduinos built in pullup since I can control the value of this component. For quickly changing events, it is sometimes better to have a lower value pullup resistor to be able to capture each individual event. Make sure you have a reliable connection to the switch or you may induce a lot of noise (which will be recorded as bounces). Until I realized that my alligator clip on a screw terminal was loose, I was recording bounces in excess of 10,000!! Once I clipped the alligator clip to the terminal itself and not the screw, they began to show the actual bounce count.

Step 3: The Code

The Arduino code is pretty simple and uses the Serial Monitor for reporting the results. Here is a description of the code:

#define btnSTART 2 // Change these pins if you want to use different ones
#define swHIT 3 // This pin is associated with External Interrupt 1
#define ledTrigger 4

#Define statements are often used in code. They are not variables and do not take up any memory in your program. They establish words that, when the compiler compiles the software, it will substitute the values you assign for the words. This is super handy if you are not sure of a particular parameter that is used a lot through your program. You can give it a name, and when you want to change it, you just need to change the value of the #define name and it will be changed everywhere in your code that you used it. It is also a great way to show people up front of what resources will be used in the code. Be careful that you do not use names that appear anywhere else in your program because the compiler will just replace that word with the value in the #define. This is the reason some programmers frown on this and use constant variables instead.

volatile int bounceCount = 0;<br>

Next, we define a variable to hold the number of bounces. Why use the qualifier "volatile" you ask? It is a way to tell the compiler of our code that this variable may change at anytime during program execution. When a compiler puts your program together, it makes choices on how to use the available memory which includes where to put variables and how to handle them. Because we manipulate this variable in our main loop (we reset it and use it to print out the results) and also use it in our interrupt service routine (to keep track of number of bounces) we want to give this information to the compiler so that it can always have ready access to this value whether we are in the main code or the interrupt code.

void setup() {
  // setup the switches and LED
  pinMode(btnSTART, INPUT_PULLUP);
  pinMode(swHIT, INPUT);
  pinMode(ledTrigger, OUTPUT);

Classic setup procedure. We will define our inputs and outputs. We use the pullup on the start button to ensure we have a strong open and shut signal.

  attachInterrupt(1, bounce, FALLING);<br>

This code then tells the Arduino that we want to have an interrupt setup on our testing pin (interrupt #1, pin 3). This interrupt will execute the routine "bounce" whenever it sees a High to Low (falling) transition on the pin.

  // Turn off the LED
  digitalWrite(ledTrigger, HIGH);

  // Start the Serial port
  Serial.begin(9600);
  
  Serial.println("Arduino Switch Debounce");
  Serial.println();<br>

This final segment in setup just establishes the initial conditions. Turn off the connected LED and get the Serial port ready to print out results.

// All the interrupt routine needs to do is increment bounceCount
// By keeping this routine small we maximize the chances of catching every bounce
void bounce() {
  bounceCount++;<br>

We setup the interrupt to run a "bounce" routine each time it met the interrupt condition. So we need to include this. In general, you want your interrupt service routines (ISR) to be a short as possible. For us, if the ISR had too much code (or worse, timing delays), another interrupt may come in while we are still handling the previous one. All we need to do is increment the bounceCount variable, so that is all that is here.

void loop() {

  Serial.println("Press START button when ready");
  Serial.println("When the LED lights, the test is ready.");
  Serial.println();

  // Wait for the START button
  while (digitalRead(btnSTART)) {}<br>

No we enter our repeating loop cycle. We print out some helpful text to the user and then wait for the start button to be pressed. The while command will not be satisfied until we press the start button so the code will just keep cycling here until that happens.

  // Then wait for it to be released
  delay(10);
  while (!digitalRead(btnSTART)) {}
  delay(1000);

  // Start the testing
  bounceCount = 0;

  // Light the LED
  digitalWrite(ledTrigger, LOW);
  Serial.println("Ready for testing...");<br>

Since our own switch is bouncy, we will wait for the switch to come to rest before we continue. This is called debouncing. The code waits for 10 ms for the bouncing to stop, then looks for the switch to be released before continuing with the code. We then reset the bounceCount variable, turn on the light to show the user we are ready, and print out to the Serial Monitor that all is well.

  // Wait for the switch to close
  while (bounceCount == 0) {}

  // If you are here, the switch was thrown
  // Wait a second to collect the bounces

  delay(1000);<br>

Now, we wait for the switch under test to be closed. When it does, our ISR is really the only thing at work, so we just delay a second to let it accumulate the counts (if you switch bounces more than a second, you got problems).

Finally, we display the results.

  // Output the results

  digitalWrite(ledTrigger, HIGH);
  Serial.print("The switch bounced ");
  Serial.print(bounceCount);
  Serial.println(" times.");
  Serial.println();<br>

Step 4: Results From Some Common Switches

When everything is ready, download the code. Start the Serial Monitor and see the intro message. Hook up your test switch to the connectors (make sure the switch is open (off). Press and release the pushbutton. After about a second, the LED will light showing the computer is ready. Flip your test switch. After about a second, the results will be displayed on the Serial Monitor.

The picture shows the results (number of bounces) of some various switches I tested. You can see that no mechanical switch is immune to this bouncing. When you write code, be aware of this so you can compensate for it with debouncing code (as simple as a small delay after switch actuation) and you can better troubleshoot code timing problems.

Try this out. And let us know if you found any particularly quite or noisy switches.