Oznog,
I've discovered and developed some relatively simple and reliable methods for debouncing and managing multiple switches over the last few years. Would you mind if I share them with you?
First, I use relatively simple
switch state latch logic for managing one to eight switches (in parallel). Using a switch state latch allows you to process and act on a "new" debounced switch press or a "new" debounced switch release while ignoring the remaining portion of a switch cycle (how long the switch is pressed or released).
Code:
;
SWKEYS equ 0x20 ; debounced switch bits, '1' = pressed
SLATCH equ 0x21 ; switch state latch
SWITCH equ 0x22 ; switch flag bits for MAIN
;
; this routine transfers a new debounced switch press to the SWITCH
; variable for MAIN
;
ISR_Switch_Press
movf SWKEYS,W ; debounced switch bits
xorwf SLATCH,W ; each '1' is a change (press or release)
andwf SWKEYS,W ; each '1' is a "new" switch press
xorwf SWITCH,F ; toggle switch flag bits for use by MAIN
movf SWKEYS,W ; update switch state latch
movwf SLATCH ;
;
; this routine transfers a new debounced switch release to the SWITCH
; variable for MAIN
;
ISR_Switch_Release
movf SWKEYS,W ; debounced switch bits
xorwf SLATCH,W ; each '1' is a change (press or release)
andwf SLATCH,W ; each '1' is a "new" switch release
xorwf SWITCH,F ; toggle switch flag bits for use by MAIN
movf SWKEYS,W ; update switch state latch
movwf SLATCH ;
There are several different ways your MAIN program can process a switch press flag bit in the SWITCH variable (or a switch release flag bit if you're using the "release" algorithm). Let's say we've defined a switch called "sw_UP" as bit 0 in the SWITCH variable. Here's one way you might process that switch in MAIN;
Code:
;
; test "UP" switch
;
Test_UP btfss sw_UP ; is SWITCH,0 a '1' (new switch press)?
goto Test_DOWN ; no, branch, else
bcf sw_UP ; clear bit so we don't process again
; perform "UP" code here
;
The previous example is for
momentary type switch functions where we press a switch, perform some function, and we're done. We clear the flag bit after we test it and it won't get set again until the user releases the switch and presses it again.
We can also use our standard momentary push button switches to emulate
toggle switches. That is, press a switch to toggle the switch flag bit from on-to-off or from off-to-on. This is extremely handy for lighted push button switches. Push it once to light the LED then push it again to toggle the LED off. In this case the only difference in the way you process the switch in MAIN is that you don't need to clear the switch flag bit after testing it. It gets toggled automatically in the ISR after each "new" press.
Code:
;
; test SET mode toggle switch flag
;
SET btfss sw_SET ; is SWITCH,1 a '1' (SET mode on)?
goto NextProc ; no, branch, else
;
; perform SET functions in SET_loop
;
SET_loop
;
; has SET mode been turned off
;
btfsc sw_SET ; SET switch still on?
goto SET_loop ; yes, continue SET operations, else
;
; save any changes and exit
;
And if I haven't bored you to death, here's one last extremely simple addition to that ISR code that provides us with a switch press beep. The additional code sends a short 32 msec 500 Hz beep when it detects "new" switch press bits in W.
Code:
;
SWKEYS equ 0x20 ; debounced switch bits, '1' = pressed
SLATCH equ 0x21 ; switch state latch
SWITCH equ 0x22 ; switch flag bits for MAIN
BEEP equ 0x23 ; beep timer
;
; process "new" debounced switch "presses"
;
ISR_Switch_Press
movf SWKEYS,W ; debounced switch bits
xorwf SLATCH,W ; each '1' is a change (press or release)
andwf SWKEYS,W ; each '1' is a "new" switch press
;
skpz ; any "new" presses? no, skip, else
bsf BEEP,5 ; send short 32-msec 500-Hz "beep"
;
xorwf SWITCH,F ; toggle switch flag bits for use by MAIN
movf SWKEYS,W ; update switch state latch
movwf SLATCH ;
;
; BEEP routine (500-Hz when using 1 msec interrupts)
;
movf BEEP,W ; beep timer set?
bz ISR_Next ; no, branch, else
movf PORTA,W ;
xorlw 1<<SPKR ; toggle SPKR port bit in W
movwf PORTA ; toggle actual SPKR pin
decf BEEP,F ; decrement beep timer
;
ISR_Next
Not bad for 15 words, yes, no?
The important thing to note about this code and method is that it simply tests the switches during each 1 msec interrupt and doesn't tie up the processor unnecessarily by waiting for a switch to change state.
I've also developed some similarly "tight" code for implementing multiple independant debounce timers (which work on both press and release), repeat timers, etc., but they use vertical counters which seems completely alien to most people so I won't impose those algorithms on you folks at this time (grin).
Regards, Mike