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 Couter.

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”.

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: