; ;******************************************************************* ; ; Experimental quadrature decoder for 12F508/12F509 ; Input: Quadrature signals on GP0, GP1. "Reverse" control on GP3 ; Output: Low going pulse on on GP5, Direction indicator on GP4 ; This expands on previous versions by adding direction-sensing debounce. ; The principal drawback of a preset loop-counting approach (eg Quad1) ; is the tradeoff between keeping-up with high speed input ; (spinning the dial) and discriminating adequately between direction- ; reversal and contact-bounce at low rotation speeds. ; This new approach makes some assumptions about the general nature ; of encoders. ; ; 1/ Contact bounce or jitter only occurs on the line that has ; changed most recently and therefore resembles a change in the ; direction of rotation. ; 2/ Due to the inertia of the mechanism, reversal of direction ; can occur only at low rotation speeds. ; ; For example: ; 00 to 01 to 00, at high rotation speed is likely to be bounce ; 00 to 01 to 11, at high rotation speed is not likely to be bounce ; 00 to 11 or 11 to 00 or 10 to 01 or 01 to 10 should never occur ; The principle here is to set a longer debounce threshold for transitions ; that indicate a reversal of the current direction of rotation ; ; Consider a 250 vane wheel spinning at 10 rotations per second. ; each edge of the vane generates a transition and there are two sensors ; This yields a transition rate of 250 x 4 x 10 = 10000 transitions per sec. ; ie 100uS per transition. ; In practice, quadrature 'skew' will reduce this time but 100uS per ; transition should be fast enough for all practical purposes. ; Our input capture loop time is approx 20uS and so the maximum (8-bit) ; 255 Consecutive identical readings would take 5.1mS corresponding to a ; rotation rate of approx. 0.2 rotations per second: 72 degrees per sec. ; We require instantaneous rotation speed to be lower than this to ; accept that the direction of rotation has changed. ; ; Connect low going quadrature pair to pins 6 and 7 ; 15uS low going pulse output on pin 2, direction output on pin3 ; connect pin4 to 0V and reboot to reverse direction ; The "non debounced" direction indicator is brought out on pin 5 ; for diagnostic purposes. ; ; V1.2 CMS 26/03/2008 ; ;******************************************************************* ; #include __config (_MCLRE_OFF & _CP_OFF & _WDT_OFF & _IntRC_OSC) ; #define CLKBIT GPIO,5 #define DIRBIT GPIO,4 #define REVBIT GPIO,3 #define DIRFLG GPIO,2 ; MSKBYT equ 3 ; quadrature input bit mask ; higspd equ D'004' ; hi speed debounce value lowspd equ D'255' ; low speed reversal credibility threshold ; ; reserve some space for variables ; cblock 0x08 ; temp1 temp2 count speed ; endc ; cblock 0x10 ; ; reserve 16 bytes for a jump table ; none1 ;0 ;0000 cw1 ;1 ;0001 ccw1 ;2 ;0010 inv1 ;3 ;0011 ccw2 ;4 ;0100 none2 ;5 ;0101 inv2 ;6 ;0110 cw2 ;7 ;0111 cw3 ;8 ;1000 inv3 ;9 ;1001 none3 ;a ;1010 ccw3 ;b ;1011 inv4 ;c ;1100 ccw4 ;d ;1101 cw4 ;e ;1110 none4 ;f ;1111 ; endc ; org 0 ; osccal value in w on power up movwf OSCCAL ; ; movlw B'10000111' ; no wake on pin change, weak pull-ups on option ; internal timer clock, prescale 256 ; movlw B'00001011' ; bit0, bit1 and bit3 are inputs tris GPIO ; ; clrf GPIO ; all outputs off, rotation clockwise bsf CLKBIT ; clock pulse active lo ; ; load up the jump-table and curse Harvard ; movlw none ; same as last scan ; movwf none1 ; into all "no change" movwf none2 ; locations movwf none3 ; movwf none4 ; ; movlw grab ; start address of grab routine ; movwf inv1 ; into all "non valid" movwf inv2 ; locations movwf inv3 ; movwf inv4 ; ; movlw cw ; start address of cw routine ; btfss REVBIT ; normal or reverse output required? movlw ccw ; start address of ccw routine ; movwf cw1 ; into all "clockwise" locations movwf cw2 ; movwf cw3 ; movwf cw4 ; ; movlw ccw ; start address of ccw routine ; btfss REVBIT ; normal or reverse output required? movlw cw ; start address of cw routine ; movwf ccw1 ; into all "anticlockwise" locations movwf ccw2 ; movwf ccw3 ; movwf ccw4 ; ; ; main loop ; grab equ $ ; movf temp1,w ; save previous movwf temp2 ; input ; movf GPIO,w ; grab data andlw MSKBYT ; mask movwf temp1 ; save ; bcf STATUS,C ; not necessary but safer rlf temp2,f ; rotate previous data left twice rlf temp2,w ; ; iorwf temp1,w ; form four-bit transition code ; iorlw 0x10 ; form table offset address ; movwf FSR ; get jump vector movf INDF,w ; ; bsf CLKBIT ; clock signal to inactive (hi) ; movwf PCL ; and go ; cw equ $ ; movlw higspd ; assume no direction change btfsc DIRFLG ; test previous direction movlw lowspd ; revese direction indicated movwf count ; refresh counter bcf DIRFLG ; flag clockwise rotation goto grab ; ; ccw equ $ ; movlw higspd ; assume no direction change btfss DIRFLG ; test previous direction movlw lowspd ; revese direction indicated movwf count ; refresh target bsf DIRFLG ; flag anti-clockwise rotation goto grab ; ; none equ $ ; movf count,f ; test counter zero flag btfss STATUS,Z ; pass new code once only decfsz count,f ; unchanged data so goto grab ; decrement debounce counter ; ; we have a consistent code ; btfsc DIRFLG ; copy flag to output bsf DIRBIT ; btfss DIRFLG ; bcf DIRBIT ; ; bcf CLKBIT ; clock signal to active (lo) goto grab ; ; end