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.
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.
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".
;; 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
Post a Comment