Encoder Library debounced

Frank B

Senior Member
Hi,

I made a fork of Pauls' great Encoder library.
It is still compatible, and just uses an alternate algorithm which is debounced.
With cheap mechanical encoders you will have a new user experience. No debouncing with capacitors needed anymore - and is better than capacitors.
I found the algorithm on the net (link in the sourcecode), tested it, and decided to use it for the library.
Updating your existing programs is easy: exchange

#include <Encoder.H>
with
"#include <EncoderBounce.h>

https://github.com/FrankBoesing/EncoderBounce
 
I tested your library on a T3.2 with the output of my Encoder tester on a T3.6 (https://github.com/luni64/EncSim, precompiled hex files in the release section).

Following findings:

  • Looks like the lib only increments every 4th step. While some mechanical encoders internally generate 4 steps per detent there are also encoders incrementing by 2 or 1 step per detent.
  • Looks like you have a problem with the starting condition. The first step counts in opposite direction (see below).

    Anmerkung 2020-04-17 105823.jpg

  • Tested 160'000 steps up and down
    • 5kHz -> no steploss
    • 50kHz -> no steploss
    • 250kHz -> some 20 steps lost

Standard Encoder lib:
  • Gives one count per encoder step
  • Starting condition OK (starts at 0 in the right direction)
  • No steploss up to about 200kHz (same as above)
 
I tested your library on a T3.2 with the output of my Encoder tester on a T3.6 (https://github.com/luni64/EncSim, precompiled hex files in the release section).

Following findings:

  • Looks like the lib only increments every 4th step. While some mechanical encoders internally generate 4 steps per detent there are also encoders incrementing by 2 or 1 step per detent.
  • Looks like you have a problem with the starting condition. The first step counts in opposite direction (see below).

    View attachment 19744
  • Tested 160'000 steps up and down
    • 5kHz -> no steploss
    • 50kHz -> no steploss
    • 250kHz -> some 20 steps lost

Standard Encoder lib:
  • Gives one count per encoder step
  • Starting condition OK (starts at 0 in the right direction)
  • No steploss up to about 200kHz (same as above)

Thanks for testing!

Looks like it is just not compatible to your "encoders". It's meant for the cheap mechanical "china" encoders.
With these:
- Startcondition is OK.
- Gives one count per encoder step
- They are operated manually, by hand. You can't reach 200kHZ manually. Even if - you'll be not able to say if it has lost 0,000125% steps or not.

Ok, so the debounced variant seems not be good for every kind of encoder.
I have *perfect* results.
The original lib has hefty problems with bouncing. With the new variant, bouncing is completely eliminated with my encoders.
Code:
Basic Encoder Test:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
 
Last edited:
Thanks for testing!

Looks like it not compatible to your "encoders". It's meant for the cheap mechanical "china" encoders.

Sure, nevertheless it seems that the lib only works correctly for those encoders with 4 steps per detent. This is often the case but not always. E.g., this is the first one I find on Adarfruit https://www.adafruit.com/product/377 If you look at the datasheet this encoder comes with various relations between detends and pulses. There are also versions with no detents at all (Detent Option 0) Your lib would only give 1/4 of the specified counts per rev for those. There are options with 2 steps per detent and options with 4 steps per detent... In my rummage box I have all kinds of mechanical encoder with 1 / 2 and 4 steps per detent.

- They are operated manually, by hand. You can't reach 200kHZ manually. Even if - you'll be not able to say if it has lost steps or not.

Of course, I was just interested in the performance of the algorithm which obviously is good.

Bouncing:
I also tested with various bounce settings. Here an example:
Anmerkung 2020-04-17 113927.jpg

1ms bounce duration, bounce peaks from 5µs to 100µs. Count frequency 500 Hz. Don't see any lost steps with any reasonable setting.
 
Maybe :)
The original often gives 4 counts for 1 step, too. (See various threads here, or "issues" on Github)
I'll leave it as it is. If anyone gets 4 counts per step, just use a div by 4 ( / 4) :)
If it is still not good enough, just use the original lib.
 
Sorry I probably was unclear and don't want to bother you but the problem is the other way round. Yours would give 1/4th of the steps which unfortunately can not be cured by the usual divide by 4.
 
EncoderBounce not any longer on Github

Hallo Frank B,

in summer last year I downloaded your EncoderBounce library and it worked perfectly with my (also checp Chinese) encoders in the Teensy Convolution SDR code.
In the meantime I had to reinstall my laptop and lost the EncoderBounce library. Tried to get it from Github again, but it does not exist any longer - just received an Error 404.
Also a Google search dis not help at all.

Does still anybody have a copy of the EncoderBounce library and could provide it to me or put it onto Github?

Many thanks
Joerg

Hi,

I made a fork of Pauls' great Encoder library.
It is still compatible, and just uses an alternate algorithm which is debounced.
With cheap mechanical encoders you will have a new user experience. No debouncing with capacitors needed anymore - and is better than capacitors.
I found the algorithm on the net (link in the sourcecode), tested it, and decided to use it for the library.
Updating your existing programs is easy: exchange

#include <Encoder.H>
with
"#include <EncoderBounce.h>

https://github.com/FrankBoesing/EncoderBounce
 
By the way.
I'm using the great EncoderTool library by luni:
https://github.com/luni64/EncoderTool

It's absolutely, by far, the best I've ever tried. Much better than Paul's library, which is something.

Problem is, it only works on Teensies.
They are great, but I would love to use it with other chips (RISC-V, SAMD21).

Any hint about porting? Where to start?

Thanks
 
Here is some simple polling code for cheap mechanical encoders. Just replace the new_ = PINC line with some digitalReads for whatever micro you are using. The code does not keep track of absolute position. If you don't want the divide by 4, comment out all code that references mod.

Code:
int8_t encoder(){   /* read encoder, return 1, 0, or -1 */
  
static int8_t mod;     /* encoder is divided by 4 because it has detents */
static int8_t dir;     /* need same direction as last time, effective debounce */
static int8_t last;    /* save the previous reading */
int8_t new_;     /* this reading */
int8_t b;

   new_ = PINC & 3;  
   if( new_ == last ) return 0;       /* no change */

   b = ( (last << 1) ^ new_ ) & 2;  /* direction 2 or 0 from xor of last shifted and new data */
   last = new_;
   if( b != dir ){
      dir = b;
      return 0;      /* require two in the same direction serves as debounce */
   }
   mod = (mod + 1) & 3;       /* divide by 4 for encoder with detents */
   if( mod != 2 ) return 0;

   if( dir == 2 ) return 1;   /* swap return values if it works backwards */
   else return -1;
}
 
Sorry, I was not clear.
I was not searching another algorithm to read encoders, I've tried them all.
I was looking for hint to port Luni's library specifically, from Teensy-only to other boards.
 
Back
Top