Introduction

I’ve been having a lot of fun with my LAB-X3
lately. This time I wanted to figure out how to read rotary encoders.
If you aren’t familiar with them, a rotary encoder looks like a
potentiometer, except that instead of a variable resistor it an encoder
wheel. Also, unlike a potentiometer they don’t have a “stop” point
generally. Thus you can turn them around and around and around. They
have become very popular on electronic equipment because you can create
a “soft” control that is digital from the start. Further, because they
have become fairly popular the costs have gone down such that the one
I used from Grayhill is only $4.70 from Digikey (
GH3071-ND) qty 1.

These mechanical encoders generate a “quadrature” signal. I don’t know
the origin of the term quadrature but basically it means there are four
states that this device can be in. Further, transition from one state
to the next is well defined so with a simple circuit or some software
you can translate the pulses into rotation movement.

The three pins on the device are A, B, and Common. Since they are
mechanical they are simply switches that connect the A pin, the B pin,
and then both the A and B pin to the C pin. A simple circuit for hooking
this up is shown below.

Encoder Reading Circuit

As you can the outputs will appear to be 5V when the encoder is not
connecting either A or B to C and they will be at ground potential
(logic 0) when they are being connected.

The output of the encoder is a two bit gray code, specifically it has the sequence

Relationship of Rotation to Signal Changes

Clockwise Rotation ->

00 01 11 10 00

Or more specifically, if the output is 00 and it goes to 01 you know that
the encoder has moved one “tick” clockwise, if it is 00 and goes to 10
then you know it moved one tick counter clockwise. If it goes from 00
to 11 you know you missed an intermediate tick. It can be useful to flag
this case so that you know your input isn’t accurate, but generally its
safe to ignore it as if the knob didn’t move.

Now there are a couple of ways you can read this device, the simplest is
to set your microcontroller to interrupt when ever the state of the two
pins changes. Then by knowing the previous state and the current state
you can tell what happened. This is easy to do with the PIC which has
the ‘change on PORTB’ interrupt mode. An alternative is to hook the two
pins up to input capture pins of the Motorola 68HC11. When you capture
a rising or falling edge on either input you can update the position
state. Finally, there is an even easier way (but its a bit risky) which
is to sample the pins every n microseconds and see if their state has
changed.

I chose to use the sampling technique and sample at 1Khz (1 mS per
sample). My reasoning was as follows:

We’re talking a human here who is turning this knob, and if they spin it as hard as they can they worse they can do is miss one state. Normal use is unaffected.

If there is any “bounce” in the switch (and I’ve not detected any) then the mS sampling will cover for it.

The code to read these is fairly straight forward, I’ll save you from
digging from the full file by just pulling out the relevant bits. If
you want the whole thing email me and I’ll send it to you.

I’m using the PIC16F628 in a LAB-X3 proto board. The encoder was soldered
into the prototyping area with the appropriate pull up resistors. Note
that you could use the ‘weak pullups’ feature on PORTB but I didn’t want
to turn those on for all the pins. Anyway, as I’m not using the serial
port in this example I jumper the Encoder to pins RB1 and RB2 on the PIC.

The code to set up a 1Khz interrupt from TMR0 on a 4Mhz system is as follows:

As you can see the TMR0 is reloaded first to insure an accurate tick rate
(also TMR0 is the first interrupt checked!) Once you know you’re set to
get the next “tick” on time, then you can check the quadrature state. In
the ISR I call QUAD_STATE and this is written as follows:

The INC_COUNT and DEC_COUNT limit the resulting value to between 0 and
200 because that was what my application called for, however it could
just as easily have kept an 8, 16, or even 32 bit absolute value. Clearly
this code would also work with quadrature encoders on wheels of a robot
but there you have to take into account that if your robot is moving
quickly you will definitely want to adjust the sample rate accordingly!

An alert reader pointed out that I could just write a subroutine for
the quadrature encoder that returned +1 or –1 or 0 and then added that
to the value. To that end, the following subroutine was created:

Now, instead of calling INC_COUNT or DEC_COUNT, I just call this
routine with the computed value of QUAD_ACT and the add W to the COUNT
variable. After the addition I test for over flow or underflow and
update the value accordingly. Given that the top 4 bits of PORT B can
be configured for “interrupt on change” I’ve got to assume this is how
they implement computer mice with two quadrature encoder wheels.

In a final bit of cleverness, if you skip a state, and you remembered that you were turning clockwise or counter-clockwise, you could choose to increment or decrement by 2. That would keep the count accurate.

Using mechanical rotary encoders is easy to do and they provide an
excellent “frob knob” for your projects. Software can set them to be
anything from simple on/off switches, to linear or log potentiometers,
or arbitrary value adjusters.

The amount of code needed to use them is comparable to the ‘pseudo analog’
techniques of pulling the line low then high and counting ticks until it
crosses the logic 1 threshold (example the POT command on the Stamp). They
do consume 2 digital I/O’s rather than an analog I/O which is a detriment,
but with an R2R ladder on the output they could use an A/D input.

Finally if you’re using quadrature encoders on your wheels, you’ve
probably already got the code in your system to deal with them and they
are then nearly a total win.