In this switch debouncing tutorial part 1 the cause and effect of switch bounce will be explained and demonstrated, then a cost effective hardware debouncing solution will be discussed, with oscilloscope captures to demonstrate the results. The last section of part 1 will show a simple program based on the MSP430 , this can be used to see the effects of a particular switch connected to the GPIO. Switch deboucing tutorial part 2 of this tutorial will look at further C code debounce algorithms and their effectiveness.
All the software solutions shown will be demonstrated on the MSP430G Launchpad. However the basic principle of operation shown in the examples, can be applied to all microcontrollers, particularly the last example which is based on some code found on Jack Ganssle tutorial, this can be easily implemented on any system using the C language.
Switch Contact Bounce
Switch contact bounce is a common issue for all mechanical switches, this includes mechanical relays. The contact bounce occurs when the metal contacts of the switch are forced together, the property of the metals used causes the contacts to bounce apart. How often the contacts bounce apart before finally latching shut depends on the contact type and the property of the switch. The bouncing effect can causes multiple high frequency pulses, as opposed to a clean transition at the output. If we take an example of a microcontroller with a switch connected to one of it’s GPIO pins, the microcontroller is able to read these high frequency pulses, misinterpreting them as legitimate presses, resulting in an undesired action.
The image below shows a basic circuit used to test switch contact bounce.
With the circuit constructed on some breadboard, an oscilloscope was connected to the GPIO pin header and set to trigger when the switch was pressed, the resultant capture can be seen below.
The oscilloscope captures shows the steady state of just over 3.3V, as the switch is pressed and released, multiple pulses are visible during this time. The switch used for this capture was an old switch I found in a bag of spares I had, it was a small momentary touch which had a sprung button. Many of these extra pulses would be picked up by a microcontroller, causing unexpected behaviour with your program if no debouncing was used.
The next oscilloscope capture was taken using a small PCB mounted tac switch, this was set-up in the same way as the previous test.
It can clearly been seen that this inexpensive PCB switch has a far superior switching action, but there is still bouncing going on, as the expanded image below shows in greater detail.
Hardware Solution
There are many hardware solutions to solve switch contact bounce, ranging in price from a dedicated microcontroller programmed purely to act as a debouncer, or a dedicated key encoder (MM74C923) with built in debounce, to a low end solution using just a resistor and capacitor. This tutorial will only cover the latter option, as when combined with a suitable software algorithm, provides a cost effective solution for most small microcontroller applications.
A simple resistor capacitor switch deboucing circuit can be seen below.
The resistor capacitor combination forms an RC circuit, which has a time constant determined by τ = R*C, therefore 47kΩ*100nF = 4.7mS. The capacitor is considered charged after approximately 5*τ, therefore roughly 25mS. So when the switch S2 is pressed effectively closing the switch, the voltage across the capacitor is discharged through the switch to ground. As there is very little resistance this happens quickly, but as will be shown not instantly. When the switch is released and becomes open, the capacitor is charged via R2 and should take approximately 25mS to charge back up to the supply voltage. Any spikes caused by bouncing contacts are absorbed by the RC circuit, however care must be taken when selecting the values to ensure the switching action is fast enough for the project. If the resistor or capacitor is too large the time lag may cause the system responsiveness to suffer, too small and a switch with a long bounce characteristic will still have an issue. Capturing the switch bounce with an oscilloscope is the best way to view the problem and then take the appropriate action. The oscilloscope capture below shows the circuit in action using the cheap PCB tac switch.
This clearly shows a huge improvement in the switching noise, the falling edge shows a clean edge, while the leading edge is curved due to C1 charging through R2. The next image shows the falling edge of the capture on a smaller time base.
The falling edge can still be seen to show the capacitor discharge curve, this takes approximately 1uS, therefore the resistance to ground is approximately 2Ω. The next image shows the rising edge of the capture on a smaller time base, the image clearly shows the capacitor curve levelling off around 25mS.
This circuit will work sufficiently in most situations, but it is best practice to discharge the capacitor in a more controlled fashion, especially if there are higher currents and voltages involved. A second resistor can be used in conjunction with R2, thus ensuring C1 has a higher resistance path to ground, when the switch S2 is closed. The image below shows a circuit using this additional resistor (R1).
The combination of R1 and R2 has very little impact on the original time constant, but allows a controlled discharge of the capacitor to ground. The value of R1 would typically be less than 6.8kΩ, being dependant on the requirements of the system. This will ultimately improve the life of the switch, as it avoids high instantaneous currents.
Before finishing part 1 of this tutorial, a basic code example is shown below which allows some of the contact bounces from a switch to be recorded on a MSP430 Launchpad.
/*** GPIO Set-Up ***/ P1DIR |= BIT0 + BIT6; P1OUT &= ~BIT0; P1OUT |= BIT6; P2DIR &= ~BIT0; P2SEL |= BIT0; /*** Timer1_A Set-Up ***/ TA1CCTL0 |= CM_2 + CCIS_0 + CAP + CCIE; TA1CTL |= TASSEL_2 + TAIE + MC_3; _BIS_SR(LPM0_bits + GIE); } //Timer_A1 TACCR0 Interrupt Vector Handler Routine #pragma vector=TIMER1_A0_VECTOR __interrupt void Timer1A0(void) { P1OUT ^= BIT0; Count++; }
The code snippet above is used with an external switch, connected to GPIO pin P1.0, which is configured to function with Timer0_A. Timer0_A is set-up in capture mode and configured to trigger an interrupt on every falling edge pulse. Every time the interrupt is triggered the variable count is incremented, therefore by running this code it is possible to determine roughly how noisy a switch is. To see the updated count value, the code can be run then the switch pressed, the code can then be paused to check the value of Count, or a breakpoint can be set and the variable Count watched.
Test Code
The link below contains the zip file with the full example C code.
In Part 2 debounce algorithms will shown with C examples, they will all be written to run on the MSP430 but the principle of operation can be carried over to other microcontrollers. The last code example in particular can easily be implemented on other microcontrollers.
Hi, i am using the MSP430F155, and I am trying to use the external DMA to be triggered on a rising edge of an external timing controller. Currently i am using the Timer B interrupt vector in order to calculate till i have an overflow on the my timer register before triggering the external DMA on the next rising edge. My challenge is that this method only works when the MSP430 is running before I run the external timing controller. If i do it the other way around , I am out of sync and the signals are not correct anymore. Do you have any idea how can i fix this issue?
Hi,
Sorry for the late reply just been very busy. Unsure your end application, but if you just need to detect a rising edge then surely using a interrupt triggered by the port changing from low to high would be the best option. If you need to count edges or pulse, then using a pin associated with a timer is required.
There is some code I posted here for a frequency counter that maybe of use.
msp430g-launchpad-frequency-counter
This is based on a similar tutorial I wrote for frequency measurement with a TI Stellaris
http://coder-tronics.com/stellaris-timer-example/
Regards,
Ant
Got a msp430f5438a and my debuger says that BCSCTL1 and the other for expressions are not defined.
BCSCTL1 = CALBC1_8MHZ; // Set range
DCOCTL = CALDCO_8MHZ; // Set DCO step + modulation
Could somebody or the humble tutorial writer give me a tip how to find the write expressions for my msp430 family? I am looking throw the datasheets and i find hundreds of DCO but no BCS, no CAL… i don’t understand the datasheet and find nearly no examples for my family. I know I ask for much but not for you to look throw the datasheet only tips how i can learn to find the right expressions.
Thank you very much in advance!!!!
Hi,
The BCSCTL1 is defined in the msp430g2553.h header file but in your case using msp430.h as the header file should work as this includes the header file for your microcontroller. Make sure you have included the header file as a first check.
BCSCTL1 is defined as follows
SFR_8BIT(BCSCTL1); /* Basic Clock System Control 1 */
DCOCTL is defined as follows
SFR_8BIT(DCOCTL); /* DCO Clock Frequency Control */
If you are using the CCS IDE, highlight the statement and right click, then select the option to ‘Open Declaration’ to view the header file contents for that statement.
This person had a similar problem to you so reading the link may help you as well
Texas Instruments EE Forum post
Cheers,
Ant