;======================================================================================
; Very high speed DUAL 4X-resolution quadrature encoder routine.
;
; This module defines a routine that will allow a 20MHz PIC16xxx to encode two
; simultaneous quadrature encoders. Transitions on both edges of both signals
; from each encoder are processed to provide 4x resolution.
;
; (c) 2003 - Robert V. Ammerman
; RAm Systems
; rammerman@adelphia.net (as of 21-Apr-2003)
; via the PICLIST (www.piclist.com)
;
; This code may be freely used in any application, commercial or otherwise, with the following
; provisos:
;
; 1. The above copyright notice and these conditions remain intact within the source code.
; 2. Robert V. Ammerman, RAm Systems, the PICLIST and PICLIST.COM have no responsibility
; for this code working in your application, or any consequences of it not working.
; 3. This code is provided without any form of warranty whatsoever.
; 4. You must make a diligent effort to contact Robert V. Ammerman via email or the
; PICLIST to inform him, in general terms, about how you are using this code (he
; is curious!)
;
; PERFORMANCE: Unlike many quadrature decoding schemes, this code does not depend on
; interrupts from edges of the input signals. Rather, it periodically checks the
; inputs to see what changes have occured. It can be driven either from a timer
; interrupt, or simply by being called from a non-interrupt-driven loop.
;
; In the non-interrupt-driven case, each call of the encoder polling routine uses
; a maximum of 22 instruction cycles, including the call and return. It uses as few
; as 12 cycles if no inputs have changed.
;
; A reasonable computation for the maximum edge rate at which this routine
; can work is:
;
; 22 instructions per poll
; x 1.5 (to allow for 'distortion' in the encoder waveforms)
; x 1.5 (to give the 'application' code at least 1/3 of the total CPU time).
; -------
; = 50 instructions per edge
;
; At a 20Mhz clock rate, or 5Mhz instruction rate, this gives a maximum edge rate
; of 100,000 edges per second or 25,000 full encoder cycles per second.
;
; Note that at the rate given above, an application has to limit itself to
; no more than 11 instruction times between calls on the ENCPOLL macro to
; meet the 1.5 factor in the above comptution. Changing that factor, for example,
; to 2.0 would allow 22 application instructions per poll at a maximum edge rate
; of about 67,000 per second. A factor of 3.0 would allow 44 application instructions
; per poll at a maximum edge rate of about 50,000 per second.
;
; When interrupt driven, a number of cycles will be used to enter and exit the
; interrupt routine, which will reduce the maximum possible edge rate.
;
; Note that if any interrupts are enabled, then the worst case ISR time has to
; be added to the clocks per edge. This is true even if the encoder is using
; the polling mode.
;
; This code is provided in ABSOLUTE mode to avoid the complexity of defining and
; distributing a linker control file with it (sorry Olin).
;
; NOTE: The sample application code that is included herein is not complete. Appropriate
; initialize code needs to be added.
;
list p=16F628,r=DEC,x=OFF
include "p16F628.inc"
;==============================================================
org 0x000
goto initialize
;==============================================================
; Where to put the lookup table
enc_lookup_table = 0x100
;==============================================================
; Variables used by the encoder
cblock 0x20
enc1_count:2 ; current count for encoder 1
enc2_count:2 ; current count for encoder 2
enc1_faults ; number of faults seen on encoder 1
enc2_faults ; number of faults seen on encoder 2
enc_inputs ; most recent (old,new) input input pair
endc
;==============================================================
; Routine to poll the encoder. This code assumes that the encoder
; inputs are connected to pins RA3..RA0, and that PCLATH is
; always set to HIGH(enc_lookup_table)
POLL_ENCODER:
movlw 0x0F ;[3]
andwf enc_inputs,F ;[4]
swapf enc_inputs,F ;[5]
andwf PORTA,W ;[6]
iorwf enc_inputs,W ;[7]
movwf enc_inputs ;[8]
movwf PCL ;[9-10]
;==============================================================
; Define a macro to poll the encoders
; Min time (including call and return) = 12 instructions
; Max time (including call and return) = 22 instructions
POLLENC macro
call POLL_ENCODER ;[1-2]
endm
;==============================================================
; Define the four possible actions for an encoder
A_NOP = 0 ; do nothing (neither input changed)
A_INC = 1 ; increment count
A_DEC = 2 ; decrement count
A_FLT = 3 ; fault condition (both inputs changed)
;==============================================================
; Macro to generate the label for an action routine
A_LABEL macro m1,m2
ACT_#v((m1<<2)|m2):
endm
;==============================================================
; Macros to perform the actions for the two encoders. To store
; a larger count than 16 bits these routines would have to be
; changed.
INC1 macro
incf enc1_count+1,f ;[1] assume carry
incfsz enc1_count,f ;[2] bump low bits
decf enc1_count+1,f ;[3] no carry actually happened
endm
INC2 macro
incf enc2_count+1,f ;[1] assume carry
incfsz enc2_count,f ;[2] bump low bits
decf enc2_count+1,f ;[3] no carry actually happened
endm
DEC1 macro
movf enc1_count,f ;[1] check for zero
skpnz ;[2]
decf enc1_count+1,f ;[3] decrement msbits
decf enc1_count,f ;[4] decrement lsbits
endm
DEC2 macro
movf enc2_count,f ;[1] check for zero
skpnz ;[2]
decf enc2_count+1,f ;[3] decrement msbits
decf enc2_count,f ;[4] decrement lsbits
endm
FLT1 macro
incf enc1_faults,f ;[1]
endm
FLT2 macro
incf enc2_faults,f ;[1]
endm
;==============================================================
; Define the routines that implement the actions.
A_LABEL A_INC,A_NOP
INC1 ;[13-15] fall thru
return ;[13-14] or [16-17]
A_LABEL A_INC,A_INC
INC1 ;[13-15] fall thru
A_LABEL A_NOP,A_INC
INC2 ;[13-15] or [16-18]
return ;[16-17] or [19-20]
A_LABEL A_INC,A_DEC
INC1 ;[13-15] fall thru
A_LABEL A_NOP,A_DEC
DEC2 ;[13-16] or [16-19]
return ;[17-18] or [20-21]
A_LABEL A_INC,A_FLT
INC1 ;[13-15] fall thru
A_LABEL A_NOP,A_FLT
FLT2 ;[13] or [16]
return ;[14-15] or [17-18]
A_LABEL A_DEC,A_INC
INC2 ;[13-15] fall thru
A_LABEL A_DEC,A_NOP
DEC1 ;[13-16] or [16-19]
return ;[17-18] or [20-21]
A_LABEL A_DEC,A_DEC
DEC1 ;[13-16]
DEC2 ;[17-20]
return ;[21-22]
A_LABEL A_DEC,A_FLT
DEC1 ;[13-16]
FLT2 ;[17]
return ;[18-19]
A_LABEL A_FLT,A_INC
INC2 ;[13-15] fall thru
A_LABEL A_FLT,A_NOP
FLT1 ;[13] or [16]
return ;[14-15] or [17-18]
A_LABEL A_FLT,A_DEC
FLT1 ;[13]
DEC2 ;[14-17]
return ;[18-19]
A_LABEL A_FLT,A_FLT
FLT1 ;[13]
FLT2 ;[14]
return ;[15-16]
;==============================================================
;==============================================================
;==============================================================
;==============================================================
; START OF SAMPLE APPLICATION CODE
;
; This dummy application shows how the PIC could be polled
; via UART to supply the current input values.
;
; Note: the numbers in [] identify the number of instructions
; between polls. To support a 100,000 edge per second rate
; this must be kept at 11 or below. As you can see, it really
; isn't too difficult.
cblock
send_save ; saved MSBits of current count value being sent
xmit_hold ; byte held while waiting for TX to be ready
endc
initialize:
; -- perform initialization of UART, ports, etc --
mainloop:
POLLENC
btfss RCSTA,OERR ;[1] do we have an overrun?
goto no_error ;[2-3]
bcf RCSTA,CREN ;[3] disable
nop ;[4]
bsf RCSTA,CREN ;[5] and reenable to correct overrun
no_error:
POLLENC
btfss PIR1,RCIF ;[1] do we have a character?
goto mainloop ;[2-3] no
movf RCREG,W ;[3] get character
xorlw 'P' ;[4] is it the poll command?
skpz ;[5]
goto mainloop ;[6-7] no
POLLENC
movf enc1_count+1,W ;[1] save MSBits of counter
movwf send_save ;[2] ...so we get a consistent view
movf enc1_count,W ;[3] send ls byte firs
call xmit_byte ;[4-5] send it off
movf send_save,W ;[3] now the ms byte
call xmit_byte ;[4-5]
movf enc1_faults,W ;[3] and the number of faults
call xmit_byte ;[4-5]
movf enc2_count+1,W ;[3] save MSBits of counter
movwf send_save ;[4] ...so we get a consistent view
movf enc2_count,W ;[5] send ls byte first
call xmit_byte ;[6-7]
movf send_save,W ;[3] now the ms byte
call xmit_byte ;[4-5]
movf enc2_faults,W ;[3] and the number of faults
call xmit_byte ;[4-5]
goto mainloop ;[3-4]
; -- send the byte in W to the UART.
xmit_byte:
movwf xmit_hold ;[8] remember it
xmit_loop:
POLLENC
btfss PIR1,TXIF ;[1]
goto xmit_loop ;[2-3]
movf xmit_hold,W ;[4]
movwf TXREG ;[5]
POLLENC
return ;[1-2]
; END OF SAMPLE APPLICATION CODE
;==============================================================
;==============================================================
;==============================================================
;==============================================================
;==============================================================
; Macro to encode an old and new state to determine what
; action to perform for a single encoder
SENCODE macro result,old,new
; no change
if old == new
result = A_NOP
exitm
endif
; fault condition (both bits changed)
if old == (new ^ B'11')
result = A_FLT
exitm
endif
; increment is: 00->01->11->10->00
; decrement is: 00->10->11->01->00
local x
x = (old << 2) | new
if x == B'0001' || x == B'0111' || x == B'1110' || x == B'1000'
result = A_INC ; it is an increment
else
result = A_DEC ; it must be a decrement
endif
endm
;==============================================================
; Macro to encode the old and new states for both encoders
; to determine the action routine to be executed.
SACTIONS macro old,new
local m1,m2,action
; figure out the action for the first encoder
SENCODE m1,((old >> 2)&B'11'),((new >> 2)&B'11')
; figure out the action for the second encoder
SENCODE m2,(old&B'11'),(new&B'11')
; combine the two
action = (m1<<2)|m2
; no sense generating a goto instruction to a return. just generate
; the return instead
if action == 0
LIST X=ON
return ;[11-12]
LIST X=OFF
else
LIST X=ON
goto ACT_#v(action) ;[11-12]
LIST X=OFF
endif
endm
;==============================================================
; Define a 256 instruction table that is indexed by the
; concatenation of the old and new state bits to determine the
; actions to be taken. It is interesting to note that each
; possible action routine is used exactly 16 times by this code
; Now build the lookup table. It consumes 0x100 locations starting
; at 'enc_lookup_table'
org enc_lookup_table
while $ < enc_lookup_table + 0x100
SACTIONS (($>>4)&B'1111'),($&B'1111')
endw
enc
| file: /Techref/microchip/ramquaddesc.htm, 13KB, , updated: 2006/3/16 11:15, local time: 2025/10/23 22:08,
owner: RVA-RAm-R00a,
216.73.216.53,10-2-207-162:LOG IN
|
| ©2025 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://www.massmind.org/Techref/microchip/ramquaddesc.htm"> Very high speed DUAL 4X-resolution quadrature encoder</A> |
| Did you find what you needed? |
Welcome to massmind.org! |
|
The Backwoods Guide to Computer Lingo |
.