Messy waveforms

Getting Noisy Encoders Under Control

With the proper care, even inexpensive encoders can be made to operate reliably.

Download this article as a .PDF

Encoders are fantastically useful devices for human-machine interfacing. The issue for the makers, teachers, students, and engineers trying to use them is that many have less-than-ideal output signals. Output lines will ring like struck bells whenever the line changes state. Some encoders ring so much, it’s like they’ve been designed to interfere with themselves. It’s kind of like trying to listen to a person giving you instructions over a walkie talkie. You can usually tell when they are saying something, but you aren’t always sure of what.

This is probably doubly true for encoders at the extreme low end of the cost spectrum. This doesn’t mean that low-cost devices are useless or not worth your time, but it does mean that you will have to exercise more care to get them to operate reliably.

The particular model shown in Fig. 1 was one of those inexpensive hobby types—the kind that can be had for a few dollars from eBay or Amazon.

1. The inexpensive encoder shown here was the impetus behind this article.

When supplied with 5 VDC, the encoder’s outputs stayed high at about 5VDC (Fig. 2). Rotating the encoder shaft plunged the outputs low. The length of time that the lines stayed low was proportional to the speed at which the shaft was rotated. The noise generated from state changes on the encoder is illustrated in Figs. 3 and 4. As you can see, these aren’t the clean, bounce-free level transitions that are the sweet dreams of microcontrollers.

2. The two encoder channels shown are normally high.

3. Here, you can see the messy waveforms generated when the encoder shaft is spun by hand about a half turn.

4. Shortening the timescale further illustrates the ringing signals.

The encoder used has some debouncing circuitry onboard. I wanted to try and get this thing working without adding additional components, or else breaking down and wiring up a Schmidt trigger on each encoder output.

A stepper motor and driver was wired up to the Arduino UNO (Figs. 5 and 6). Now, in addition to the serial monitor, the motor would be an indicator of the health of the code. You can watch the motor mirror the effects of fumbling human fingers. Plus, motors are cool.

5. A stepper motor was used to visually indicate a properly functioning encoder.

6. A paper flag taped to the stepper shaft clearly indicates when it moves.

I tried to use a lot of other people’s code, and the results were…not good. The code may have been fine under other circumstances, but it wasn’t happening with my noisy friend. At times, specifically with falling edge interrupt triggering, it looked like the code was getting interrupted when it shouldn’t have been possible. Theoretically, the ATMega328 disconnects all interrupts the instant a hardware interrupt is triggered. However, it appeared that the rapid-fire triggering of the hardware interrupts happened so fast that the processor didn’t always get the chance to disconnect them.

So, here’s what I came up with: There are two versions of the code. One is a bare-bones program that can be incorporated into your project. The second one is the code used to control the stepper motor.

7. Shown is the stepper motor setup used to test the encoder code.

A diagram of the stepper motor circuit is included, as well (Fig. 7). Any compatible stepper driver and stepper motor can be used. You don’t need to source the exact same components seen here.

A few final notes on the code: The interrupts were set to trigger on the RISING edge. That means that the normally high encoder pulses had to drop low and then back to high before anything would happen. This was done to sidestep as much of that noise as possible. Any variables used by the interrupt-service-routines are declared as a volatile byte. Data type byte was used for speed and data integrity.

The UNO uses an 8-bit processor and can only work on a byte at a time. If the 16-bit data type int was used, the processor would actually have to chop up the int variables into byte sizes, and an interrupt can occur while this is happening.  The qualifier volatile was used to have the variables loaded from RAM rather than a storage register. This was also done for data integrity because, in some instances, storage registers can be changed in unwanted ways by the call to an interrupt service routine.

So there you are, and good luck. Hopefully, this article and the included code will be a good starting point for all you frustrated encoder users out there.

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish