My approach to software debouncing - what do you think ?

Go To Last Post
3 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi !

Recently I was working with software debouncers.
I checked Danni`s code for debouncing and one software debouncer from a guide to debouncing by J.G Ganssele.
But as I am really stubborn I have decided to use my experience wich I have learned applying this two codes to write my version of software debouncer. Which I could uderstand in 100 %.
It is mainly based on software debouncer from this guide.
But please have a look and give me any remarks about it.
I think it is a lit a bit tough and not so economical using memory but for me the most important think is to understand what is going on in the code :)

Below I have pasted my approach:

My main request for you is to check if my way of thinking is good. I have enclosed plenty of comments which states what I think and what I do. Any improvements for the code are welcome. :)

#include 
#include 
#define MAX_CHECKS 8 // number of checks before a switch is debounced

/* Uninitialized global or static variables end up in the .bss section
which means that they equal 0 or null and you don`t have to assign them.
"Lucky for you you made this a BSS variable so it's guaranteed 
to be cleared to 0 anyway." */

//volatile unsigned char key_press; // here we have to use volatile
//Global variables:					// or "atomic access" function !!!
unsigned char key_press;          // "FAQ1: ISR/main variables MUST 
unsigned char key_state;          // be defined volatile"
unsigned char state[MAX_CHECKS];		   
unsigned char counter;	// uint8_t = unsigned char look avr library for 
					    // more info if you want to use this typedef
ISR(TIMER0_OVF_vect)
{
	unsigned char i,j,k; //These wariables don`t equal zero cause
	//they are not global. Assign values before you use them !!!
	static unsigned char prev_state; //This value is seen outside 
									   //ISR and is equal 0 at start
	state[counter]= (~(((PIND & 1<<2)>>2)|((PINC & 1<<2)>>1))); //input
	counter++;
	j=0xff; //mask
	k=0x00; //mask						   
	for(i=0; i 1: key press detect
   
   if (counter>=MAX_CHECKS) counter=0; //reset counter
} 

// Below is presented function called "atomic access".
// You don`t have to define key_press as volatile.
unsigned char get_key_press(unsigned char key_mask) 
{
	cli();
	key_mask &=key_press;
	key_press ^=key_mask;
	sei();
	return key_mask;
}

int main(void)
{
	unsigned char n=0;

	TCCR0 = 1<<CS01; // enable timer interrupt 
	TIMSK = 1<<TOIE0;                     

	DDRB=0xff;		
   
	PORTC=0xff; // enable internal pulling-up remember that then 
	PORTD=0xff;	// negation is triggering signal 
  
	sei(); // gloabal interrupts enable

	for(;;)
		{
			if(get_key_press(1))
			{
				n++;
			}
			if(get_key_press(2))
			{	
				n--;
			}
			
			PORTB=n;
		}
}

Thanks in Advance

Adam

Last Edited: Tue. Oct 23, 2007 - 03:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a little suggestion to improve this program.
Since the following code...

   j=0xff; //mask
   k=0x00; //mask                     
   for(i=0; i

only check any zero in state array. I think this program
could be simplified by the following...

   key_press=debounced_state;   // needed previous state
   debounced_state = 0xff;
   for(i=0; i

If you are worry too much memory been used, you could just
mark the "time" PIN state changed. Hold the new PIN state
for at least MAX_CHECKS timer interruption. I believe it
will have same effect but only require one byte for each
button.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey

I see that not much response my software debouncer received.
Is this mean it is so perfect ?? ;)

I found really one bug in my code:
It was:

key_press=debounced_state;   // needed previous state
   debounced_state|=j;
   debounced_state&=k;
   key_press=((debounced_state^key_press) & debounced_state);
   //0 -> 1: key press detect 

But it should be:

prev_state=key_state;   // needed previous state 
   key_state|=j;
   key_state&=k;
   key_press|=((key_state^prev_state) & key_state); 
   //0 -> 1: key press detect

It is really important cause we all know that ISR interrupt is called when Timer0 overflow. Let`s assume that we have pressed switch and key_press changed it state. When next interrupt occur and we will not deal with state_press it will become 0 state which means that our algorithm can miss switch press.

I don`t know if my explanation is clear enough ? :)
If not just tell me :)

bernie_w39 wrote:
I think this program
could be simplified by the following...

Well you can simplify it by this chunk of code but then you don`t have protection in both directions.

Know you wait for example for 3 confirmations (MAX_CHECKS=3 )to change the state then 0 -> 1
and then you wait 3 confirmations for changing key_state 1 -> 0.

In my opinion we provide in this way better protection against bouncing.

Any more remarks ??

Adam