Here's a contribution for managing up to 8 switches, not necessarily in a single port. Heavily commented. This should be called as part of a main program loop once per iteration. There is code to evaluate whether the switch is switched to ground or Vcc. Just comment out the part you don't need. Similarly, there are examples for applying a switch from any pin to fill out a single byte for parallel processing. It is dependent on a 4ms ISR for the delay counter. You can alter the ISR speed and compensate by altering the bit being evaluated for the ISR delay time counter held in GPR , 'Dbouncecount'. Just try to have the overall time within 20% of the times used here.
Keypad; Evaluate keypresses for click, hold (long press) , open with debounce & transition states. Works in parallel for up to 8 switches. Requires a 4 (can use others) ms tick (usually done in an ISR) for 'Dbouncecount'. ;Setup for Key_0 , in bit 0; this method allows any pin in any port to be a key /switch as the keys are mapped to a single 8bit byte here. 'Tmp' is a locally valid temp variable for general subroutine use. ; The Transition bytes are set if a new debounced keystate just happened . These are cleared on each iteration. ;Each of the 8 Transition bits in the bytes (Keytrans and HoldTrans) allow for debounced edge triggering events. eg. If the DbKeystate,0 is hi and the Keytrans,0 is high then the debounced key0 press leading edge just happened. ;If DbKeystate is Hi and Keytrans,0 is lo, then the debounced Keypress is mature. ;If the DbKeystate,0 is lo and the KeyTrans,0 is hi then the debounced key was just released - trailing edge. Stored in "Shortpress' GPR; Just do a bit check on this byte for any of the 8 switches' shortpress condition. ; A similar structure applies to HoldTrans and HoldKeystate bytes as applies to a 'long key hold/click' operation - holding down a key for a 1/2 second. Stored in 'Longpress' byte. Just do a bit check on this byte for any of the 8 switches' longpress condition. ; Thus a single key can deliver up to 4 states, leading and trailing edge for both short clicks and long clicks. ; The use of the leading edge transitions is manifest when preventing 'repeating' a routine that responds to the key condition.eg. only respond to a keypress if the transition bit is also set, like make a beep. ;The leading edge can also keep track of which key to respond to if multiple keys are pressed simultaneously. ; eg. The trailing transition can be used for triggering an acknowledgement after the key is released. clrf Sw_state ;clear switch state byte for evaluation below. clrf KeyTrans ;limit all transitions to one complete program loop. clrf HoldTrans; " " ;btfsc GPIO,3 ; Key0 = pin physical location. Btfsc used when key is pulled hi when closed. btfss GPIO,3; Key0 = pin physical location. Btfss used when key is pulled low when closed bsf Sw_state,0 ; match Sw_state bit 0 to Key state, 1= closed, 0=open. ;Setup for Key_1 , in bit 1 ;btfsc PORTA,6 ; Key1 pin. = PORTA,6 ;bsf Sw_state,1 ; match Sw_state bit 1 to Key state, 1= closed, 0=open. ;Setup for Key_7 , in bit 7 ;btfsc PORTB,2 ; Key7 pin. = PORTB,2 ;bsf Sw_state,7 ; match Sw_state bit 7 to Key state, 1= closed, 0=open. movf Sw_state,w ; get newstate eg. Sw0,2 closed 0101 xorwf LastKeystate,w ; state changes eg. 1100 => 1001 xorwf LastKeystate,f ; make Laststate =Newstate. 1100=> 0101 andlw b'11111111'; test wreg if any bits changed btfss STATUS,Z; skip zero set, else (statechange) clrf Dbouncecount; reset counter (counts every 4 msec in ISR) btfss Dbouncecount,2 ; skip if bit 2 set=> 16ms passed, else goto Testkeyhold; movf LastKeystate,w; 0101 xorwf DbKeystate,w; get changes bet. current state and debounced state. 0110 => 0011 movwf KeyTrans; save in transition byte. 0011 (transition bits) xorwf DbKeystate,f; apply them to DB state 0110 => 0101 movf DbKeystate,w xorlw .255; test for key release (open) andwf KeyTrans,w; verify transition of key release. movwf Shortpress; update shortpress status, based on click/release. Testkeyhold movf DbKeystate,w ; 0101 andwf HoldKeystate,w ;zero Hold bits if matching key is released - wreg. 0011 => 0001 xorwf HoldKeystate,w ; get Transition from Hold to release 0011 => 0010 movwf HoldTrans; update HoldTransition byte. 0010 xorwf KeyTrans,f ; toggle any matching release from clicks off, release from hold priority. xorwf HoldKeystate,f ; now immediately switch off Hold if a key is released - file. 0011 => 0001 xorwf DbKeystate,w ; get newly pressed keys to test for hold.(state change) 0101 => 0100 btfss STATUS,Z; skip if no new key pressed, else Testforholdcount ; test if timer expired btfss Dbouncecount,7 ; 128*4ms = 512ms goto Keydone movf DbKeystate,w; 0101 xorwf HoldKeystate,w ; get statechanges 0001 => 0100 iorwf HoldTrans,f; update hold transition byte. 0010 => 0110 (transition bits) ;using what's still in wreg to apply changes 0100 xorwf HoldKeystate,f;apply changes 0001 => 0101 movf HoldKeystate,w andwf HoldTrans,w; verify transition of key movwf Longpress; update Longpress status. Keydone return