Rotary Encoder Object?

in Propeller 1
Does anyone know of a Spin object that handles a rotary encoder? I tried the one in OBEX but it doesn't seem to track very well. I'm not sure it is handling contact bounce.
Comments
Jim
Jim
John Abshier
ENS1J-B28-L00256L-ND try this on digikey
I've used that exact encoder several times. It's really hard to get the output to change by one. As ErNa suggests, just take this into account in your program.
I don't know which quadrature encoder object you used but there's an object written by Kye (how usually does great stuff) which doesn't always count encoder transitions correctly.
/* * code to read a rotary encoder */ #include <propeller.h> #include "encoder.h" struct encoder_mailbox { int pin; int minValue; int maxValue; volatile int value; }; / require this many samples to match before accepting a new value #define DEBOUNCE_TARGET 2000 static _COGMEM unsigned int pin; static _COGMEM int minValue; static _COGMEM int maxValue; static _COGMEM unsigned int nextValue; static _COGMEM unsigned int nextCount; static _COGMEM unsigned int tempValue; static _COGMEM unsigned int lastValue; static _COGMEM unsigned int thisValue; _NATIVE void main(volatile struct encoder_mailbox *m) { pin = m->pin; minValue = m->minValue; maxValue = m->maxValue; nextValue = -1; nextCount = 0; lastValue = 0; m->value = 0; for (;;) { tempValue = (INA >> pin) & 3; if (tempValue == nextValue) { if (++nextCount >= DEBOUNCE_TARGET) { thisValue = nextValue; nextCount = 0; } } else { nextValue = tempValue; nextCount = 0; } switch ((lastValue << 2) | thisValue) { case 0b0000: // no movement case 0b0101: case 0b1111: case 0b1010: // nothing to do break; case 0b0001: // clockwise case 0b0111: case 0b1110: case 0b1000: if (m->value < maxValue) ++m->value; break; case 0b0010: // counter-clockwise case 0b1011: case 0b1101: case 0b0100: if (m->value > minValue) --m->value; break; } lastValue = thisValue; } }
It should be a simple matter of waiting until A goes low and checking B. Turned CW if B is still high when A goes low, or CCW if B is already low when A goes low. Then debounce until A and B are steady high.
between two neighbouring states which is fine (this can happen with optical shaft encoders at
low speeds for instance). You should be ignoring small changes (ie have a little hysteresis)
when interpreting the count value in higher level code, as the switch may be teetering on the
edge of making contact and oscillate anyway.
This is essentially the X4 encoding scheme that I recently implemented in order to use a cheap (in terms of quality and price) encoder as a tuner knob for an FM radio. Since I also monitored the switch, my pseudo-code looks like:
WAITPNE EN0ABSW, EN0ABSW
IF EN0SW = 0 THEN {seek next valid channel}
ELSE
WAITPEQ 0, EN0A
IF EN0B = 1 THEN {INC channel}
ELSE {DEC channnel}
ENDIF
ENDIF
WAITPEQ EN0ABSW, EN0ABSW
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 BAUD = 115_200 ' PST Baud Rate Ao = 0 ' A output from encoder Bo = 1 ' B output from encoder VAR long counter OBJ pst : "Parallax Serial Terminal" PUB Main | newBits, oldBits, direction pst.Start(BAUD) ' Set Parallax Serial Terminal to 115200 baud dira[Bo..Ao]~ ' Set encoder pins to inputs oldBits := ina[Bo..Ao] ' Pre-initialize oldBits (prevents non-zero starting count) pst.Clear repeat ' Repeat forever pst.Home pst.Bin(newBits, 2) pst.NewLine pst.Dec(counter) pst.ClearEnd newBits := ina[Bo..Ao] ' Get current encoder bits if newBits <> oldBits ' See if bits have changed since last time direction := (newBits & %1) ^ oldBits >> 1 ' Calculate direction (Returns 0 or 1) case direction ' Evaluate direction 0 : counter-- ' Decrement counter 1 : counter++ ' Increment counter oldBits := newBits ' Update oldBits