Silicon Labs Silicon Labs Community
silabs.com
Language
  • 简体中文
  • 日本語
  • MCUs
    • 8-bit MCU
    • 32-bit MCU
  • Wireless
    • Bluetooth
    • Proprietary
    • Wi-Fi
    • Zigbee & Thread
    • Z-Wave
  • More Products
    • Interface
    • Isolation
    • Power
    • Sensors
    • Timing
  • Development Tools
    • Simplicity Studio
    • Third Party Tools
    • Thunderboard
  • Expert's Corner
    • Announcements
    • Blog
    • General Interest
    • Projects
  1. Community - Silicon Labs
  2. Blog

Chapter 6: User Interface Experiments Part 2 - Switch Bounce

08/233/2015 | 01:11 PM
lynchtron

Level 5


makersguide_ch6_2.png

Switch Bounce

Another issue in the design of button interfaces is switch bounce, also known as contact bounce or chatter.  When a mechanical switch is pressed, the metal contacts inside actually bounce on the surface of each other for some amount of time before they settle down and remain in contact.  The Stater Kit has two pushbuttons which are “debounced” via an RC filter.  The resistor and capacitor create a low-pass filter that doesn’t allow the sharp rise and fall waveforms of switching bouncing to occur.   The change in voltage passing through the pushbutton is smoothed to create a single button press event.  There are more robust debouncing circuits that involve flip-flops and even integrated circuits dedicated to solve this problem in hardware.  That may be right for your solution if the response time is critical, but for most applications, you can handle this solely in software without any external components at all.

 

4.4_user_pushbuttons.png

 

Keep in mind that other user actions can cause indeterminate states.  Switches can bounce when they are pressed and again as they are released.  Sometimes, they don’t bounce at all and work perfectly.  As switches are used in the field and age, they can perform differently than the new switches that you test for your prototype.  In addition, you will get similar bouncing waveforms from a plug being inserted into a socket.  If your design is trying to detect that event, you will need to debounce the plug event.  To handle all of these situations, you will need to develop a software algorithm to detect the initial event and then wait for some amount of time until the bouncing has stopped before you allow another input event.

 

Since the pushbuttons on the Starter Kit are brand new and already debounced in hardware, I used a jumper wire attached to the GPIO pin PF9 and then touched it against the VMCU power rail to introduce a nasty switch bounce effect.  The following code will count the number of times the jumper has been touched to VMCU, which is the pin right next to PF9.

 

#include "em_device.h"
#include "em_chip.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "utilities.h"
 
#define TEST_JUMPER_PORT      gpioPortF
#define TEST_JUMPER_PIN       9
 
/**************************************************************************//**
 * @brief  Main function
 *****************************************************************************/
int main(void)
{
      // Chip errata
      CHIP_Init();
 
      setup_utilities();
 
      CMU_ClockEnable(cmuClock_GPIO, true);
 
      // Set up the user interface buttons
      GPIO_PinModeSet(TEST_JUMPER_PORT, TEST_JUMPER_PIN, gpioModeInput,  0);
 
      bool pressed = false;
      int number_of_presses __attribute__((unused)) = 0;
 
      while (1)
      {
            if (GPIO_PinInGet(TEST_JUMPER_PORT, 9))
            {
                  if (pressed == false)
                  {
                        number_of_presses++;
                        pressed = true;
                  }
            }
            else
            {
                  pressed = false;
            }
      }
}

I am keeping track of the number of times the jumper has been touched against VMCU with the number_of_presses variable.  I have added a special message to the compiler in the declaration of this variable with __attribute__((unused)) that I don’t want to see any compiler warnings if this variable is unused.  I like to do this whenever I declare a variable that I will use strictly for debugging purposes, and it keeps my build console clean.

 

In order to use this code, compile and run the debugger, then put a break point on the if (GPIO_PinInGet…) line, and the code should immediately break in a that line.  Examine the value of the number_of_presses variable is zero by hovering your mouse over it.  Remove the breakpoint, and click on the resume button.  Then touch the jumper from PF9 to VMCU once and then remove the jumper from VMCU.  Set the breakpoint on the if line again, which should again cause the debugger to break in and allow you to examine the value of the number_of_presses.  If you only touched the jumper one time, it should contain a count of one, but it will sometimes be higher than one.  It depends on how cleanly you touched the jumper to the pin.

 

To debounce this switch, we need to start a timer when the jumper is touched to the pin, and not allow another touch or release until the timer expires.  Then, we need to do the same thing when the jumper is released from the pin.

 

#define DEBOUNCE_TIME         300  // ms
 
      bool pressed = false;
      int number_of_presses __attribute__((unused)) = 0;
      int debounce_pressed_timeout = 0;
      int debounce_released_timeout = 0;
 
      while (1)
      {
            if (GPIO_PinInGet(TEST_JUMPER_PORT, 9))
            {
                  if (pressed == false && expired_ms(debounce_released_timeout))
                  {
                        // You could start some process here on the initial event
                        // and it would be immediate
                        number_of_presses++;
                        pressed = true;
                        debounce_pressed_timeout = set_timeout_ms(DEBOUNCE_TIME);
                  }
            }
            else
            {
                  if (pressed == true && expired_ms(debounce_pressed_timeout))
                  {
                        // You could start some process here on the release event
                        // and it would be immediate
                        pressed = false;
                        debounce_released_timeout = set_timeout_ms(DEBOUNCE_TIME);
                  }
            }
      }

I found that a DEBOUNCE_TIME of 100ms was not sufficient for this jumper wire switch, and I had to look at an oscilloscope waveform to figure out why that was so.  Sure enough, attaching a jumper to pin with a wire actually connects and disconnects over a longer period of time than a switch, as much as 300ms.  Sometimes, it can toggle back and forth between VMCU and ground many times before settling on VMCU, so I set DEBOUNCE_TIME to 300ms to be safe.  More characterization and test is needed to ensure that this value will work for every user that interacts with your device and with your users.

 

6.2_switch_bounce.png

 

Keep in mind when using GPIO interrupts that switch bounce will cause many rapid interrupts to occur.  If you were to always trigger an interrupt handler to do something on each button press, you will find that you get more button presses than what the user actually presses.  Therefore, you will either need to disable the interrupts for a time after a button is pressed, or allow the interrupt to trigger but always check a timer to see if the time for switch bounce has passed before taking any action.

 

This jumper wire should perform much more poorly than an SMT switch, but you never know until you test it.

 

More research on this topic can be found in this article from The Embedded Muse.  An analysis of multiple switches are performed, and hardware and software solutions to the problem are explained.

 

One more thing to consider: whenever a user connects power to your device, whether it be through a battery or a connector, the MCU will see power for a few milliseconds and then power will be lost, due to the same phenomenon we are studying in this lesson.  Therefore, I always recommend putting a delay in the beginning of your program to allow everything to settle down before you start to process any of your inputs or sensors.  You don’t want to do a one-time only event such as the first ever power-on initialization only to see power be removed a few milliseconds after it was applied.  While debugging, I will usually inject a delay(400) statement in my programs as soon as I enable the clocks and the SysTick interrupt before the MCU tries to initialize anything else.

 

PREVIOUS | NEXT 

  • Blog Posts
  • Makers
  • erikm

    Pathfinder
    Level 7


    Replied Aug 21 2015, 2:50 PM

    My preferred way to do switches (one or a lot) is to read the switches in a timer ISR with the timer set to bounce time + safety.  then if you read the same twice your switch read is valid

    0

Tags

  • Wireless
  • High Performance Jitter Attenuators
  • EFR32MG21 Series 2 SoCs
  • Blue Gecko Series 2
  • Zigbee SDK
  • ZigBee and Thread
  • Internet Infrastructure
  • Sensors
  • Blue Gecko Bluetooth Low Energy SoCs
  • Z-Wave
  • Micrium OS
  • Blog Posts
  • Low Jitter Clock Generators
  • Bluetooth Classic
  • Makers
  • Flex SDK
  • Tips and Tricks
  • Smart Homes
  • IoT Heroes
  • Reviews
  • RAIL
  • Simplicity Studio
  • Mighty Gecko SoCs
  • Timing
  • Blue Gecko Bluetooth Low Energy Modules
  • Clocks
  • Ultra Low Jitter Clock Generators
  • General Purpose Clock Generators
  • Industry 4.0
  • Giant Gecko
  • 32-bit MCUs
  • blue-gecko-xpress-modules
  • Bluetooth Low Energy
  • 32-bit MCU SDK
  • Gecko
  • Microcontrollers
  • News and Events
  • Industrial Automation
  • Wi-Fi
  • Bluetooth SDK
  • Community Spotlight
  • Biometric Sensors
  • General Purpose Jitter Attenuators
  • Giant Gecko S1
  • Flex Gecko
  • Internet of Things
  • 8-bit MCUs
  • Isolation
  • Powered Devices

Top Authors

  • Avatar image Mark Mulrooney
  • Avatar image Siliconlabs
  • Avatar image Nari Shin
  • Avatar image lynchtron
  • Avatar image deirdrewalsh
  • Avatar image Lance Looper
  • Avatar image lethawicker

Archives

  • 2014 December
  • 2015 January
  • 2015 February
  • 2015 March
  • 2015 April
  • 2015 May
  • 2015 June
  • 2015 July
  • 2015 August
  • 2015 September
  • 2015 October
  • 2015 November
  • 2015 December
  • 2016 January
  • 2016 February
  • 2016 March
  • 2016 April
  • 2016 May
  • 2016 June
  • 2016 July
  • 2016 August
  • 2016 September
  • 2016 October
  • 2016 November
  • 2016 December
  • 2017 January
  • 2017 February
  • 2017 March
  • 2017 April
  • 2017 May
  • 2017 June
  • 2017 July
  • 2017 August
  • 2017 September
  • 2017 October
  • 2017 November
  • 2017 December
  • 2018 January
  • 2018 February
  • 2018 March
  • 2018 April
  • 2018 May
  • 2018 June
  • 2018 July
  • 2018 August
  • 2018 September
  • 2018 October
  • 2018 November
  • 2018 December
  • 2019 January
  • 2019 February
  • 2019 March
  • 2019 April
  • 2019 May
  • 2019 June
  • 2019 July
  • 2019 August
  • 2019 September
  • 2019 October
  • 2019 November
Silicon Labs
  • About Us
  • In the News
  • Email Newsletter
  • Cookies
  • Contact Us
  • Community
  • Site Feedback
  • Investor Relations
  • Blog
  • Privacy and Terms
  • Corporate Citizenship
Copyright © Silicon Laboratories. All rights reserved.
粤ICP备15107361号-1