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