This example ISR code features a switch press 'beep' function and supports standard "momentary" and "toggle" emulation switch types using standard normally-open push button switches. I often use "toggle" switch emulation for lighted switches (push to toggle from off-to-on and push to toggle from on-to-off).
;****************************************************************** ; ; Mike McLaren's "debounce" vertical counter example ISR code ; based on concepts/examples from Jonny Doin and Scott Dattalo ; ; <> process up to eight switches in parallel ; <> eight independent 24.0-msec "debounce" vertical counters ; <> debounced switch press audible feedback (beep or click) ; <> momentary switch operation (test then clear a SWITCH bit) ; <> toggle switch emulation (push to toggle a SWITCH bit from ; off-to-on or from on-to-off) perfect for lighted switches ; ; 27 words/27 cycles (14-bit core), or ; 18 words/18 cycles without switch press beep code ; ; setup the SWKEYS variable with "live" switch press data from ; your switch input pins or your scanned switch matrix before ; falling into this routine. A '1' bit represents a 'pressed' ; switch and a '0' bit represents a 'released' switch. ; ; execute this code each 1.0-msec interrupt cycle ; ; ; clear vertical counters for bouncing and steady-state switches ; ISR_Sw movf SWKEYS,W ; live switch press data |B0 xorwf SLATCH,W ; debounced pressed switch latch |B0 andwf VCBIT0,f ; |B0 andwf VCBIT1,f ; |B0 ; ; cyclic vertical counter algorithm. vcmask is seeded with the ; active switch mask and bn' is the previous state of bn before ; the bit increment operation. ; ; a switch is debounced or filtered after sampling it at the ; same level through four vertical counts spanning 24.0-msecs ; ; b0 ^= (vcmask) ; b1 ^= (vcmask & b0') ; b2 ^= (vcmask & b0' & b1') ; ; Mike McLaren's "cumulative AND" vertical counter method ; ; b0 ^= vcmask : vcmask &= bo' ; b1 ^= vcmask : vcmask &= b1' ; b2 ^= vcmask ; andwf COLPOS,W ; 8-msec 'column' prescaler |B0 movwf VCMASK ; seed "cumulative AND" mask |B0 xorwf VCBIT0,f ; b0 ^= vcmask |B0 xorwf VCBIT0,W ; restore b0' in W |B0 andwf VCMASK,W ; vcmask &= b0' |B0 movwf VCMASK ; |B0 xorwf VCBIT1,f ; b1 ^= vcmask |B0 xorwf VCBIT1,W ; restore b1' in W |B0 andwf VCMASK,W ; vcmask &= b1' |B0 ; ; each '1' bit in the SLATCH variable represents a "debounced" ; 24.0-msec switch press (bit cleared when switch is released) ; xorwf SLATCH,f ; update debounced state latch |B0 ; ; send a 32-msec short beep for new debounced switch presses ; andwf SWKEYS,W ; new debounced switch press? |B0 btfss STATUS,Z ; no, skip, else |B0 bsf BEEPER,5 ; send 32-msec short beep |B0 ; ; toggle SWITCH flag bits for processing by the MAIN program ; ; test SWITCH bits for emulated "toggle" switches. test then ; clear SWITCH bits for "momentary" switches. ; xorwf SWITCH,f ; toggle SWITCH bits for MAIN |B0 ; ; advance ring counter prescaler (initialized value = 00000001) ; for the next interrupt cycle ; rlf COLPOS,W ; advance column ring counter |B0 rlf COLPOS,f ; |B0 ; ; beep (500-Hz tone with 1.0-msec interrupts) ; movf BEEPER,W ; beep timer set? |B0 bz ISR_Next ; no, branch, else |B0 movf GPIO,W ; read port |B0 xorlw 1<<Speaker ; |B0 movwf GPIO ; toggle piezo speaker pin |B0 decf BEEPER,f ; decrement timer |B0 ; ISR_Next