Another PIC Trick -- Quadrature Rotary Encoders

Thread Starter

joeyd999

Joined Jun 6, 2011
4,269
Hi, Guys. I know you've discussed rotary encoders in the past, and I'd like to share my solution, just for fun.

Below is the interrupt routine for a quadrature rotary encoder. It was written for a PIC16CE625 back in 2000, and should run on any PIC16. It uses the port b change interrupt, with the 'A' signal tied to RB7 and the 'B' signal tied to RB6.

The nice thing about it is that it requires no signal conditioning. It's very fast, so high resolution/high speed encoders are no problem. It can accumulate up to +127/-128 counts before requiring being 'read out'.

Typically, the main program waits till the 'rawrdy' flag is set. At that point, it adds the 8 bit '_encinc' value to an accumulator (of arbitrary size), zeros '_encinc', and clears the flag. Remember to disable ints during this process, or corrupted counts will occur.

Happy to answer questions about it. Enjoy!

Rich (BB code):
;**********************************************************************
;** Rotary Quadrature Encoder                                        **
;** By JoeyD999 (AAC) Circa 2000                                     **
;**********************************************************************
;** Interrupt Routine                                                **
;** PortB.7 = Signal A                                               **
;** PortB.6 = Signal B                                               **
;**********************************************************************
;** On exit:                                                         **
;**   _encinc = signed 8 bits                                        **
;**           = number of increments/decrements                      ** 
;**             since last asynchronous read                         **
;**   flag bit rawrdy=1                                              **
;**********************************************************************
;**   uses inttmp, _enclst                                           **
;**********************************************************************     

;***** Interrupt Processing *****

	org	0x04			;interrupt vector

intrup	movwf	intw			;save context
	swapf	status,w
	clrf	status			;ensure bank 0
	movwf	intstat
	movf	pclath,w
	movwf	intpch
	clrf	pclath			;ensure this page

	btfsc	intcon,rbif		;port change interrupt?
	goto	pcint

intdone	movf	intpch,w		;restore context
	movwf	pclath
	swapf	intstat,w
	movwf	status
	swapf	intw,f
	swapf	intw,w

	retfie				;return with ints enabled

;******** Port B Change Interrupt **********

pcint	movf	portb,w			;capture encoder bits on portb7:6
	bcf	intcon,rbif		;clear interrupt
	movwf	inttmp			;save bits

	rlf	inttmp,f		;move bits into encoder reg
	rlf	_enclst,f
	rlf	inttmp,f
	rlf	_enclst,f		;bits 3:0 have index into inc table

	movlw	0x0f
	andwf	_enclst,w		;mask for 16 possible jumps
	addwf	pcl,f			;jump in table

	goto	none			;0 = no change
	goto	dec			;1 = decrement
	goto	inc			;2 = increment
	goto	none			;3 = no change
	
	goto	inc			;4 = increment
	goto	none			;5 = no change
	goto	none			;6 = no change
	goto	dec			;7 = decrement

	goto	dec			;8 = decrement
	goto	none			;9 = no change
	goto	none			;10 = no change
	goto	inc			;11 = increment

	goto	none			;12 = no change
	goto	inc			;13 = increment
	goto	dec			;14 = decrement
	goto	none			;15 = no change

dec	decf	_encinc,f		;decrement encoder counts
	goto	setupd

inc	incf	_encinc,f		;increment encoder counts

setupd	bsf	rawrdy			;indicate a new raw counts are ready

none	goto	intdone			;we are finished!
 
Last edited:
Top