Here's a C18 vertical counter "debounce" & "beep" code example.
Like the assembler version, this example code uses 1.0-msec Timer 2 interrupts, eight independent 2-bit vertical counters, and 'glue' code to debounce up to 8 switches in parallel. A switch is "debounced" or "filtered" after it's sampled four times at the same level spanning a 24.0-msec period. The vertical counters for any particular switch are reset when the switch bounces or changes state.
Your MAIN program code should test and clear a SWITCH flag bit for normal "momentary" push button switches and should simply test a SWITCH flag bit for switches that emulate a "toggle" switch. I use "toggle" switch emulation for lighted push button switches (push to toggle the SWITCH flag bit from off-to-on or from on-to-off).
/***************************************************************** * function prototypes * *****************************************************************/ void isr_hi (void); /***************************************************************** * variables * *****************************************************************/ unsigned char SWKEYS = 0; // live switch press bits unsigned char SLATCH = 0; // debounced switch latch unsigned char VCBIT0 = 0; // vertical counter bit 0 unsigned char VCBIT1 = 0; // vertical counter bit 1 unsigned char VCMASK = 0; // 'cumulative AND' mask unsigned char SWITCH = 0; // switch flags for MAIN unsigned char COLPOS = 1; // ring counter prescaler unsigned char VCTEMP = 0; // unsigned char BEEPER = 0; // beep timer /***************************************************************** * setup interrupt vectors * *****************************************************************/ #pragma code high_interrupt = 0x08 void high_interrupt (void) { _asm goto isr_hi _endasm } #pragma code /***************************************************************** * ISR (high) * *****************************************************************/ #pragma interrupt isr_hi /***************************************************************** * * * Mike McLaren's "debounce", "beep", and "toggle" example ISR * * code based on vertical counter concepts 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 * * * * a switch is debounced or filtered after sampling it at the * * same level through 4 vertical counts spanning 24.0-msecs * * * * this code is executed each 1.0-msec interrupt cycle * * */ void isr_hi () { if (PIR1bits.TMR2IF == 1) // Timer 2 interrupt? { PIR1bits.TMR2IF = 0; // yes, clear interrupt flag /* * * this is where you would set the SWKEYS variable with live * * switch press data from your switch input pins or scanned * * switch matrix. A '1' bit represents a pressed switch. * * */ SWKEYS = PORTB ^ 0xFF; /* * * Clear vertical counters for bouncing/inactive switches * * */ VCMASK = SWKEYS ^ SLATCH; VCBIT0 &= VCMASK; VCBIT1 &= VCMASK; VCMASK &= COLPOS; // apply 8-msec prescaler /* * * each '1' in the SLATCH variable represents a "debounced" * * 24.0-msec switch press (bit cleared when switch released) * * */ SLATCH ^= (VCTEMP = VCMASK & VCBIT0 & VCBIT1); /* * * toggle SWITCH variable flag bits for processing by MAIN * * */ if (VCTEMP &= SWKEYS) // if new debounced switch press { SWITCH ^= VCTEMP; // update SWITCH variable BEEPER = 32; // and send 32-msec "beep" } /* * * increment vertical counters for the active switches * * */ VCBIT1 ^= (VCMASK & VCBIT0); VCBIT0 ^= (VCMASK); /* * * beep (500-Hz tone with 1.0-msec interrupts) * * */ if (BEEPER) // is beep timer set? { LATA ^= 0b00000100; // toggle piezo speaker pin BEEPER--; // decrement beep timer } /* * * advance ring counter prescaler for next interrupt cycle * * */ if (!(COLPOS *= 2)) { COLPOS = 1; } } }