cblock 0x20 ;or whatever your ram start is
total_pulses ; the number of pulses counted
current_state ; bit0 reflects the most recent sampled state
; bit1reflects the most recent filtered state
; bit2 indicates that the debounce filter is running
steady_state_counter ; keeps track of the number of consecutive steady
; state samples
endc
#define IOPORT PORTA
#define IOBIT 0
;;--------------------------------------------------------------
;; pulse_counter - count pulses on an I/O pin
;;
;; This routine counts the number of occurances of high pulses
;; on the IOBIT of IOPORT (defined above).
;;
;;
;; Must be called at a constant rate and at least 4 times faster
;; than the narrowest pulse expected.
;; For example, if the narrowest pulse expected is 10 ms then
;; this routine should be called at least once every 2.5 ms. 1ms
;; would be a good interval.
pulse_counter:
; Define the number of consecutive samples required to measure either
;a high or a low:
#define SAMPLES_FOR_STEADY_STATE 4
movlw 0 ;Sample the input
btfsc IOPORT,IOBIT
movlw 1
xorwf current_state,w ;compare to the previous sample
andlw 1 ;Clear upper bits of current sample
skpz ;If this sample is different than previous
goto detected_a_change ; then handle below
;; no change in last two samples
;If we're not filtering, then we can return.
;If we are filtering, but the steady state counter hasn't
;terminated, then we can also return
btfsc current_state,2
decfsz steady_state_counter,f
return
; We sampled `SAMPLES_FOR_STEADY_STATE' consecutive samples
bcf current_state,2 ;We're no longer filtering
rlf current_state,w ;Compare the current filtered state
xorwf current_state,w ;with the previous filtered state
andlw 2 ;Just look at the differences
xorwf current_state,f ;and save the current as the previous
andlw 2 ;again, look at the differences
skpz ;If there are no differences
btfss current_state,1 ;or the current filtered state is low
return ;then we found a low pulse
; We found a high pulse. Count it!
incf pulse_counter,f
; This would be a good place to check the pulse counter...
return
detected_a_change:
xorwf current_state,f ;save this sample for next time
movlw SAMPLES_FOR_STEADY_STATE ; Initialize the steady state counter
movwf steady_state_counter
bsf current_state,2 ; Set a flag so we know we're filtering
return
cblock
sample ; The most significant bit contains the most recently filtered
;state. The other bits contain the last N samples, where N is
;the filter width. (and N must be less than 8).
pulse_counter ; each time a pulse is discovered, this is incremented
endc
;--------------------------
; constants:
;
; Number of consecutive samples of the same state required to declare
;an input as filtered
#define STEADY_STATE_SAMPLES 4
; The FILTER_MASK is a constant with the least significant
;STEADY_STATE_SAMPLES bits set. e.g. if STEADY_STATE_SAMPLES is 4
;then the FILTER_MASK is (1<<4)-1 = 16-1 = 15 = 00001111b
#define FILTER_MASK ( (1 << STEADY_STATE_SAMPLES) - 1)
count_pulses:
clrc ;Copy the I/O pin state into the carry
btfsc IOPORT,IOBIT ;First, it's assumed the io pin is low
setc ;If it isn't then we set the carry bit
;NOTE, if the I/O pin is either the most
;or least significant bit, then a rlf
;or rrf instruction accomplishes the
;same thing in 2 fewer cycles.
; The next 4 instructions copy the new sample to the lsb and shifts
;the previous samples left one position. However, the msb (which
;contains the filtered state) is left unchanged.
; starting with sample == abcdefg and C=s (carry is equal to newest
;sample):
rlf sample,f ; bcdefghs C=a
rlf sample,f ; cdefghsa C=b
rrf sample,w ; cdefghsa C=a (W contains bcdefghs)
rrf sample,f ; acdefghs C=a
andlw FILTER_MASK ;examine the last N consecutive samples
skpnz ;If they're all zero
bcf sample,7 ; then the filtered state is low.
xorlw FILTER_MASK ;But we're really interested in highs
;If we complement all of the bits
;and the result is zero, then that
;means the last N samples were high.
skpnz ;If any of the last N were low or if
btfsc sample,7 ; they're all high but the filter is
return ; already high, then we're done
;If we get here then a positive pulse has been detected
incf pulse_counter,f ;count it
;
bsf sample,7 ;Set the "filtered" flag
return
See: