;-------------------------------------------------------- ; ; Quad_Decoder_Example.asm ; ; MPASM listing for the PIC 12F683 ; ; Increments and decrements an 8-bit counter ; based upon quadrature-encoded Phase A and Phase B ; conditions. ; ; The counter increments when Phase A leads Phase B, ; and decrements when Phase B leads Phase A. ; ; This routine extracts the maximum resolution possible ; from a quadrature encoder. If your codewheel contains ; 250 cells, this routine will produce 500 counts per ; revolution. ; ; Version 1.0.0 ; tjl June, 2008 ; ;-------------------------------------------------------- ; ; Overview: ; ; The PhaseA and PhaseB lines are set for interrupt-on-change. ; ; When an interrupt occurs on either the PhaseA or PhaseB line, ; the interrupt routine does the following: ; ; 1. Gets the pointer to current state ; 2. Tests if current state is the one following the previous state. ; If so, increments the counter ; 3. Tests if current state is the one preceeding the previous state. ; If so, decrements the counter ; 4. Sets previous state pointer equal to the current state pointer ; ;-------------------------------------------------------- ; ; 12F683 wiring: ; ; Phase A input on pin 7 (GP0) ; Phase B input on pin 6 (GP1) ; ; MCLR disabled. ; ;-------------------------------------------------------- ; ; Config section ; ;-------------------------------------------------------- list p=12F683 #include __CONFIG _FCMEN_ON & _IESO_OFF & _CP_OFF & _CPD_OFF & _BOD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTOSCIO ;-------------------------------------------------------- ; ; Radix, Switches ; ;-------------------------------------------------------- radix dec errorlevel -302 ;-------------------------------------------------------- ; ; Macro definitions ; ;-------------------------------------------------------- bank0 macro bcf STATUS,RP0 endm bank1 macro bsf STATUS,RP0 endm ;-------------------------------------------------------- ; ; Storage ; ;-------------------------------------------------------- ; Un-init RAM cblock 0x20 counter prevstateptr ; previous state pointer stateptr ; pointer to state table temp0 endc ;-------------------------------------------------------- ; ; Program code begins here ; ;-------------------------------------------------------- org 0 ; processor reset vector goto main org 0x04 ; interrupt vector goto Int_Svc_Rtn ;-------------------------------------------------------- ; ; Interrupt service routine ; ;-------------------------------------------------------- Int_Svc_Rtn Call FindState ; get pointer to current state movwf stateptr Call IsHigher ; if stateptr = prevstateptr + 1, Z set btfss STATUS,Z goto testlower incf counter,F ; increment the counter goto exitint testlower Call IsLower ; if stateptr = prevstateptr - 1, Z set btfss STATUS,Z goto missedpulse ; Missed transition decf counter,F ; Decrement the counter missedpulse ; For now, just ignore misses exitint movf stateptr,W ; Update prevstateptr movwf prevstateptr Call EnableInts retfie ;-------------------------------------------------------- ; ; Main program routine begins here ; ;-------------------------------------------------------- main ; Disable system interrupts Call DisableInts ; set the internal oscillator to 8 MHz bank1 movlw 0x71 movwf OSCCON ; init I/O bank0 movlw 0x07 ; No comparator, and movwf CMCON0 ; 0,1,2 are digital I/O bank1 movlw 0 ; No analog pins movwf ANSEL movlw b'00110111' ; Preset 0, 1, 2, 4, and 5 as inputs, movwf TRISIO ; with MCLR on 3 movlw b'00000011' ; Set interrupt-on-change for GP0 & GP1 movwf IOC bank0 ; Find initial PhaseA / PhaseB state, init prevstateptr Call FindState movwf prevstateptr ; Initialize counter to its midpoint movlw 128 movwf counter ; Enable interrupts to start looking for quad decoder transitions Call EnableInts ; Top loop - do nothing. mainloop goto mainloop ;-------------------------------------------------------- ; ; Subroutines ; ;-------------------------------------------------------- EnableInts ; Enable interrupts movlw b'10001000' movwf INTCON return DisableInts ; Disable interrupts bcf INTCON,GIE return FindState ; Reads PhaseA & PhaseB ; Returns with state table pointer in W bank0 movf GPIO,W ; Read state andlw b'00000011' addwf PCL,F ; State table retlw 0 retlw 3 retlw 1 retlw 2 IsHigher ; If stateptr equals the state immediately ; following the prevstateptr, returns Z set movf prevstateptr,W ; Is prevstateptr at end of state table? sublw 3 btfsc STATUS,Z goto htest movf prevstateptr,W ; if stateptr - 1 = prevstateptr, set Z addlw 1 subwf stateptr,W return htest movf stateptr,W ; prevstateptr = 3, so... return ; ...if stateptr = 0, set Z IsLower ; if stateptr equals the state immediately ; preceeding the prevstateptr, returns Z set movf prevstateptr,W ; is prevstateptr at top of table? btfsc STATUS,Z goto ltest movf stateptr,W ; if stateptr + 1 = prevstateptr, set Z addlw 1 subwf prevstateptr,W return ltest movf stateptr,W ; prevstateptr = 0 so... sublw 3 ; ...if stateptr = 3, set Z return end