Main Site Documentation

Rotary Encoder glitches


#1

I need help debugging a class I’m working on for this rotary encoder.
http://www.sparkfun.com/commerce/product_info.php?products_id=9117

Here’s the datasheet:
https://docs.google.com/viewer?url=http://www.sparkfun.com/datasheets/Components/TW-700198.pdf

Using the diagram on bottom right of datasheet (note that off/on is backward), I watch for the rising edge of pin A. At which time, I read pin B, if it’s off then it’s clockwise, otherwise it’s counter clockwise. Simple enough.

It is working, but every 5 “clicks” or so, it would report the wrong direction! >:(

I’ve cranked up the glitch filter all the way to 500ms, I’ve turned off glitchfilter, same intermittent unreliability.

As far as wiring, I connect pin A to A0, pin B to A1, and 3.3V to middle pin C.
I am using analog pins because I’m reserving the digital pins for other use.

public class Program
{
    public static void Main()
    {
        RotaryEncoder encoder = new RotaryEncoder(
            FEZ_Pin.Interrupt.An0, FEZ_Pin.Digital.An1, 
            new RotaryEncoder.EncoderCallback(onEncoderEvent));

        Thread.Sleep(Timeout.Infinite);
    }

    public static void onEncoderEvent(bool isClockwise)
    {
        Debug.Print( isClockwise ? "CLOCKWISE" : "counterclockwise");
    }
}

public class RotaryEncoder
{
    InterruptPort encoderA;
    InputPort encoderB;
    EncoderCallback callbackMethod;

    public delegate void EncoderCallback(bool isClockwise);

    public RotaryEncoder(FEZ_Pin.Interrupt pinA, FEZ_Pin.Digital pinB, EncoderCallback encoderCallback)
    {
        Microsoft.SPOT.Hardware.Cpu.GlitchFilterTime = new TimeSpan(0, 0, 0, 0, 200);
        
        encoderA = new InterruptPort((Cpu.Pin)pinA, true, Port.ResistorMode.PullDown, Port.InterruptMode.InterruptEdgeHigh);
        encoderA.OnInterrupt += new NativeEventHandler(encoderA_OnInterrupt);

        encoderB = new InputPort((Cpu.Pin)pinB, true, Port.ResistorMode.PullDown);

        callbackMethod = encoderCallback;
    }

    void encoderA_OnInterrupt(uint data1, uint data2, DateTime time)
    {
        bool isClockwise = encoderB.Read();
        callbackMethod(isClockwise);
    }
}


#2

look at the values of data2, maybe you see a pattern ?


#3

I’ve just printed it using Debug.Print, and as expected (due to InterruptMode.InterruptEdgeHigh) , it’s always 1, never 0.

Maybe it’s just an unreliable device? :frowning:


#4

Hi Hari… If the encoder has driven high / low outputs why have you enabled the pulldowns.

The only ways you can get this is by
a) pinA missing an interrupt (not likely as it reads low to high transition, and the next interrupt will be the same state on pinB)

or b) pinB is in the wrong state… Are you getting a wrong direction in both directions? If only in one direction, then pinB is being held in the wrong state…

The code looks right… but I’m still getting my head round interrupt behaviour in netmf…

My quadrature encoder is done with a small pic12f675 this way I get very clean pulses and a clear direction signal…

Cheers Ian


#5

Hi Ian, I enabled pulldowns because the diagram wanted the pins to be normally low and be high for pulses. So, I tell Panda to keep pins low via internal pulldown (i do not have any resistors wired outside), and the encoder will pull pins up via Pin C.

[quote]The only ways you can get this is by
a) pinA missing an interrupt (not likely as it reads low to high transition, and the next interrupt will be the same state on pinB) [/quote]
Turning the encoder knob reliably generates an interrupts.

Yes, I am getting wrong pinB states in either direction.

[quote]The code looks right… but I’m still getting my head round interrupt behaviour in netmf…
My quadrature encoder is done with a small pic12f675 this way I get very clean pulses and a clear direction signal…[/quote]
I tested this previously using just LEDs connected to pin A and B, seems to behave as expected, but I don’t have a scope so, if it bounces around, I won’t be able to see that.


#6

The outputs of the rotary encoder will be TTL there wont be much bouncing unless there is an unusual noise created on the power side… Have you got a couple of .1uf caps you can put on the signal wires (you may have to disable the pulldowns) put one on the encoders power rail aswell (This is mainly why I decode the signalling externally)

Cheers Ian


#7

By the way… Have you measured the signal output voltage A-C and B-C…

Cheers Ian


#8

Multi-tester says pin C is 3.3V, A and B are normally at 0V and spike as I turn the encoder. Unfortunately my multi-tester is not fast enough to tell me the actual voltage. I’m 99% sure the pulses are 3.3V (coming from pin C). Maybe it’s time for me to get a scope. :frowning:

Oh, maybe I should get some .1uf caps before I get that scope. :wink:

Ian, thanks for trying to help me. I’m going to join real life for a while, I’ll check back later tonight.


#9

I found this on Alpha site

Its a suggested connection diagram for these units… Thy have commoned the ground to pin C

Cheers Ian

P.S (not TTL ouputs then, I should make sure first )


#10

I use a similar rotary mechanical encoder in some products. The capacitors will go a long way towards cleaning up the signal. I’m not sure though, due to the relatively longish, read time from NETMF how polling an input to determine the state of the second phase will work. You need to know the state of the second phase at the time the first phase triggered the interrupt, not the time at which you have been informed of the interrupt by NETMF and then poll the second phase.

If both phases called the same event handler on both edges of the signal in NETMF then you would expect to see a series of events like this: PhaseA-Rising, PhaseB-Rising, PhaseA-Falling, PhaseB-Falling, PhaseA-Rising, PhaseB-Falling. If you rotate the knob in the other direction you would see somethign like: PhaseA-Rising, PhaseA-Falling or PhaseB-Falling, PhaseA-Falling. The cadence would be different so you know that the direction had changed.

This would be a much more convoluted logic to get right but may be the only way to do it when you only have access to the data ‘after the fact’.

Another option is to explore the Registers class. There are counters and such on the uC that could be used to read an encoder in a similar manner to what you are doing currently (I think.)


#11

[quote]You need to know the state of the second phase at the time the first phase triggered the interrupt, not the time at which you have been informed of the interrupt by NETMF and then poll the second phase.
[/quote]
Jeff, I understand my mistake now. That explains why it works most of the time. It misses if my interrupt handler is called just a bit too late. I will work on recognizing the phase pattern.

Thanks for the insights guys!