Вы находитесь на странице: 1из 4

Decode a quadrature encoder in software - 2011-01-20 11:00:00 | EDN Page 1 of 4

Decode a quadrature encoder in software


Use a microcontroller to decode signals without the need for a dedicated IC.
Sid Levingston, Gentec-EO, Lake Oswego, OR; Edited by Martin Rowe and Fran Granville -- EDN, January 20,
2011

Quadrature encoders work in many applications to determine displacement and direction of mechanical travel.
They vary in design, but they all do the same thing: supply a set of square waves 90° out of phase. Figure 1
shows the typical output signals.

The encoder rotates clockwise


when Channel A leads
Channel B. If Channel B leads
Channel A, the encoder is
rotating counter clockwise. By
counting the pulses and the
direction of rotation, you can
find the position of the
encoder. Although ICs can
decode quadrature encoders,
you can easily and less
expensively have the
processor decode the signal. The signals from Channel A and Channel B go through a Schmitt trigger
if necessary, but many encoders and processors include this trigger internally. The signals are then
applied to two I/O pins on the processor that support edge-triggered interrupts. The code in the
interrupt handler implements a standard decoder algorithm, but all algorithms typically follow these
steps:

1. Set up a state table like the one in Table 1. The table wraps
around from State 3 to State 0.
2. Initialize a counter.
3. Measure the current state of Channel A and Channel B. Find
that state in the table and set a pointer to it.
4. Enable the interrupts.

In the interrupt handler, use the following steps:

1. Read the state of Channel A and Channel B.


2. If the state is the one preceding the pointer, decrement the counter.
3. If the state is the one following the pointer, increment the counter.
4. Set the pointer to the new state. 5. Clear the interrupt.

This method requires that a state table exists, that the previous state Read More
remain, and that the handler determine on each interrupt which of four Design Ideas
states exists and then make a decision based on two possible conditions. The handler accomplishes
this task with a four-case switch, in which each case has two if conditions.

Now, consider what happens in the real world. If the I/O pin generates an interrupt on a rising edge, then when
the interrupt happens, that channel goes from low to high. Therefore, there’s no reason to read the state of the
pin that interrupted. The other channel did not interrupt because the signals are 90° out of phase. So, to
determine the current state, you need only to read the state of the pin that didn’t initiate the interrupt. The state
of the unchanged low or high signal tells which way the encoder rotated. If it is low, then the interrupting pin is
leading. If it is high, then the interrupting pin is trailing. You can use these facts to implement an efficient
interrupt handler with no state table and no memory of a previous state.

The code in Listing 1 was tested on an MSP430F processor connected to an Encoder Products
model 15T. The encoder monitored the position of a linear stage. The stage traveled 85 mm and could
be tracked with resolution of 5 microns.

The define statements (highlighted in red) make the code more readable. The initPort() function
(highlighted in blue) sets up the rising-edge interrupt on channels A and B. The final piece is the
interrupt handler (highlighted in green). Note that it contains only six lines of code compared with the
20 or 30 lines it would take to implement the traditional method of decoding the channels.

http://www.edn.com/article/512304-Decode_a_quadrature_encoder_in_software.php 04-Feb-11
Decode a quadrature encoder in software - 2011-01-20 11:00:00 | EDN Page 2 of 4
TALKBACK

» SUBMIT FEEDBACK

There is a better way to do this without having to look at edges, or requiring edge interrupts. You sample
the 2 channels periodically, ad a rate sufficient to guarantee that no more than one state change can
occur per sample. You maintain 4 bits of information: present A, last A, present B, last B. So the routine
goes like this: save last A&B to the "last" register, read A&B, and put into the "present" A&B register.
Stack those 4 bits as an index into a table of 16. In each table element there are 2 bits: one indicates
whether a step was taken, and the other indicated whether up or down. That feeds to an up/down counter
enable and direction respectively. The clock of the counter is fed from the master clock, which invokes
this routine. This can be done with a few 4000 CMOS logic packages, or done in software. In addition, a
3rd table bit can indicate an overspeed condition, (2 steps between reads) which gets latched to indicate
unreliable data. There are other enhancements, such as putting +1/0/-1 directly into the table, and adding
that to the count on each cycle to reduce the routine to a few assembly lines.

Brian Park - 2011-3-2 10:13:55 PST

This is truly a sad entry. The set up is correct. The analysis is correct. The state-machine requirements
are correct. Then the software implementation ignores all that is required, all that is discovered in the
analysis, and falls flat on its face. It doesn't desire being printed in a professional, electronics, or design
magazine.

When it says "Now, consider what happens in the real world" it might have well said, "Now here's how to
ignore the carefully-identified, and thus necessary, requirements above, and do something which will
obviously fail". The statement, "You can use these facts to implement an efficient interrupt handler with
no state table and no memory of a previous state" is complete nonsense. You cannot solve a problem
requiring quadrature tracking without memory of the previous state, or a way to translate from the
previous state and the new inputs to get the next state and count output. To say otherwise is to ignore
what a state machine is, or exhibit ignorance of the problem at hand and arrogance in promoting a flawed
solution.

As described, every time the quadrature encoder changes direction, an uncertainty of 1 count
accumulates to the count. When the direction reverses, the marks that were giving rising edges are then
giving falling edges. So every reversal, it's like randomly slipping the ruler you're measuring with to
another one, off by one count more or less.

Even worse, "in the real world" mechanical vibrations and motion chatter may cause a single transition to
vibrate under the sensor. When that happens, as it sends a rising edge, the count is advanced, and as it
moves back low, it is ignored, to be counted again on the next twist back. Literally, the count can be
advanced thousands while the shaft is sitting essentially still. This is not something a Schmitt trigger can
fix. It is real information, and can easily be tracked by the a dedicated IC or properly designed state-
machine software.

It is flawed before we even begin to descend into the design to check for latency issues, if foreground or
other interrupts can delay service which will cause counts to be lost, whether clearing one interrupt
accidentally clears the other, etc - issues a real engineer would have to consider before claiming to be
any kind of professional.

http://www.edn.com/article/512304-Decode_a_quadrature_encoder_in_software.php 04-Feb-11
Decode a quadrature encoder in software - 2011-01-20 11:00:00 | EDN Page 3 of 4

This article highlights the sad state of education about state-machines, and how poorly understood the
equivalence of software is to hardware.

Randy M. Dumse - 2011-26-1 14:19:28 PST

The approach advocated by Mr. Levingston is flawed in that it only captures 2 of the 4 possible
quadrature state changes, and is thus susceptible to incorrect counting.

For example, if the table is stopped just after a channel A interrupt, then backed up a small amount, then
moved forward again to the original position, a new channel A interrupt will occur, and a count increment
will be generated, even though no net movement of the table occurred. The only way to avoid this
problem is to detect all 4 state changes of the quadrature. This can be accomplished in one of two ways:

1. For processors which have the capability of interrupting on either edge of the int signal (such as the
Change Notification capability of the PIC24 parts from Microchip and others), enabling this mode will then
generate interrupts at all 4 states. One additional test must be made to detect the level of the channel on
which the interrupt occurred.
2. For processors without the 'either edge' capability, but which have an interrupt polarity select capability
(The ES selection on the MSP430 processor mentioned in the article and others), the other method
requires the interrupt polarity to be changed with each interrupt. If an interrupt occurs on a rising edge,
then falling-edge interrupts must be enabled while in the int handler so that the next falling edge will
cause an interrupt, and so forth. This way all state changes will be detected. The additional test
mentioned above must also be performed.

The sample code below implements this expanded algorithm. As can be seen, the implementation is still
very simple and fast to execute. Both quadrature bits are set to interrupt on a change, and then the bits
are tested to determine which one changed. The end result is a single variable, inc, that is either 1 or 0,
indicating the need to increment or decrement the count, respectively. This could be a Boolean single-bit
variable, as are the _asignal and _bsignal variables in the example, if the processor architecture allows it.

Since there are only 2 cases, the code could be made tighter by implementing an if .. else construction,
but the case was chosen instead for readability since tha maximum speed of the interrupt is far below the
maximum capabilities of the processor.

Sample C code:

x = PORTB & 0x804; // bits 3 & 12 are the quadrature bits


y = x ^ last_quad; // what changed?
last_quad = x;
inc = 0; // default inc to 0
switch (y) {
case 0x4: // B just changed
if ((_bsignal && _asignal) || //B rising w/A=1
(!_bsignal && !_asignal)) { // B falling with A=0
inc = 1;
}
break;
case 0x800: // A just changed
if ((_asignal && !_bsignal) || // A rising w/B=0
(!_asignal && _bsignal)) { // A falling w/B=1
inc = 1;
}
break;
default: // both or none = error
return;
} // switch (y)

Duane Hall
Senior Design Engineer
Won-Door Corp
Salt Lake City, Utah
duaneh@wondoor.com

Duane Hall - 2011-25-1 11:09:52 PST

if you use interupts on rising and falling of each signal, your resolution is 4 times higher, making a 2500
pulse / rotation encoder a 100000 pulse / rotation resolution. this is used in servo controllers for
machines, no problems with machine vibration as the encoder is on the servo motor axe

jazz - 2011-23-1 17:50:28 PST

The problem with only detecting rising (or falling) edges can be understood if we think about the encoder
being stopped near a transition on either channel. Now assume we have a bit of vibration (e.g., from the

http://www.edn.com/article/512304-Decode_a_quadrature_encoder_in_software.php 04-Feb-11
Decode a quadrature encoder in software - 2011-01-20 11:00:00 | EDN Page 4 of 4
machine with the encoder on it) that makes the encoder move back and forth over that one edge. There
will be rising and falling edges on one channel, but if we only detect one type of edge then we will
accumulate error counts in one direction. Same problem occur if we have larger repetitive back-and-forth
motion that do not cause the same number of rising edges each way. Each cycle will accumulate error
counts.

Bjorn Jansson - 2011-21-1 10:56:55 PST

» SUBMIT FEEDBACK

Resource Center Browse Categories Browse Companies

Featured Company
Mill-Max Mfg. Corp.
The leading US manufacturer of machined interconnect components. Product line includes
spring-loaded contacts, SIP, DIP, PGA and BGA sockets, board-to-board interconnects and
pin headers, surface mount and application specific products, PCB pins... more

Most Recent Resources


Security Video Analytics on Xilinx Spartan-3A DSP

Programmable Embedded Video Analytics


Xilinx Industrial Imaging Solutions

Spring-loaded and Target Connectors Application Note


Power Considerations in FPGA Design

http://www.edn.com/article/512304-Decode_a_quadrature_encoder_in_software.php 04-Feb-11

Вам также может понравиться