In my case, I was using a PIC18F2550 with a fixed 500 Hz interrupt to poll the encoder inputs
and I selected pins that had schmitt trigger inputs. On the software side, I used the algorithm
described in the attached Application Note (It does NOT use a lookup table). The interrupt
routine determined the direction of rotation and then either incremented or decremented a global
count variable. Then in the main() function, the count variable was used and cleared. Thus,
the running count could be applied at a slower rate than the encoder sampling rate.
On a side note, you could use the amplitude of the running count as a pseudo acceleration if
your main execution loop occurs at a relatively regular rate.
For example, to set some amplitude:
int count=0; // Running encoder count from interrupt
int amplitude=0; // Variable to be changed
main() {
int x; // Temp storage for encoder count
while (1) {
x = count; // Get encoder count
count = 0; // Clear count right away to avoid missing an encoder change
if (x>0) {
amplitude += 10abs(x-1)
} else if (x<0) {
amplitude -= 10abs(x-1)
}
// Do Other Stuff...
}
}
I choose the 500 Hz interrupt rate because of other functions it also needed to do.
You can experiment with the rate to see how slow is acceptable.
The code (I rewrote it in C):
; PROGRAM: Read Rotary Encoder (RD_ENCDR.SRC)
; This program accepts input from a rotary encoder through bits RA.0 and RA.1,
; determines the direction of rotation, and increments or decrements a counter
; appropriately. It displays the hexadecimal contents of the four-bit counter on a
; seven-segment LED display connected to port RB.
; Remember to change device info when programming a different PIC.
device pic16c54, rc_osc, wdt_off, protect_off
reset start
encoder = ra
display = rb
; Variable storage above special-purpose registers.
org 8
temp ds 1
counter ds 1
old ds 1
new ds 1
; Set starting point in program ROM to zero.
org 0
start mov !rb, #0 ; Set rb to output.
mov !ra, #255 ; Set ra to input.
clr counter
mov old, encoder
and old, #00000011b
:loop call chk_encoder
mov w, counter
call sevenseg
mov display, w
goto :loop
chk_encoder mov new, encoder ; Get latest state of input bits.
and new, #00000011b ; Strip off all but the encoder bits.
mov temp, new
xor temp, old ; Is new = old?
jz :return ; If so, return without changing counter.
clc ; Clear carry in preparation for rotate-left instruction.
rl old ; Move old to the left to align old.0 with new.1.
xor old, new
jb old.1, :up ; If the XOR resut is 1, increment counter, otherwise decrement.
:down dec counter
skip
:up inc counter
and counter, #00001111b
mov old, new
:return ret
sevenseg jmp pc+w ; display lookup table
retw 126, 48, 109, 121, 51, 91, 95, 112
retw 127, 115, 119, 31, 78, 61, 79, 71