Debouncing signal (switches)

This is my ISR responding to a switch press on digital pin 2 of the Arduino. I’m assuming my Makerduino is operating @ 16 MHz, so this algo takes 0.9µ seconds.

  Btn:	  push	    r20			; Preserve current contents
	  in	    r20, SREG
	  push	    r20			; Preserve current status register
	  push	    r19			; and only other register used by ISR

	  in	    r20, PORTD
	  ldi	    r19, (1 << PD7)
	  eor	    r20, r19
	  out	    PORTD, r20

   ; *** Debounce code here

	  pop	    r19
	  pop	    r20
	  out	    SREG, r20
	  pop	    r20
	  reti

Tests have demonstrated this routine works 12 out of 15 times and only when I’m not really definitive with my press or release is there undesired results using this switch. This leads me to think a delay of 500µ would work inside the ISR.

Alternately, set a global variable that represents the number of nano seconds to delay and attach a delay to TIMER0 that has the appropriate duration between events. This would mean, disable INT0 in ISR and re-enable it in TIMER0 when count has elapsed.

(1) Is my thinking correct that no matter what is done in hardware, software should have some kind of debouncing mechanism.

(2) A delay outside the ISR is the only viable option, as the code becomes more complex servicing more handlers, any delay could lead to undesirable problems.

(deleted)

If you use mechanical (SPST) contacts, debouncing is required. This is typically done in loop(), by polling the contact.

What do you want to achieve, by using interrupts and assembly for really simple tasks, like checking a switch?

(1) Is my thinking correct that no matter what is done in hardware, software should have some kind of debouncing mechanism.

It depends on the project requirements. What if the hardware normally produces a clean signal, but the application needs to know when the hardware begins to fail ... then any debouncing would prevent this detection. You might find this interesting: Debouncing, hardware and software, part 2

Are you trying to achieve the quickest response possible to the first edge of any signal that has some noise (or bounce)?

DrDiettrich:
What do you want to achieve, by using interrupts and assembly for really simple tasks, like checking a switch?

Primarily, this is a learning experience into AVR architecture and although these snippets are not particularly useful in and of themselves, they do lead to insight. Case in point, this following modification eliminates what is a problem in the previous code by simply writing to the LED the inverse of INT0.

 Btn:	  push	    r20
	  in	    r20, SREG
	  push	    r20			; Preserve stack pointer

	  sbis	    PIND, 2
	  rjmp	    LED_Off
	  sbi	    PORTD, PIND7
	  rjmp	    LED_Off + 1	  	      
LED_Off:  cbi	    PORTD, PIND7
	  
	  pop	    r20			; Restore stack pointer
	  out	    SREG, r20
	  pop	    r20
	  reti

I prefer assembly because of its WYSIWYG nature and I did emulate this algorithm using Arduino IDE in "C" with a resultant size of 1,280 bytes. This code is 170 bytes. I don't intend this to be a flame toward "C" or "C++", but the proof is in the pudding and when confronted with limited space, a tight design is imperative.

dlloyd:
Are you trying to achieve the quickest response possible to the first edge of any signal that has some noise (or bounce)?

Ultimately, that is the goal to design ISR's to be as responsive as possible. I only started 6 days ago with my Makerduino Uno 3, but fundamentally there are a lot of similarities with IA32. Hopefully my experimentation and insight from others will pave the road to near bullet proof designs.

Thanks for the link to the guide to debouncing

An output pin can be toggled quickly by writing a 1 to its PIN register.
sbi PIND, PIND7
IMO is sufficient, but I'm not an assembly expert.

DrDiettrich:
An output pin can be toggled quickly by writing a 1 to its PIN register.
sbi PIND, PIND7
IMO is sufficient, but I'm not an assembly expert.

That was my thinking in the beginning, but as it turns out, any data written to a port is done through PORTx. If the PIN is set to input then writing to the port simply toggles PULL-UP or PULL-DOWN.

If a port is set to output:
pinMode (2, OUTPUT);
then
PIND = PIND | 0b00000100;
will toggle the output pin.
"Three I/O memory address locations are allocated for each port, one each for the Data Register – PORTx, Data

Direction Register – DDRx, and the Port Input Pins – PINx. The Port Input Pins I/O location is read only, while

the Data Register and the Data Direction Register are read/write. However, writing a logic one to a bit in the

PINx Register, will result in a toggle in the corresponding bit in the Data Register. In addition, the Pull-up Disable

– PUD bit in MCUCR disables the pull-up function for all pins in all ports when set."

Section 14 of the datasheet.

CrossRoads:
PIND = PIND | 0b00000100;
will toggle the output pin.

Interestingly, changing this to address PIN rather than PORT created some very unpredictable results. Within a couple of button presses, the logic was inverted or sometimes didn’t respond at all.

		sbi    PIND, PIND7
		rjmp    LED_Off + 1        
LED_Off:  	cbi    PIND, PIND7

The complier however will do this when addressing the PIN register

	PIND = (1 << PIND0) | (1 << PIND1);
  a6:	83 e0       	ldi	r24, 0x03	; 3
  a8:	89 b9       	out	0x09, r24	; 9

Even the example on page 79 of the datasheet (section 14) uses IN & OUT, but the difference is, several pins are being changed at one time which would save space.