Testing debounce software from a guide to debouncing problem

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

Hi folks

You all advise this great guide to debouncing by JACK G. Ganselle. I wrote program from listing 3 "Handling multiple inputs" Everything looks fine in AVRstudio but when I program my atmega8 via AVRISP II it is not working as it should. What is wrong in the code ??

#include 
#include 


#define MAX_CHECKS 10  //checks befgore a switch is debounced

unsigned int debounced_state;
unsigned int state[MAX_CHECKS];
unsigned int index1;

unsigned int RawKeyPressed(void);

ISR(TIMER0_OVF_vect)
{
	unsigned int i,j;
	state[index1]=RawKeyPressed();
	++index1;
	j=0xff; //maska dla naszego debouncera ;)
	for(i=0; i=MAX_CHECKS) index1=0;
	
}

int main(void)
{
	state[MAX_CHECKS]=0;
	index1=0;
	
TCCR0 = 1<<CS01;                      
TIMSK = 1<<TOIE0;                     //enable timer interrupt	

DDRB=0xff;
PORTC=0xff;
PORTD=0xff;
sei();

for(;;)
	{PORTB|=0x04;
		if(debounced_state & 0x08)
		{
			PORTB|=0x01;
		}
		else
			PORTB&=0xfe;
		
		if(debounced_state & 0x20)
		{
			PORTB|=0x02;
		}
		else
			PORTB&=0xfd;	
	}
}

unsigned int RawKeyPressed(void)
{
	unsigned int bufor;
	cli(); reading from
	bufor=((PIND & 1<<5)|(PINC & 1<<3));//want to read from PIND5 and PINC3 ??
	sei();
	return bufor;
}

Thanks in advance for help

Adam

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

Quote:
not working as it should

That's not a whole lot to go on is it?

But one real dangerous thing there is that you call RawKeyPressed() from early in the ISR and this then does an sei() - that's never a great idea in an ISR unless you REALLY know what you are doing. As the AVR vectors into the ISR via the jumptable it does an implicit CLI and when it gets to the very end of the ISR and does a RETI that includes an SEI - so it's not normally necessary to code those in the AVR

As you don't specically program the timer apart from starting it and enabling interrupts this code is going to be directly dependent on F_CPU so you may want to say what that is too. (the interrupts are going to occur at F_CPU/256)

(well actually all timers are always dependent on F_CPU but I guess you know what I mean!)

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

Exactly not so much code to let the ball rolling ;)
I got rid of these sli() and cli() in reading function:

unsigned int RawKeyPressed(void)
{
	unsigned int bufor;
	bufor=((PIND & 1<<5)|(PINC & 1<<3));
	return bufor;
}

But still doesn`t work :/

Please help me with this simple code.

Adam

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

Well that's the second time you have said "doesn't work". I remember I once took my car to be serviced and just told them "it didn't work". Can you imagine my surprise, after I paid them $500 for 8 hours labour when I found that it still didn't work when I drove it home? I guess they must have been hopeless engineers?

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

Oh it`s not like that :)
I am not a lazy boy :)
I am really stubborn. ;) I understand what`s going on in this code and know about timers. This code is really easy not so complicated as Danni`s code.
But I am a lit a bit nervous cause I am siting whole weekend on these software debouncers and I cannot apply them.
Last post concerned Danni`s code:

https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=55185

Probably you see that I am missing something but I can`t. But I am surprised that everything is working in AVRstudio but on a real hardware not.

Adam

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

Just out of interest why are you using 16 bit wide "unsigned int" when Ganssle suggests "uint8_t" ? (although that shouldn't be the problem).

By the way, so far, you still haven't told us:

1) which AVR
2) what clock speed
3) what the "problem" actually is.

Oh and:

state[MAX_CHECKS]=0;

does not do what I think you are after if you are following Ganssle's advice to start state at 0. For one thing the 'state' array only has elements state[0]..state[MAX_CHECKS-1] so there isn't a state[MAX_CHECKS] element anyway but even if there were, just setting the last element to 0 does not clear the entire array. Lucky for you you made this a BSS variable so it's guaranteed to be cleared to 0 anyway.

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

Yes I should use unsigned char
I am using: atmega8
clock speed: 1000000 [Hz] (I haven`t changed fuses)
Using WinAVR for writing code and for debuging AVRstudio.

Problem is that when I press one button which is connected to PINC3 should make my diode to go high and light. The same should do second button with another diode,second button is connected to PIND5.

When I press buttons diodes don`t light.

Adam

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

By the way, this program violates FAQ #1 which is more than likely your problem though your use of PORTC as well could mean that FAQ#5 is also involved (though that tends to affect the UPPER four bits of PORTC)

EDIT: Ah now that you've finally identified it as mega8 you can forget FAQ#5 as mega8 doesn't have JTAG (our posts just crossed). So my money is on FAQ#1 - I'm just testing it on the STK600 with a Dragon to check operation.

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

PS Yup that code seems to work just fine on this STK600 once you change:

volatile uint8_t debounced_state;

(I also changed all the other vars to uint8_t as per Ganssle). I just tested it with PD5 but I've no reason to doubt that PC3 would work as well.

(course PC3 on the mega32 is one of the JTAG pins so grounding this with a switch while trying to debug it using a Dragon was not a great experience - I guess I should have read the mega32 datasheet FIRST in fact and not waited until something went wrong!)

One interesting question for you - given that you are just echoing the button state to an LED - how on earth can you tell whether it's actually debouncing or not? (unless you have SuperMan's eyes?)

Last Edited: Mon. Oct 15, 2007 - 03:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tricky but when I changed the code:

I redefined these virables which are shared with ISR
All diodes are high :) Not responding for pressing buttons
Hah but the truth is close :) I can feel it :)

#include 
#include 


#define MAX_CHECKS 3  //checks befgore a switch is debounced

volatile unsigned int debounced_state;
volatile unsigned int state[MAX_CHECKS];
volatile unsigned int index1;

volatile unsigned int RawKeyPressed(void);

ISR(TIMER0_OVF_vect)
{
	unsigned int i,j;
	state[index1]=RawKeyPressed();
	++index1;
	j=0xff; 
	for(i=0; i=MAX_CHECKS) index1=0;
	
}

int main(void)
{
	unsigned char t;
	for(t=0;t<=MAX_CHECKS;t++)
	state[t]=0;
	
	index1=0;
	
TCCR0 = 1<<CS02;         //was CS01             //divide by 256 * 256
TIMSK = 1<<TOIE0;                     //enable timer interrupt	

DDRB=0xff;
PORTC=0xff;
PORTD=0xff;
sei();

for(;;)
	{PORTB|=0x04;
		if(debounced_state & 0x08)
		{
			PORTB|=0x01;
		}
		else
			PORTB&=0xfe;
		
		if(debounced_state & 0x20)
		{
			PORTB|=0x02;
		}
		else
			PORTB&=0xfd;	
	}
}

volatile unsigned int RawKeyPressed(void)
{
	unsigned int bufor;
	bufor=((PIND & 1<<5)|(PINC & 1<<3));
	return bufor;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well THAT *should* have worked. Here's the exact code I used on the 7.37MHz mega32 (after adding some debug stuff to it):

#include  
#include  


#define MAX_CHECKS 10  //checks befgore a switch is debounced 

volatile uint8_t debounced_state; 
uint8_t state[MAX_CHECKS]; 
uint8_t index1; 
uint8_t my_buf[32];
uint8_t buf_wr = 0;
uint8_t buf_rd = 0;

void send_char(
	uint8_t 	c
){
//	return; // no comms
        while (!(UCSRA & (1<<UDRE))); // wait till transmit Data register is empty
        UDR = c; // send the character
}

void
send_space(
	void
){
	send_char(' ');
}

void
send_crlf(
	void
){
	send_char('\r');
	send_char('\n');
}

void
send_str(
	char * str
){
	
	while (*str != '\0') {
		send_char(*str);
		str++;
	}
}

uint8_t is_char(void) {
	return (buf_rd != buf_wr);
}

uint8_t get_char(void) {
	uint8_t retval;
	retval = my_buf[buf_rd++];
	if (buf_rd > sizeof(my_buf)) {
		buf_rd = 0;
	}
	return retval;
}

void init(void) {
	/// Enable UART receiver and transmitter and receive interrupt 
	UCSRB = (1 <<RXCIE) | ( 1 << RXEN ) | ( 1 << TXEN ) ;
	/* Set the baud rate 115,200 at 7.3728MHz*/
	UBRRL = 3;
}


ISR(USART_RX_vect)
{
    if (UCSRA & ((1<<FE) | (1<<DOR)))           // Framing or over run error
    {
    }                         // always read a character otherwise another interrupt could get generated
                              // read status register before reading data register
    my_buf[buf_wr++] = UDR;       // get char
	if (buf_wr > sizeof(my_buf)) {
		buf_wr = 0;
	}
}


ISR(TIMER0_OVF_vect) 
{ 
	uint8_t i,j; 
	state[index1]=((PIND & 1<<PD5)|(PINC & 1<<PC3)); 
	++index1; 
	j=0xff; //maska dla naszego debouncera ;) 
	for(i=0; i=MAX_CHECKS) index1=0; 
} 

int main(void) 
{ 
	char buf[10];
   	index1=0; 

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

	DDRB=0xff; 
	PORTC=0xff; 
	PORTD=0xff; 
	sei(); 

	send_str("Hello");

	for(;;) {
		PORTB |= 0x04; 
		itoa(PIND, buf, 16);
		send_str("D=0x");
		send_str(buf);
		send_crlf();
		if(debounced_state & (1<<3)) 
		{ 
			PORTB|=(1<<PB0); 
		} 
		else {
			PORTB&=~(1<<PB0); 
		}

		if(debounced_state & (1<<5)) 
		{ 
			PORTB|=(1<<PB1); 
		} 
		else {
			PORTB&=~(1<<PB1);    
		}
	} 
} 

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

Even using your code didn`t help
I supose it is maybe something with programmer(I bought recently AVRISP II) or maybe with hardware but there is not so much hardware here ;)

Final code:

#include 
#include 


#define MAX_CHECKS 10  //checks befgore a switch is debounced

volatile uint8_t debounced_state;
uint8_t state[MAX_CHECKS];
uint8_t index1;
uint8_t my_buf[32];



ISR(TIMER0_OVF_vect)
{
   uint8_t i,j;
   state[index1]=((PIND & 1<<PD5)|(PINC & 1<<PC3));
   ++index1;
   j=0xff; //maska dla naszego debouncera ;)
   for(i=0; i=MAX_CHECKS) index1=0;
}

int main(void)
{
   
      index1=0;

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

   DDRB=0xff;
   PORTC=0xff;
   PORTD=0xff;
   sei();

   

   for(;;) {
      PORTB |= 0x04;
      
      if(debounced_state & (1<<3))
      {
         PORTB|=(1<<PB0);
      }
      else {
         PORTB&=~(1<<PB0);
      }

      if(debounced_state & (1<<5))
      {
         PORTB|=(1<<PB1);
      }
      else {
         PORTB&=~(1<<PB1);   
      }
   }
}



Adam

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

Well you'll know if the code is programmed or not because of:

   DDRB=0xff; 
     PORTB |= 0x04; 

This ensures that until any buttons are pressed 7 of the STK LEDs are on but PB2 is off. In fact, for even more "signs of life" you can easily make the PB2 LED flash using something like:

uint8_t count;

ISR(TIMER0_OVF_vect) 
{ 
	uint8_t i,j; 
	state[index1]=((PIND & 1<<PD5)|(PINC & 1<<PC3)); 
	++index1; 
	j=0xff; //maska dla naszego debouncera ;) 
	for(i=0; i=MAX_CHECKS) index1=0; 
	if (count++ == 200) {
		PORTB ^= (1<<PB2);
		count = 0;
	}
}

In which I've added a new global variable 'count' and have also added the last few lines of the ISR that toggle the state of PB2 after every 200 interrupts. At 1MHz this flashing it easily visible.

Cliff

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

Yes I made changes to see if programmer is ok but it is good. Led is blinking on and off. But buttons not.
Each time I try to take software debouncer and try to implement it i become defeated.

Cliff maybe you have good checked code for software debouncing. I know that many folks provided here many algorithms but I can`t find my favourite.

Adam

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

Like I say, your code DOES work (and the fact that it's so close to Ganssle's suggestion I'd suggest that it does work to debounce too)

If it works on my STK600 and not on your STK500 (which as far as LEDs and buttons are identical) then it suggests that you maybe just haven't set up your patch cables OK. Clearly if you are seeing the LEDs then I guess you have 10 way from PORTB to LEDs (just as I have) but do you have wires from the SWn switch pins to the PINC and PIND port headers you are trying to read?

In fact, forget the debounce stuff for now, just put a 10 pin cable from the switches header to the PORTD header and try:

int main(void) {
 DDRB = 0xFF;
 PORTD = 0xFF;
 while (1) {
   PORTB = PIND;
 }
}

and press the buttons - the lights (well at least some of them) should change! If they don't it's a fundamental wiring issue.

Cliff

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

Uff Finally I made it :))))
I thought that internal pulling-up will be enough but it occured that on PINC3 and PIND5 was state 1 which created constantly high state on output. When I add two pulling-up resistors to the inputs everything started working as it should.

Well from many tutorials I have learnt that internal pulling up is enough. But as you can see without external pulling-up it would not work :/

I am confused now :)

Sorry Cliff that I took you so many time.
But I hope some day I will have opportunity to stand you a good Polish beer. ;)

clawson wrote:
if it works on my STK600 and not on your STK500 (which as far as LEDs and buttons are identical) then it suggests that you maybe just haven't set up your patch cables OK

I am not so lucky. I don`t have STK500. I am programming by AVRIP mkII on breadboard. I would like to have STK500 but it is to expensive for me now ;)

Once again thanks a milion Cliff

Adam

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

Oh right - I was working under a mmis-apprehension. I assumed you had an STK500. This is why it's SO important when reporting problems to give ALL the details like which AVR, which compiler, what circuit, what AVR clock speed, etc, etc.

The STK500 has the advantage that the buttons work as active low and therefore simply need the internal pull-ups to be activated.