![]() |
Helicron's AVR Pages Atmel AVR and GCC tools |
Contact Us |
|
|
Quadrature decoding with a tiny AVR 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 2X decoding 4x decoding 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
|
|||
|