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;
}
}
}