ISR(INT0_vect) - external interrupt TOO SENSITIVE

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

Hello everyone,

I intend to use an external interrupt by setting the INT0 pin (atmega64 - gcc AVR Studio - v.4.18, Build 700) and triggered at the falling edge, and the following code is working, but it's way too SENSITIVE. If i just slightly touch the side of the button (without pushing it) the ISR triggers. What should i do for INT0 to be triggered only at the push of the button? does this has something to do with 'debouncing'? Should i add some extra code or maybe it has sthing to do with the value of the resistor being used?

the INT0 pin is connected to a 4.7k resitor which is connected to 5V. When the push button is pressed, the INT0 pin is shorted to GND.

any advice / help would be great!
thank you guys,

- Eric

edit: i removed the code since it is irrelevant at the moment and so that other readers don't waste time in it
Last Edited: Tue. Jul 13, 2010 - 06:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

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

External push buttons or mechanical switches of any kind require debouncing in software or hardware for proper operation. It might also be possible your switch transfers an electrostatic discharge (ESD) from you into the INT0 pin and triggers it without any proper mechanical switch closing. If you have an ESD problem it could possibly damage the AVR chip and it needs protection hardware to suppress the ESD before it gets to the AVR.

Search the forums for switch bounce and ESD to get more information.

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

Does the switch have some metallic enclosure that you can connect to your powersupply ground (via a separate path from the one that the AVR uses)? That can act as a small-scale lightning rod to divert the charge from your finger into ground rather than let it capacitively couple into the switch contacts themselves.

Some switches (of the bare "oilcan contact" type actually have the operator touch one of their contacts directly. If you're using that kind of switch, make sure that you wire it so that the contact the operator touches is the one that gets connected to a low-impedance powersupply.

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

Suggest you also search "danni lee debounce" to get two elegant solutions to the button debouncing problem. The essence of it is to run a timer interrupt and only flag a stable change of button state after it's been seen to be stable in one state for several 10's of ms

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

thanks everyone, i suspected it was a 'debouncing' issue but i've never dealt with this before. So i've been going through ganssle's thorough analysis, other webpages, 2 versions of danni's debouncing software, and i have decided to use one of this last versions found at
[url]
https://www.avrfreaks.net/index.p...
[/url]
but with an atmega64, and with only 2 keys (not 8 as in danni's). I need to use pins 25 (INT0/PD0) and 26 (INT1/PD1). The other 6 pins in portD are being used to drive an LCD. Should i use 2 different ISRs - TIMER0_OVF_vect and TIMER1_OVF_vect - ? or could it be done in the same one? the problem is that if i do use only one ISR,
i = key_state ^ ~KEY_INPUT;
i'll be modifying / affecting the other pins in portD used to drive the LCD...

either way, do i need to call get_key_press (or in the case of 2 ISRs, get_key_press_0 & get_key_press_1) every cycle of the main while loop? the code is shown below

/************************************************************************ 
;*				---- MODIFIED ----                                                    * 
;*              Testing Read and debounce up to 8 keys                  * 
;*              Bulletproof: 4 equal samples needed                     * 
;*                                                                      * 
;*              Author: P. Dannegger                                    * 
;*                      danni@specs.de                                  * 
;*                                                                      * 
;***********************************************************************/ 
//https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=33821&highlight=dannegger+debounce

// Danni's debounce version MODIFIED

#include 
#include 
#include 

#define KEY_INPUT       PIND	/* PINx - register for button input */
#define KEY_BIT_0		PD0     /* bit for button input/output */
#define KEY_BIT_1		PD1     /* bit for button input/output */
#define LED_OUTPUT      PORTB 
#define LED_DIR         DDRB 

char key_state_0, key_state_1;			// debounced and inverted key state: 
                                        // bit = 1: key pressed 
char key_press_0, key_press_1;			// key press detect 

/************************************************************************************************/

ISR(TIMER0_OVF_vect)					//INT0_vect		//SIGNAL (SIG_OVERFLOW0) 
{ 
  static char ct0, ct1; 
  char i; 
// INSTEAD OF KEY_INPUT, check key changed in PD0
 // i = key_state ^ ~KEY_INPUT;			// key changed ? 
	i = key_state_0 ^ ~KEY_BIT_0;
	ct0 = ~( ct0 & i );					// reset or count ct0 
	ct1 = ct0 ^ (ct1 & i);				// reset or count ct1 
	i &= ct0 & ct1;						// count until roll over ? 
	key_state_0 ^= i;					// then toggle debounced state 
										// now debouncing finished 
	key_press_0 |= key_state_0 & i;		// 0->1: key press detect 
} 
/************************************************************************************************/

ISR(TIMER1_OVF_vect)					//INT0_vect		//SIGNAL (SIG_OVERFLOW0) 
{ 
  static char ct0, ct1; 
  char i; 
// INSTEAD OF KEY_INPUT, check key changed in PD1
  i = key_state_1 ^ ~KEY_BIT_1;			// key changed ? 
  ct0 = ~( ct0 & i );					// reset or count ct0 
  ct1 = ct0 ^ (ct1 & i);				// reset or count ct1 
  i &= ct0 & ct1;						// count until roll over ? 
  key_state_1 ^= i;						// then toggle debounced state 
										// now debouncing finished 
  key_press_1 |= key_state_1 & i;		// 0->1: key press detect 
} 
/************************************************************************************************/

char get_key_press_0( char key_mask ) 
{ 
  cli(); 
  key_mask &= key_press_0;				// read key(s) 
  key_press_0 ^= key_mask;				// clear key(s) 
  sei(); 
  return key_mask; 
} 
/************************************************************************************************/

char get_key_press_1( char key_mask ) 
{ 
  cli(); 
  key_mask &= key_press_1;				// read key(s) 
  key_press_1 ^= key_mask;				// clear key(s) 
  sei(); 
  return key_mask; 
} 
/************************************************************************************************/

int main( void ) 
{ 
  	key_state_0 = 0;	key_state_1 = 0;
	key_press_0 = 0;	key_press_1 = 0;

	TCCR0 = 1<<CS02;                      //divide by 256 * 256 
	TIMSK = 1<<TOIE0;                     //enable timer interrupt 

	LED_DIR = 0xFF; 
	LED_OUTPUT = 0xFF; 
	sei(); 
	for(;;)										// main loop 
	LED_OUTPUT ^= get_key_press_0( 0xFF );		// toggle LEDs on key press 
	LED_OUTPUT ^= get_key_press_1( 0xFF );
} 

Wouldn't it be more convenient to use ISR(INT0_vect) instead of calling get_key_press every cycle of the while loop? maybe sthing like this

#define BUTTON_PORT PORTD       /* PORTx - register for button output */
#define BUTTON_PIN PIND         /* PINx - register for button input */
#define BUTTON_BIT PD0          /* bit for button input/output */

ISR(INT0_vect)	
{checkPinState();}
void checkPinState(void)
{
	/* the button is pressed when BUTTON_BIT is clear */
	if (bit_is_clear(BUTTON_PIN, BUTTON_BIT)) 
	{
		_delay_ms(25); // or check several times instead of the delay..?
		if (bit_is_clear(BUTTON_PIN, BUTTON_BIT)) 
		{	DebouncedButtonPushed = true;	}
		else 
		{	DebouncedButtonPushed = false;	}
	}	
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

schamton wrote:
with only 2 keys (not 8 as in danni's). I need to use pins 25 (INT0/PD0) and 26 (INT1/PD1).
Yeah, so?
schamton wrote:
The other 6 pins in portD are being used to drive an LCD.
Danni's code is set up to handle an entire port for input, with masking bits to "remove" pins that are used for something else. You should only need one ISR to run the whole show, since the code is essentially using the interrupt to "poll" the status of the inputs.
schamton wrote:
Should i use 2 different ISRs - TIMER0_OVF_vect and TIMER1_OVF_vect - ? or could it be done in the same one?
Strictly speaking, you don't need any ISRs whatsoever. You could just poll the pins. The AVR works much faster than any human/robot can push a mechanical switch.

In this case, just one timer is needed. The code should keep track of the state of all pins under its control.

schamton wrote:
Wouldn't it be more convenient to use ISR(INT0_vect) instead of calling get_key_press every cycle of the while loop? maybe something like this
No. Absolutely, positively NO.

Really, don't even think about putting a mechanical switch on an interrupt. The transitions on the line are fast enough that the processor can collect dozens, if not hundreds, of interrupts in the few milliseconds of transition. On both transitions (off->on and on->off). That means the AVR is busy servicing those interrupts and not doing work that you would like it to be doing. Also, it is likely getting completely confused.

Granted, I have (in desperate cases) tied a "bouncy" signal to an interrupt. What I did in the interrupt ISR was mark that I saw the transition, turned off the interrupt, then set a timer for the debounce period. When the timer expired, I looked at the state of the pin that "changed", and if it was still "changed", I reported the new pin state. On the whole, though, this was clumsy and would not handle multiple "bouncy" signals gracefully.

You should never report the state of a "bouncy" signal until you have assured yourself that it really has changed, and that it is stable (for some value of stable). Otherwise, you end up with your original problem.

The only case where I would recommend putting a mechanical switch on an interrupt is if the switch has hardware debouncing on it already (most likely as a one-shot or "armed" flip-flop, but there are other methods). In this case, the switch is not directly connected top the INTx pin but is filtered through the hardware. So, strictly speaking, I have debounced the signal, and again the mechanical switch is not tied to the interrupt.

Get away from the idea that a mechanical switch is "fast". It isn't. And because of that, get away from the idea of using interrupts. They are meant for far faster (and predictable) signals.

Stu

Edit: PS: Putting delays in an ISR is the dumbest thing you can possibly do. ISRs should be fast. Best case, they should collect a byte (or set a byte), set a flag that it did something, then return.

Calling functions in ISRs, while occasionally necessary, should be avoided if possible.

Try reading:

[TUT] Newbie's Guide to AVR Interrupts
[TUT][SOFT] The traps when using interrupts

These pointers can be found (along with lots of others) in Newbie? Start here!

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

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

Quote:
Putting delays in an ISR is the dumbest thing you can possibly do

Sounds like a challenge to me. Shall we have a competition? :wink:

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

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

thank you Stu,

i do know it's in general a bad design to call a function from within an ISR or to put a delay in it, it's just the example i could think of for implementing the ISR(INT0_vect)...

I wasn't sure if the pins used for the LCD would be affected by the line
i = key_state ^ ~KEY_INPUT;
that is, to NOT and XOR all pins in portD, but if, as you mentioned, masking bits would "remove" pins that are used for something else, then great.

So i am now using only one ISR, just as in Danni's original code, i have connected 5 LEDs to portB, PB0 - PB4, and i have a push button connected to PD0/INT0. When i flash the atmega64, all 5 LEDs are turned on (all portB is high) but nothing happens when i press the button. Shouldn't PB0 go low?

the code i'm working with is shown below

#include 
#include 
//#include 

#define KEY_INPUT       PIND	/* PINx - register for button input */
#define LED_OUTPUT      PORTB 
#define LED_DIR         DDRB 

char key_state;							// debounced and inverted key state: 
										// bit = 1: key pressed 
char key_press;							// key press detect 

/************************************************************************************************/

ISR(TIMER0_OVF_vect)					//INT0_vect		//SIGNAL (SIG_OVERFLOW0) 
{ 
  static char ct0, ct1; 
  char i; 

	i = key_state ^ ~KEY_INPUT;			// key changed ? 
	ct0 = ~( ct0 & i );					// reset or count ct0 
	ct1 = ct0 ^ (ct1 & i);				// reset or count ct1 
	i &= ct0 & ct1;						// count until roll over ? 
	key_state ^= i;						// then toggle debounced state 
										// now debouncing finished 
	key_press |= key_state & i;			// 0->1: key press detect 
} 
/************************************************************************************************/

char get_key_press( char key_mask ) 
{ 
  cli(); 
  key_mask &= key_press;				// read key(s) 
  key_press ^= key_mask;				// clear key(s) 
  sei(); 
  return key_mask; 
} 
/************************************************************************************************/

int main( void ) 
{ 
  	key_state = 0;	
	key_press = 0;	

	TCCR0 = 1<<CS02;                      //divide by 256 * 256 
	TIMSK = 1<<TOIE0;                     //enable timer interrupt 

	LED_DIR = 0xFF; 
	LED_OUTPUT = 0xFF; 
	sei(); 
	for(;;)										// main loop 
		LED_OUTPUT ^= get_key_press( 0xFF );	// toggle LEDs on key press 
} 

Thank you :)
- Eric

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

i went through all the bit manipulation in the code, but i can't figure out why nothing happens when i press the push button connected to INT0/PD0. Any ideas?
Thank you!
- Eric

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

The example debounce 8 keys and toggle 8 LEDs.

If you want a certain action on a single key:

#define KEY0 0
#define LED0 1
...
   for(;;){                              // main loop
      if( get_key_press( 1<<KEY0 ))
         LED_OUTPUT ^= 1<<LED0;
...
   }

You get the press event only. If you want the release event also, it can be expanded easily.

The keys are low active, because then the internal pullups can be used to get high level, if the key was released.

Peter

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

thank you Peter. I added the code as you mentioned, but with

#define KEY0 PD0 
#define LED0 PB0  

as i think it should be in my case, and replaced the line

//LED_OUTPUT ^= get_key_press( 0xFF );

by the if statement. It kind of works, but very irregularly, the LED is not really responsive to the pin, and it flickers a lot at the push/release of the button. Sometimes it even turns on/off without even pressing it.

Does this code account for any EMI from our own finger?

edit: I went through all the bit manipulations in the ISR but i'm not really sure what's going on in there. Is the code somehow considering approx 12-25ms for the normal bounce time of a push button release?

Last Edited: Wed. Jul 14, 2010 - 08:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

zbaird wrote:
Quote:
Putting delays in an ISR is the dumbest thing you can possibly do

Sounds like a challenge to me. Shall we have a competition? :wink:

I suggest doing a jump (eg by setjmp/longjmp) from inside the ISR to some place in the main loop is dumberer [spelling intended].

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

I would have thought a while(1) in the ISR is all it really takes to REALLY mess things up?

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

Quote:
The keys are low active, because then the internal pullups can be used to get high level, if the key was released.

what would you change in the above code to have high active keys (no internal pullups) - just have PD0 shorted normally to gnd, and when you press a button pull PD0 high through a 4.7k resistor to 5V?

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

clawson wrote:
I would have thought a while(1) in the ISR is all it really takes to REALLY mess things up?
If you re-enable interrupts before the loop ...

Stealing Proteus doesn't make you an engineer.

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

Quote:
...to REALLY mess things up

And here I thought it was something simple like saying AVRs are nice chips while Leon is awake.

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

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

Quote:
what would you change in the above code to have high active keys

If the question is "The code above assumes active-low switches, I have active high switches. What do I need to change?". With that interpretation change

~KEY_INPUT

to

KEY_INPUT

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

thanks Johan : )
the LED at PB0 does turn off when pushing the button in PD0 (yes, i have an active high switch) but it flickers significantly when touching the button without even pressing it... maybe the radioshack push button just sucks...

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

I would interchange the switch terminals. I will bet that there is a "large" metallic frame that is connected to your port pin. Connect this terminal to either Vcc or ground and connect the other terminal to the port pin.

Another way of dealing with this is to add a capacitor from the port pin to Vcc or ground (usually ground). A 10nf (0.01uf) should work.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

Thank you Jim, i interchanged the switch terminals but the issue continues. I have created a new thread as i have found the original 'efficient key debounce' project posted by Peter / danni. If anyone could take a look at it, i'll greatly appreciate it
https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=724358#724358
thanks,
- Eric