Get Adobe Flash player
FacebookTwitterGoogle+
English Arabic French German Italian Portuguese Russian Spanish

Did you know?

Currents of approximately 0.2 A are potentially fatal, because they can make the heart fibrillate, or beat in an uncontrolled manner
 

Help us stay online:

small donate

push button debouncing exampleThis article will use one digital input pin (PortA pin 3) to readout state of push-button connected to it. Pull-up resistor must be connected to this pin to differentiate voltage on pin when push-button is pressed and when it is released. In short period of time when push-button is pressed, voltage on input pin connected to is very noisy and this can make problems. This is shown on picture on left side. Microcontroller would interpret this as multiple push-button pressing and releasing. To eliminate this we use debouncing.

 

 

This can be implemented in hardware and software. In hardware this is done by adding capacitor to reduce noise and, optionally, comparator with hysteresis. You must agree this is too complicated and expensive if we can simply do this by writing few lines of code inside software.
Below are given examples of software push-button debouncing implemented in two ways:
1 - Without usage of timer
2 - With usage of timer


1 – Software debouncing without usage of timer:


Whole code is executed in while(1) loop. Comments in code are self-explanatory. Good side of this method is that it does not use any timer and is very simple.
Below is given source code with key lines highlighted:

/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.4 Standard
Automatic Program Generator
© Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :  push_key AVR example readout
Version : 
Date    : 2/19/2012
Author  : 
Company :      www.Electronics-Base.com
Comments:
Chip type           : ATmega8535
Program type        : Application
Clock frequency     : 8.000000 MHz
Memory model        : Small
External RAM size   : 0
Data Stack size     : 128
*****************************************************/
#include <mega8535.h>
// Standard Input/Output functions
#include <stdio.h>
#include <delay.h>
#define push_key_pin PINA.3
// Declare your global variables here
unsigned char push_key_debounce,push_key_pressed;
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTA=0x00;
DDRA=0x00;
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTB=0x00;
DDRB=0x00;
// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: Off
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x08;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
putsf("ON");
putsf("OFF");
while (1)
      {
      // Place your code here
      
      //push_key readout handler START
        if (push_key_pin==0)
        {
        if (push_key_debounce<200) //we need this condition so variable wouldnr overrun to zero and go in circles
            push_key_debounce++;
        if(push_key_debounce==199) //we ract after this number of stabilised push_key readings
            push_key_pressed=1;   //wariable where we keep state of the push_key 
        }
        else
        {
        if(push_key_debounce==200)   //push_key is unpressed and before state was pressed
            {
            putsf("OFF ");  
            putchar(13);
            }         
        push_key_debounce=0; //push_key is unpressed or dobounce noise is still in progress
        }
         //push_key readout handler END  
      
        //push_key action handler START   
        if(push_key_pressed==1)     //push_key was spessed
        {
        push_key_pressed=0;
        putsf("ON ");
        }
        //push_key action handler END
      };
} 

Complete project with source code files can be downloaded on this link.

 

2 - Software debouncing wit usage of timer:


Basically it is the same code. The only difference is that push-key readout handler is executed in interrupt routine while only push-key action handler is executed in while(1) loop. This way we ensure exact timings of push-button debouncing duration. This was not possible in first example since this time depended on other functions that are placed in while(1) loop and this time can change depending on current conditions in these functions.
Code for second example with usage of timer is given below with key lines highlighted:

 

/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.4 Standard
Automatic Program Generator
© Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :  push_key AVR example readout
Version : 
Date    : 2/19/2012
Author  : 
Company :      www.Electronics-Base.com
Comments:
Chip type           : ATmega8535
Program type        : Application
Clock frequency     : 8.000000 MHz
Memory model        : Small
External RAM size   : 0
Data Stack size     : 128
*****************************************************/
#include <mega8535.h>
// Standard Input/Output functions
#include <stdio.h>
#include <delay.h>
#define push_key_pin PINA.3
// Declare your global variables here
unsigned char push_key_debounce,push_key_pressed;
 // Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Place your code here
      //push_key readout handler START
        if (push_key_pin==0)
        {
        if (push_key_debounce<20) //we need this condition so variable wouldnt overrun to zero and go in circles
            push_key_debounce++;
        if(push_key_debounce==19) //we ract after this number of stabilised push_key readings
            push_key_pressed=1;   //variable where we keep state of the push_key 
        }
        else
        {
        if(push_key_debounce==20)   //push_key is unpressed and before state was pressed
            {
            putsf("OFF ");  
            putchar(13);
            }         
        push_key_debounce=0; //push_key is unpressed or debounce noise is still in progress
        }
         //push_key readout handler END 
}
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTA=0x00;
DDRA=0x00;
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTB=0x00;
DDRB=0x00;
// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 125.000 kHz
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x03;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x01;
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: Off
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x08;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
putsf("ON ");
putsf("OFF ");
// Global enable interrupts
#asm("sei")
while (1)
      {
      // Place your code here
        //push_key action handler START   
        if(push_key_pressed==1)     //push_key was spessed
        {
        push_key_pressed=0;
        putsf("ON ");
        }
        //push_key action handler END
      };
}

Complete project for push-button readout with usage of timer can be downloaded from this link.

On video below you can see above given examples in action.