[sdiy] Need goog working rotary encoder in C code..

rburnett at richieburnett.co.uk rburnett at richieburnett.co.uk
Sat Aug 7 17:02:55 CEST 2021

As an embedded programmer crappy encoder interfaces are a major pet hate 
of mine.  Particularly when a product relies on the encoder as the main 
part of the user interface in order to achieve anything.  For example, 
in my home I currently have an Agilent 33250A signal generator who's 
encoder wheel is almost completely un-responsive, a NEFF oven where the 
clock goes wild if you so much as touch the encoder knob, and a 
Microwave oven where the time counts backwards if you turn the encoder 
dial too quickly!

The timing function of the NEFF oven is completely unusable, but the 
encoder is directly above the oven door so I guess it's had a hard life 
in terms of temperature excursions.  The backwards counting encoder on 
the Microwave is annoying and surely down to bad programming, but still 
potentially dangerous if you end up heating something for 95 mins 
instead of 20 seconds.  (I'd love to know what stubborn cooking task 
requires 900 Watts of microwave energy for 95 minutes!?!?)

I'm less forgiving of the Agilent sig gen though.  It's had an easy life 
sat on a bench in a clean lab (it's not even in a busy production 
environment) and apparently has succumb to oil leaking past an O-ring in 
the optical encoder due to lack of use!  Either way it renders a 
multi-thousand pound piece of professional test equipment next to 
useless if it wasn't for the much slower option of entering frequencies 
using the numeric keypad (>.<)

I don't claim to know the answers, but what I've always done is to poll 
the encoder connected to two GPIO inputs about every 2ms or so.  I read 
the values of the two inputs as a 2-bit binary number.  Each time you 
read the inputs you keep track of the new code and the previous code, so 
that you can follow the sequence... 00, 01, 11, 10, 00, 01, 11... etc.  
You can then make a state machine and decide which state transitions are 
valid and those that are not.  For example you might decide to increment 
your parameter if you move from 00 to 01, or when you move from 11 to 10 
if these correspond to clockwise rotation, and decrement the parameter 
when you move from 01 to 00, or when you move from 10 to 11 for anti-CW 
rotation.  This doesn't remove the effect of contact bounce in itself, 
but does ensure that you don't accumulate transitions due to bouncing.  
In other words if there is contact bounce around a transition your 
variable might alternately inc and dec a few times, but shouldn't 
suddenly jump up or down by a large amount with a single click of the 

Watch the attached video for an example of a product that implemented 
this wrong.  You can make the value increment endlessly for no overall 
clockwise movement in the encoder dial just by rocking it back and forth 
over a particular spot.  Likewise you can make it decrement endlessly 
with no overall anti-clockwise movement by rocking it over other spots!


On 2021-08-07 14:34, Mike Bryant wrote:
> Agreed – which is why I have a stock of the cheapest Chinese EC12
> clones bought on eBay.  I’d never put them in a real product but
> great for proving the design will last over time.
> From: Synth-diy [mailto:synth-diy-bounces at synth-diy.org] On Behalf Of
> John Speth via Synth-diy
> Sent: 07 August 2021 14:21
> To: 'Brian Willoughby'; Jean-Pierre Desrochers
> Cc: 'SDIY'
> Subject: Re: [sdiy] Need goog working rotary encoder in C code..
> Clean edges are expected with a new encoder. That's what makes
> debounced design and testing so difficult. If you had noisy switches,
> you can work on code that can address bounce. Without noisy switches,
> you can't. For starters, until your switches start to bounce, you have
> the benefit of working with a perfect model of switches (which means
> you should never miss edges that don't bounce).
> On Saturday, August 7, 2021, 04:17:04 AM PDT, Jean-Pierre Desrochers
> <jpdesroc at oricom.ca> wrote:
> Here is a screen shot of the encoder's pins A & B pulsing from idle
> state..
> I know this is around 150RPM spinning (way too fast) but it is to show
> you the pulses are clean.
> I mostly turn the encoder around 60 RPM or slower for all my tests.
> -----Message d'origine-----
> De : Brian Willoughby [mailto:brianw at audiobanshee.com]
> Envoyé : 7 août 2021 03:49
> À : Jean-Pierre Desrochers
> Cc : SDIY
> Objet : Re: [sdiy] Need goog working rotary encoder in C code..
> The Bourns PEC11L is rated for 60 RPM, maximum. That's 1 rev/sec or 50
> ms/pulse:detent.
> The contact bounce at 60 RPM is 10 ms, so that leaves only a small
> window in which to read the steady switch state before it changes
> again. A challenge here is that I would expect a pulse a.k.a. detent
> to involve all four transitions of the quadrature pattern. If that is
> correct, and each transition involves 10 ms of bounce, then you have a
> total of 40 ms of bounce during each 50 ms cycle, and that's only 2.5
> ms of steady state in which to read each state.
> The Bourns data sheet says "Devices are tested using standard noise
> reduction filters. For optimum performance, designers should use noise
> reduction filters in their circuits." I assume that this means a
> simple RC filter, but one which would not interfere with the 2.5 ms
> window. In other words, the RC filter should smooth out the contact
> bounce that occurs during the first 10 ms, without holding the voltage
> so long that the 2.5 ms window is not still outside the logic
> threshold to detect the change. You probably want to confirm the
> signal integrity with a 'scope if you're having trouble.
> One technique that was mentioned in the thread is to use a counter.
> This allows the bounce to occur, with every high value adding 1 to the
> count and every low value subtracting 1. Thus, even if you read
> unfiltered bounces, the final value should still be correct. The trick
> here is to only count the changes, not every polled value (if I recall
> correctly).
> Given these time frames, you must consider the clock rate of your
> PIC16F as well as the operating speed of your particular firmware
> implementation. If your code cannot process an entire pulse:detent in
> 12.5 ms, then you're probably going to read very unreliable values.
> There are processors such as the TM4C ARM family from Texas Instrument
> that have quadrature encoder interface peripherals. With these, you
> can program the hardware for a maximum value and an minimum value, as
> well as control whether you want to allow the value to wrap around at
> the extents or stick at the extreme value. These peripherals handle
> the quadrature pins directly, and increment or decrement the current
> value based on the direction of rotation. There is even digital
> filtering available as an option. Unfortunately, these QEI peripherals
> still require proper pull-ups and filters, or they won't work
> reliably, either.
> One question I have is whether typical users might exceed the 60 RPM
> in short bursts. I don't think anyone could twist a full 360 degrees
> at an excessive rate, but smaller rotation could actually be done
> faster than the rated maximum. I don't actually have any numbers here,
> but if I imagine what it would take to rotate an encoder a full turn
> at a constant speed during one second, I can easily imagine rotating
> it faster than that for a fraction of a full turn. In any case, if my
> estimate is correct, then you'll exceed to maximum rated speed of the
> hardware itself, regardless of your firmware.
> Brian
> p.s. Note that cheaper encoders have so much contact bounce that no
> firmware could possibly read them reliably. The only solution for
> cheap encoders is to train the operator to rotate the encoder VERY
> slowly.
> On Aug 6, 2021, at 08:46, Jean-Pierre Desrochers <jpdesroc at oricom.ca>
> wrote:
>> Hi everybody.
>> I’m doing some tests on a rotary encoder and a PIC16F1783.
>> A standard Bourns encoder like THIS .
>> Connected using 2 x 10k pullups with 0.01uf caps to ground to PORTB
> of
>> the micro. Interrupt calls (falling edges) used on encoder pins A &
> B.
>> I struggled so far to get clean increments/decrements out of it.
>> Many missing counts occur..
>> I tried many source codes on the web with no luck..
>> Is there anybody who’d have worked on this in the past and have a
>> working c code ?
>> No ARDIUNO please.
>> Thanks !
> _______________________________________________
> Synth-diy mailing list
> Synth-diy at synth-diy.org
> http://synth-diy.org/mailman/listinfo/synth-diy
> Selling or trading? Use marketplace at synth-diy.org
> _______________________________________________
> Synth-diy mailing list
> Synth-diy at synth-diy.org
> http://synth-diy.org/mailman/listinfo/synth-diy
> Selling or trading? Use marketplace at synth-diy.org

More information about the Synth-diy mailing list