Very high speed DUAL 4X-resolution quadrature encoder

;======================================================================================
; 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年9月4日 11:26, owner: RVA-RAm-R00a,
40.74.122.252: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?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://techref.massmind.org/techref/microchip/ramquaddesc.htm"> Very high speed DUAL 4X-resolution quadrature encoder</A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.


Link? Put it here:
if you want a response, please enter your email address:
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?

Welcome to massmind.org!

Welcome to techref.massmind.org!

.

AltStyle によって変換されたページ (->オリジナル) /