Compressing the PIC debounce example code

The code from the PIC switch debounce example is shown below. One odd thing is that the LastStableState variable uses 1 to indicate the last stable state was "switch down", which reads as a low (zero) on the input port. I added some pseudo-C comments in my efforts to make sure I understand the code.

;; LSS = 1 ;; actually, this means the switch was stable at 0
movlw     1
movwf     LastStableState     ; Assume the Switch is down. [not up as original comment]
;; counter = 0
clrf      Counter

MainLoop:
btfsc     LastStableState,0
goto      LookingForUp

;; note redundant CLRW here: could have put before btfsc LSS,0
;; LSS is 0
;; switch was stable with 1: if current_state != 1 counter++ else counter = 0
LookingForDown:
clrw                          ; assume it's not, so clear
btfss     PORTA,3             ; wait for switch to go low
incf      Counter,w           ; if it's low, bump the counter
movwf     Counter             ; store either the 0 or incremented value
goto      EndDebounce

;; lss is 1:
;;  switch was stable with 0: if current_state != 0 counter++ else counter = 0

LookingForUp:
clrw                          ; assume it's not, so clear
btfsc     PORTA,3             ; wait for switch to go low
incf      Counter,w
movwf     Counter

;; note redundancy here: incf Counter,w puts result in W
;; movwf Counter puts W --> counter
;; movf Counter,w brings same value back into W
EndDebounce:
movf      Counter,w           ; have we seen 10 in a row?
xorlw     5
btfss     STATUS,Z
goto      Delay1mS

;; if counter = 5
;;   lss = !lss
;;   counter = 0
;;   if "active" take action
;;

comf      LastStableState,f   ; after 10 straight, reverse the direction
clrf      Counter
btfss     LastStableState,0   ; Was it a key-down press?
goto      Delay1mS            ; no: take no action

[button-down action here]

Delay1ms:
[delay loop here]

goto MainLoop


This version takes 23 instructions plus the length of the "down action" routine, plus the length of the delay loop.

I came up with a slightly more compact version; in the process, to keep my sanity, I reversed the LastStableState convention, so LSS = 1 meant the switch was last stable in the up position.

;; LSS = 1
movlw     1
movwf     LastStableState     ; Assume the Switch is up.
;; counter = 0
clrf      Counter
MainLoop:
clrw ; need w=0 for counter calculation
btfsc     LastStableState,0
goto      LookingForDown
LookingForUp:
;; lss is 0: if current_state != 0 w=counter++ else counter = 0
;; i.e. if porta,3 is CLEAR skip the increment
btfsc     PORTA,3
incf      Counter,w           ; if it's SET, w = counter+1
goto      EndDebounce
LookingForDown:
;; lss is 1: if current_state != 1 w=counter++ else counter = 0
;; i.e., if porta,3 is SET skip the increment
btfss     PORTA,3
incf      Counter,w           ; if switch low, w = counter+1
EndDebounce:
movwf     Counter  ; store either 0 or incremented value
;; W==counter, either 0 or incremented
xorlw     5
btfss     STATUS,Z
goto      Delay1mS

;;  zero flag was set: means W==5
;; if counter = 5
;;   lss = !lss
;;   counter = 0
;;   if "active" take action
;;
switch_happened:
comf      LastStableState,f   ; after 5 straight, reverse the direction
clrf      Counter
btfsc     LastStableState,0   ; Was it a key-down press?
goto      Delay1mS            ; no: take no action

[down button action here]

Delay1ms:
[delay routine here]
goto MainLoop

This code comes to 20 instructions plus the "down action" and "delay" routine lengths. I still have a vague feeling that I could save another instruction by changing the LSS convention back, and using CLRF LastStableState to initialize it. Perhaps there is an opportunity to simplify the "clrw, conditionally increment counter into W, store W back into counter, test W" by using a different "count up/down to zero" convention, and a inc/decfsz counter. However, that would expand the clrf counter line to movlw initialcount + movwf Counter.

I'm still getting used to the rather limited conditional branching when reading---I keep thinking the branches go far away, past an "else clause", instead of simply missing one instruction that changes the "then" into the "else".

Comments

Popular posts from this blog

Open Genera VLM on Linux

FPGA selection for beginners

Restoring the Heathkit Jr 35