PIC Microcontroler based Keyboard

Mike McLaren's 'debounce', 'beep', and 'toggle' using vertical counters in C18

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