Jump to content

Quadrature encoders and interrupts

Recommended Posts

I have some quadrature encoders I'm working to interface with. The issue is that they have detents that are aligned with the "open" state on both lines (so you can idle them with zero current draw).


During a single "click", both channels will experience a full pulse, with one channel leading the other to indicate direction. I'm curious what is considered the best way to handle this. Do I need to use timer capture and figure out which pulse was first, or is there something simpler I can do with just standard interrupts? I did try it out with just interrupts, but when I put a breakpoint in the isr, both flags were always set, like it wasn't catching one hitting before the other.


Any ideas?

Link to post
Share on other sites

I would enable the pulldown resistor on both input pins, then put an interrupt on one pin, let's say quadrature pin A.

When the pin A interrupt fires check the state of the other quadrature pin. If B is low, A happened first, if B is high B happened first.


I don't see any particular reason that wouldn't work with idle-open quadrature. I know it works nicely on idle-LOW quadrature.

Link to post
Share on other sites

I tried basically that (just backwards... Pull ups on the two pins and common grounded.


When I put a breakpoint in the isr, it would halt when I clicked it over, but both flags were set and the two pins always showed high.... I suppose that could just be a quirk of the debugger though.

Link to post
Share on other sites

The debugger doesn't work well inside interrupts, or at least it certainly didn't for the last person that was trying to read inputs via the debugger inside an interrupt. I haven't tried it myself.

I'd feed a counter variable and use that to see if the interrupt is working correctly.

Link to post
Share on other sites

I would guess at bounce issue as well. Simplest solution is an RC filter. Several ways to do it, but I tend to avoid the simplest, which is putting a cap directly across the contacts, unless I know that it is a very limited use device, as this method tends to destroy the contacts quickly. A three resistor solution is better, and properly tuned generally satisfactory. (see attached MSpaint sketch) Adjust the cap as needed. The Tc as shown is about 1ms, which is my usual starting point.


This is not the best way to go for production devices, but is quick and simple for a one off, and a good check for bounce issues.


A better solution is to disable the interrupt for a while after the first one. Figure the first one will be the true, unbounced read for the other line. How long to disable? Depends on rate you expect the control to be turned at. If it is a 16posn unit, and figure maybe 2 rev per sec at breakneck speed (32 motions per sec), disable interrupt for 25ms  and you will catch the next.


ANY debounce scheme can be sensitive to the half-step issue. Half way to the next click, then back. Is it counted? If the knob is held near half step, does it continually retrigger?


I tend to prefer a state machine approach to reading quad encoders. Both lines to interrupt inputs, and set the interrupt enables based upon current state. That way, all bounce does is go back and forth between to adjacent states, until settling occurs to the final state. With mechanical switching, I still usually put an RC in if I can, as that reduces the need for quick response to the interrupts due to switch bounce, but the RC Tc can be short enough (maybe 20us, depending on circumstances) that the cap can be very small, sometimes lead capacitance being enough if the resistors are at the switches.


Link to post
Share on other sites

Yea, my board design does have an RC filter on those lines very similar to what you drew up (pulled it from the encoder's data sheet, so I'm assuming it will work well).  I was just prototyping with some jumpers and a launchpad while I wait for parts to arrive.  I will give the software debounce a shot though.  The detents are small and deep enough that it is pretty tough to get the encoder to half-step. 



Link to post
Share on other sites

So... I made an attempt with limited success. My code looked something like this (I'm on my phone so I can't copy the actual code):


Port 1, interrupt on encoder channel A;
Timer A 0 in up mode, interrupt off;
Ta0ccr0 = 40ms;

Port 1 Isr:
Disable port 1 interrupt;
Check state of B to determine direction;
Reset timer to 0 and enable interrupt;

Timer isr:
Disable timer interrupt;
Enable port 1 interrupt;

It seems to have cleaned things up quite a bit, but I'm still getting random spurious counts. The scope shows the edges can get really messy, so I'm hoping the hardware filter can stabilize it.

Link to post
Share on other sites

good to hear. Debounce can seem like magic. Quad encoder with decent switches gives redundancy (via 4 states) that helps a lot. Old school with sliders, like the early microsoft mice with brass contacts sliding on a pattern on a PC board, were horrid to decode, as it was ALL bounce. I hated those mice, and I hated when I was working on things that used the guts of one for an input device.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...