;====================================================================================== ; 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 10:15, local time: 2024/12/25 19:17,
owner: RVA-RAm-R00a,
3.133.149.244:LOG IN
|
©2024 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://linistepper.com/techref/microchip/ramquaddesc.htm"> Very high speed DUAL 4X-resolution quadrature encoder</A> |
Did you find what you needed? |