Nikolai Golovchenko says:
; Encoder input test program. ; ; Board: SX Demo/Proto Board ; DEVICE SX28L, OSC32KHZ, TURBO, STACKX, OPTIONX RESET start ORG $08 ;global bank leds DS 1 ;state of leds (port B), bits 2-7 enc_state DS 1 ;state of encoder, bits 0-1 (coincides with port assignment) temp DS 1 ORG $10 ;bank0 ORG $30 ;bank1 ORG $50 ;bank2 ORG $70 ;bank3 ORG $90 ;bank4 ORG $B0 ;bank5 ORG $E0 ;bank6 ORG $F0 ;bank7 RA_DIR EQU %00000000 RB_DIR EQU %00000011 ;RB.0, RB.1 - encoder inputs ;RB.2 .. RB.7 - LED outputs RC_DIR EQU %00000000 OPTION_INIT EQU %01001111 ; |||||\_/ ; ||||| | ;Reg 0 is WREG ______||||| | ;RTCC int is dis______|||| | ;RTCC clock int._______||| | ;RTCC edge 1/0__________|| | ;Prescaler to WDT _______| | ;Prescaler (WDT) 1:128_____| ORG $000 start ;init ports clr RA clr RB clr RC mov w, #RA_DIR mov !RA, w mov w, #RB_DIR mov !RB, w mov w, #RC_DIR mov !RC, w ;init vars clr leds mov w, RB ;save initial encoder state mov enc_state, w ;**************************************************************************** ;main loop: ;1) read encoder state ;2) compare to old state ;3) if step forward, light one more led (a bar display) ; if step backward, dim one led ; if same, don't change ;4) update state ;5) repeat ; ;Note: keys are not debounced. ;**************************************************************************** read_enc mov w, RB ;get change between current and previous ;encoder state in w xor w, enc_state ; xor enc_state, w ;update state and preserve difference in w and w, #$03 ;check if there is change snz jmp read_enc ;no change, read encoder again ;if both bits changed, this will be an error, but we ignore it here ;xor w, #$03 ;skpnz ; jmp enc_error ;calculate direction in temp.1 mov temp, w mov w, <<enc_state xor w, enc_state xor temp, w sb temp.1 call inc_bar ;light one more led snb temp.1 call dec_bar ;dim one led jmp read_enc ;repeat ;**************************************************************************** ;increase the bar indicator dec_bar clc rr leds mov w, leds mov RB, w retp ;**************************************************************************** ;decrease the bar indicator inc_bar rl leds setb leds.2 ;set lower bit mov w, leds mov RB, w retp ;**************************************************************************** ORG $200 ORG $400 ORG $600
Matthew Ballinger [MattBeck at AOL.COM] says:
Or a much more efficient routine would be (in parallax mnemonics):ChkEnc mov new,Enc ;get new input and new,#%00000011 ;get rid of all but 2 enc bits mov temp,new ;make copy xor temp,old ;is old = new jz ChkEnc ;then no change, go back cje temp,#3,err ;goto "error" if both bits changed clc ;get ready for right shift rl Old ;align bits xor old,new ;check for direction jb old.1,up ;if 1 then up direction, if 0 then down direction
Alvaro Deibe Diaz [adeibe at CDF.UDC.ES] says:
; Encoder read #define encx PORTA,1 ; Encoder inputs #define ency PORTA,2 ; ; ; Inic (usually needless) clr auxint ; Clear aux var snb encx ; and get encoder inputs setb auxint.0 ; in bit 0... snb ency setb auxint.1 ; ...and 1 ; ; Here starts the hard work mov W, auxint ; encod <- (actual state) xor (previous one) xor encod, W ; (only bits 0 and 1 affected) ; rr auxint ; XOR results, reordered, get rl encod ; into encod, in bits 0 and 1. rr auxint ; This bits are the motion indicators rl encod ; At this point you have a new read of the encoder. Bits 2 and 3 of 'encod' have the information about the direction of movement of the encoder. If you have to translate this information into a variable, then you can do something like this: ; snb encod.2 ; Direction 'X' motion inc posenc snb encod.3 ; ...or 'Y' dec posenc ; Bits 4,5 and 6,7 of 'encod' have the previous reads.
Lance Allen says:
The easiest way (in my opinion) is to feed one of the two outputs (I assume its a quadrature type) to B0 and the other one to any other input (probably B1). Set the B0 input to ext interrupt enabled . Whenever an interrupt is detected by an edge presenting itself (rising or falling .. its all programable) a movement of (pulses-per-rev divided by 360) deg has been made and if you read B1and there is a 1 there the encoder turned one way, if a 0 then it turned the other.If no interrupts are available (B0 is the only ext one) then you will need to poll one input and read the other on a change.... instead.
Morgan Olsson says:
Encoders use to have between 32 to several thousands cycles per revolution.If you want perfect synchornization to a 0° sync signal, set the two gotos that you wish will count into the zero position to point to specialized count up/down routines that also checks the sync signal.
This will give the best possible zero position synchronization, with a resolution of four steps per cycle, making the most out of the encoder.
Using interrupt on change for the two lines is the best.
If you need to poll for changes instead, we we might want to add a few lines of code before my example that just check if any line has changed, thus minimizing the cycles needed when no change. (but will add total cycles when a change has occurred)