Fads to Obsessions and Beyond...

Free domain for life, exceptional technical support, website transfer

Button Debounce - PIC Software Approach

Demonstrate a software (firmware) approach to debounce mechanical switches using interrupts on a PIC microcontroller.

When any mechanical switch is pressed to change its position, the metal contacts which form the switch do not open and close "cleanly", that is, there is no instantaneous change from zero voltage to positive voltage (and vice versa). This means that when a mechanical switch is operated, a series of low and high voltage spikes are generated (analogous to a bouncing ball), before the circuit "settles" into the final state (either low/high as determined by the on/off of the switch). This is particularly a problem when interfacing mechanical switches to digital circuits, which interpret such "bouncing" voltage spikes when a mechanical switch changes position as a series of logic pulses instead of a single "clean" transition from one logic state to another (1).

The following diagram represents the problem with switch debouncing and digital circuits, showing how a "pulse train" is produced rather than the desired "instantaneous" change in logic level.

  • Switch Debouncing DiagramSwitch Debouncing Diagram

    Silver Membership registration gives access to full resolution diagrams.

    Switch Debouncing Diagram

There are basically two ways to deal with the switch debouncing issue, hardware (e.g. set-reset latch, R-C circuit and/or specialised IC) or software (microcontroller firmware). If a microcontroller is part of the circuit design, a software/firmware approach is generally preferred (and more economical as less parts involved). Hardware approaches are not further discussed here (see (1) if this is of interest).

The software approach generally involves "continually" reading the state of the input switch, which after a voltage transition from the switch occurs, increment a counter if the voltage level is maintained, otherwise, the counter is reset. If the counter exceeds a previously set maximum number, then it is assumed a stable switch reading has been achieved.

The "continual" reading of the state of the input switch needs to be often enough so that the code is responsive to user input, however, are spaced enough in time to representatively sample the state of change of the switch. A simple delay (generally in the order of a few tens of microseconds) could be used, but generally with current microcontrollers and the "on chip" resources available, an interrupt driven scheme is preferrable.

The Testing/Experimental Results Section demonstrates the use of an interrupt driven, software switch debouncing algorithm implemented on a PIC 18F248.

The minimum requirements for a PIC (PIC16 and PIC18 dealt with here) are:

  • Power Supply (generally 5V, but 3.3V also widely available)
  • Oscillator (RC network, external crystal oscillator)
  • In-circuit serial programming (ICSP)

Power Supply

A typical "wall-wart" power-supply is used (a surplus laptop charger in this case) in conjunction with a voltage regulator (LM7805) to provide the regulated 5V required by the PIC microcontroller.

The 'wall-wart' avoids resorting to the use of a transformer/rectifier with AC input etc (after which likely a LM7805 would be used in any case to provide load and line regulation). As a 'disclaimer', the DIY hobbyist should avoid dealing with AC power as a general rule.


An external crystal oscillator is used (X1 in the schematic) with associated capacitors C1 and C2. The PIC datasheet specifies a range of suitable capacitance values for C1 and C2 depending upon the oscillator frequency being used. Higher capacitance will increase the stability of the oscillator but will also increase the start-up time.

Note, the oscillator crystals can be either series or parallel cut. The PIC18FXX8 oscillator design requires the use of a parallel cut crystal.

In-circuit serial programming (ICSP)

I use a PICkit2 as the ICSP. Connection is as per the Microchip recommendations.

PIC microcontrollers can be serially programmed while in the end application circuit (i.e don't need to remove the component). This is simply done with two lines for clock and data and three other lines for power, ground and the programming voltage. This means the microcontroller can be programmed with the latest firmware and or updated as required. The Flash program memory is readable, writable and erasable during normal operation over the entire Vdd range.


A resistor and diode is connected to pin 1 of the PIC. This is to take advantage of the PIC power-on reset (POR) circuitry, which requires MCLR (pin 1) connected directly (or through a resistor) to Vdd. The diode is to provide protection against incorrect voltage polarity.

Mechanical Switches

For the purposes of testing the switch debouncing code, two momentary push button switches are connected to PIC input pins using pull-up resistors (see Schematic Diagram Section).

As user feedback, when a switch is pressed, a corresponding LED is energised via a PIC output pin (and a text string is sent via RS232 to a connected PC).

Note: Image loading can be slow depending on server load.

  • PIC Schematic - Switch DebouncingPIC Schematic - Switch Debouncing

    Silver Membership registration gives access to full resolution schematic diagrams.

    PIC Schematic - Switch Debouncing

    PIC Schematic - Switch Debouncing

This project did not require a PCB.

The construction was done using prototyping board. See the photographs and schematic diagram sections.

Qty Schematic Part-Reference Value Notes
2R1-R310K1/4W, 10% 
Integrated Circuits
1U1PIC18F248PIC microcontroller datasheet
1U27805Linear Voltage Regulator  datasheet
1U1MAX232ERS232 Driver/Receiver datasheet
1J1CONN-H55-pin connector for ICSP
1X110MHzCrystal Oscillator
Description Downloads
PIC - Bill of Materials Text File Download

Before connecting the PIC, check the supply voltages to ensure that the linear voltage regulator (or other power supply scheme) is supplying optimally 5V. Note (from datasheet), absolute maximum voltage on Vdd with respect to Vss is -0.3V to +7.5V.

Programming the PIC

The C code (using CCS compiler) to debounce two switches connected to PORT B0 (pin 21) and PORT B1 (pin 22) and report the button press via RS232 to a connected PC is as follows:

Code Snippet 1:

#include "debounce.h"
#include "button.c"
#zero_ram //all variables automatically initialised to 0

// These are the "Bvar" variables required by Button.c. 
int8 B0 = 0;   // For the button on pin B0 
int8 B1 = 0;   // For the button on pin B1 

// Global "button pressed" variables. 
int8 B0_pressed = FALSE; 
int8 B1_pressed = FALSE; 

// The buttons are read in this Timer0 (RTCC) isr. 
void timer0_isr(void) { 
   if(button(PIN_B0, 0, 50, 10, B0, 1))    
      B0_pressed = TRUE;       
   if(button(PIN_B1, 0, 50, 10, B1, 1))    
      B1_pressed = TRUE;
   set_timer0(0); // Reload the Timer - prescaler = 1, frequency ~100mS   
void main() {
 * Function:   main()
   char recChar;  //the received character from the serial port via keyboard
   set_tris_b(0x03);  // Set Pin B0 and B1 as input
   setup_timer_0(RTCC_INTERNAL | RTCC_DIV_1);
   set_timer0(0); //prescaler = 1, frequency ~100mS 
      if (kbhit()) {      
         recChar = getc();
         //printf("cmd=%c \n\r",recChar);
         switch (recChar) {
            case 'e': 
            case 'E': printf("Cmd E\r\n");
            default:  printf("Unknown cmd\n\r");
      if(B0_pressed == TRUE) { 
         B0_pressed = FALSE; 
         printf("pressed B0\n\r"); 
      if(B1_pressed == TRUE) { 
         B1_pressed = FALSE; 
         printf("pressed B1\n\r"); 

Code Snippet 2:

#include <18F248.h>
#device adc=16

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD) 
#FUSES PUT                      //Power Up Timer

#use delay(clock=10000000) //clock=40M) //crystal=10M)
#use rs232(baud=4800,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8, ERRORS)    

Code Snippet 3: This is based upon the CCS code (2)

// Button.c 

#define read_bit_var(x)  bit_test(*(int8 *)(x >> 3), x & 7) 

int8 button(int16 pin, int8 downstate, int8 delay, int8 rate, int8 &BVar, int8 action) { 
   int8 pin_value; 
   pin_value = read_bit_var(pin); 
   if(pin_value != downstate){ 
      Bvar = 0; 
   if(Bvar == 0){ 
      if(delay == 0) 
         Bvar = 255;      
         Bvar = delay;    
   if(BVar == 0){ 
      BVar = rate; 
      if((delay != 0) && (delay != 255)) 

Once the circuit has been constructed as per the schematic (photographs of the circuit laid-out on breadboard given in the Photographs Section), the text string "pressed B0" or "pressed B1" will be sent via RS232 to an attached PC.

The circuit is the basic minimum required to enable a PIC microcontroller to operate after being programmed with a suitable .hex file. So this circuit was only laid out on a breadboard.

Before connecting the PIC, check the supply voltages to ensure that the linear voltage regulator (or other power supply scheme) is supplying optimally 5V. Note (from datasheet), absolute maximum voltage on Vdd with respect to Vss is -0.3V to +7.5V.

If the RS232 communications fail, carefully check your breadboard circuit against the schematic and the photographs in the Photographs Section. Look for "gotcha's" like the connection polarity of pullup resistors etc. If not successful with the RS232, replace the text messaging with powering on/off LED's from output ports, to enable just testing of the switch debouncing in isolation of using RS232 communications.

Also, when programming the PIC with .hex file, the PICkit2 will provide power to the circuit. In this particular simple circuit this is not of concern. However, in a more complicated circuit, it may be required to insert a 'jumper link' or even a SPST switch to isolate the application circuit from pin 1 of the ICSP connector during programming of the PIC. This will avoid possible excessive current draw that could damage the PICkit2 programmer, and or adversely affect application circuit components/connected devices.


No comments yet.

Add Comment/Question

Only Logged-In Members can add comments

"If we could sell our experiences for what they cost us, we'd all be millionaires".

Please donate any amount to help with hosting this web site.

If you subscribe (only $2/annum) you can view the site without advertisements and get emails abouts updates etc.



Only logged-in users with Silver Membership and above can download.

Silver Membership is only $2, so join now!