Electronic – How to interface a quadrature encoder with PIC

counterencoderpic

I'm developing a prototype that uses a quadrature encoder to measure it's linear displacement. The encoder is attached to the prototype body and has a wheel in it's shaft. As the prototype moves straight forward the encoder measure the linear distance. All the trouble around the conversion between linear/angular units have been worked out.

The reason to measure the distance with an encoder is that i NEED to know everytime that the prototype has traveled exacly 1 mm (1 millimeter = 0.0393 in). Everytime it moves 1 mm, PIC activates another system.

The way it has been done before I started working on it is by reading the encoder with a PIC (16F688) in it's I/O ports. It was kindda ok but when I added some features to the PIC code, if the prototype linear speed is greater than ~1.77 in/s (~45 mm/s) PIC starts missing the encoder count.

I've tried using the IOC (interrupt on change) from portA to read the quadrature signal (channels A and B) but it wasn't effective.

I know that there are dsPIC's but I need to solve this in my board and I have only 14 pins to do so lol. So i found this PIC16F1825 which has a higher (4x) freq. Could that (my PIC low freq) be my main problem??

I'm was thinking about using the LFLS7183 UP/DOWN signals with the timer/counter from PIC or another counter IC so that would reduce the amount of signaling to PIC. Would that work? Which counter should I use? I don't have 8 pins in my PIC to use as in those http://goo.gl/2Wc3d.

My encoder isn't my problem, I've checked and it can track as far as 76 feet/s for my wheel radius.

Best Answer

You left out the all-important information about how fast the pulses will be coming in, so I'll just assume the worst cases pulses are still slow enough for properly written firmware to catch.

I have found a few tricks to doing quadrature decoding in firmware:

  1. Don't try to catch individual changes, poll at regular intervals instead. Assume that the encoder can get stuck right on the transition for any one edge, and that edge can therefore rapidly dither. This would make a mess of any interrupt on change technique.

    With regular polling, you can tune the system carefully for how much time you want to spend in the interrupt routine. The upper limit of encoder speed is also nicely known, and isn't really any slower than the worst case with the interrupt on change method anyway. The polling method is guaranteed to work correctly up to some maximum motion speed you can easily calculate. The interrupt on change method degrades unpredictably as there is bouncing on transitions.

  2. Always decode the full 4x position. Don't try to get cutesy and do stupid stuff like count +1 when A transitions while B is high, etc. These "shortcuts" are actually harder to implement and have corner cases that get you into trouble. Even if upper levels only want to know position to a single fully cycle, you keep yourself out of trouble by decoding the new position from every change of state.

  3. Decode using a lookup table. Each interrupt, you take a snapshot of the current state of the two encoder lines. This together with the snapshot from the previous interrupt is 4 bits of data. From the previous state and the new state you can tell whether the 4x count stayed the same, or went up or down 1. Since there are only 16 possible cases, you can use these to dispatch from a table. There are 4 cases for each of staying the same, +1, and -1.

    There are also the 4 cases of the count having changed by 2 that require special handling. A change of 2 means that one transition was missed and the encoder is moving rapidly. From looking at the old and new state alone, you don't know whether it went forward 1/2 cycle or backward. Note that 1/2 cycle is a count of +2 or -2 in this system. The way I deal with this is to keep a last known direction flag. The code that does +1 and -1 sets this flag according to the known direction. When you get a step of 2, you assume it's going in the same direction as the last step of 1. That's a pretty good assumption considering inertia of real mechanical systems.

    In reality therefore you really have 5 bits of information to process each interrupt, the 2 previous encoder line levels, the new encoder line levels, and the last known direction. So for the ultimate in speed you make this a 32 entry table and handle each possible case with explicit code. The code for each of the cases adds from -2 to +2 to the current position and possibly updates the known direction flag.

As you can see, only a few instuctions are needed each polling interrupt. Your PIC (16F1825) can run at up to 32 MHz clock rate, which is 8 MHz instruction rate. Let's say you set up a interrupt every 50 instructions, which is well more than needed to do what I described above. That means you can poll at 160 kHz. Since the encoder can change by up to 1/2 cycle per interrupt, this supports up to 80 kHz encoder full cycle rate.

Related Topic