There exist a number of ready-to-go chips that can convert the output of incremental (quadrature) encoders into counts, count and direction or count-up and count-down signals. This projects uses an 8-pin ATtiny processor to flexibly perform this conversion for a fraction of the cost of commercial devices.
Several applications make use of incremental shaft encoders. Many of the 'soft' front panel controls on electronic equipment use them. The4se are the kind that spin without stops - a spin clockwise increases a quantity, a spin anticlockwise decreases it. Motor speed/position sensors also produce quadrature signals as the shaft is rotated. A mechanical mouse has a slotted wheel and a pair of sensors that generate quadrature signals when the mouse is moved. The chip inside the mouse is a simple processor which can detect this quadrature signal and keep count of distance and direction, communicating the results periodically with the main computer.
A typical, ideal two-channel quadrature signal looks like this:
View this as a time-dependant graph as if on an oscilloscope. The sequence begins at the left.
1X decoding
The simplest way to use the output would be to take channel A as the input to a counter. However, that would tell us nothing about the direction of the count. Suppose however that the counter increments on the rising edge of A. You will be able to see that if we are scanning from left to right, immediately after a rising edge on channel A, channels A and B have different values. Equally, if we reverse the direction and scan from right to left, after a rising edge on channel A, both channels have the same value. Thus, we can test for equality of channels A and B to determine the direction while channel A generates the count. This scheme works very well. even if your encoder dithers back and forward around a channel A edge, the count simply increments and decrements alternately.
2X decoding
A shortcoming of the previous method is that the count frequency is the same as the frequency of channel A. Thus, an encoder said to have a resolution of 500 counts per revolution (cpr) does exactly that. We can do better by using both edges of Channel A . This is not too hard to arrange in hardware but this uses up valuable board space. The equality test described just now works just as well if we are detecting falling edges. Thus we can use the same routine for both rising and falling edges and detect twice as many transitions. With 2X decoding our 500 cpr encoder can generate 1000 counts per revolution.
4x decoding
It is possible to do even better if we examine the edges of both channel A and channel B. There are four edges for each phase of channel A and it is possible to get 2000 counts per revolution from our 500 cpr encoder.
If you have a processor with the ability to generate an interrupt on pin change it is pretty simple to get the count we want. I had a number of Atmel AVR ATtiny13 processors available which are 8 pin devices with an internal 9.6MHz clock. Channel A is connected to the INT0 pin and channel B is connected to the INT1 pin. Only the INT0 interrupt is used here as I needed only 1X or 2X decoding. The ATtiny can generate an interrupt on either a rising or a trailing edge. For 2X decoding, the sense of the interrupt is changed after each interrupt so that the routine responds alternately to rising and falling edges. On each interrupt, the direction of the count is determined and a pulse generated on either the count-up or the count-down pin as appropriate. On the processor used, pulse rates as high as 150kHz should be readily detectable. The interrupt routine takes less than 4.5us to execute and rates as high as 220kHz may be possible with inputs that are in perfect quadrature. That is unlikely in practice.
Source Listing:
;=========================================================== ; QUD ; ; P Harrison 29/11/05 ; peter.harrison@helicron.net ; If you use this code then at least let me know. ; Quadrature decoder with choice of 1X or 2X decode ; ; connect A and B phase of the quadrature signal ; to PORTB.0 and PORTB.1 (pins 5 and 5 on the ATTiny13 ; ; count up and count down pulses will appear on ; PORTB.2 and PORTB.3 (pins 3 and 7) as the count progresses ; ; PORTB.4 (pin 4) can be left floating for 2X decode ; or tied to ground for a 1X decode ; ; The pulses are about 2us long ;=========================================================== .LISTMAC .EQU PINB=0x16 .EQU DDRB=0x17 .EQU PORTB=0x18 .EQU WDTCR=0x21 .EQU CLKPR=0x26 .EQU MCUSR=0x34 .EQU MCUCR=0x35 .EQU GIFR=0x3A .EQU GIMSK=0x3B .EQU SPL=0x3D .EQU SREG=0x3F .CSEG .ORG 0 ;INTERRUPT VECTORS RJMP __RESET RJMP _INT0_ISR RJMP 0x00 RJMP 0x00 RJMP 0x00 RJMP 0x00 RJMP 0x00 RJMP 0x00 RJMP 0x00 RJMP 0x00 __RESET: LDI R30,LOW(0x9F) ; stack pointer to top of ram OUT SPL,R30 _main: LDI R30,0x80 ; system clock is crystal/1 OUT CLKPR,R30 LDI R30,0 OUT CLKPR,R30 LDI R30,0x0C ; set PORTB.2 and PORTB.3 as outputs OUT DDRB,R30 LDI R30,0x3F ; activate the pull ups on the inputs OUT PORTB,R30 LDI R30,0x40 OUT GIMSK,R30 LDI R30,0x02 OUT MCUCR,R30 LDI R30,0x40 OUT GIFR,R30 SEI _loop: RJMP _loop _INT0_ISR: LDI R30,0 ; test PINB.0 and PINB.1 for equality SBIC PINB,1 LDI R30,1 LDI R31,0 SBIC PINB,0 LDI R31,1 CP R30,R31 BRNE _DOWN_COUNT SBI PORTB,2 ; bits equal => count up RJMP _DECODE_TYPE _DOWN_COUNT: SBI PORTB,3 ; bits different => count down _DECODE_TYPE: SBIS PINB,4 ; what kind of decoding do we want? RJMP _MAKE_PULSE ; pull PINB.4 low for 1X decoding IN R30,MCUCR ; if we want 2X decoding then we LDI R26,0x01 ; toggle the sense of the interrupt edge EOR R30,R26 ; at each interrupt to detect both edges OUT MCUCR,R30 _MAKE_PULSE: LDI R24,5 ; short delay to get a proper pulse _DELAY: DEC R24 BRNE _DELAY CBI PORTB,3 ; clear the bits again CBI PORTB,2 RETI