Home > Arduino, Code > PROBLEMS WITH ROTARY ENCODERS?

PROBLEMS WITH ROTARY ENCODERS?

September 12, 2011 Leave a comment Go to comments

CLICKS (DETENTES) AND PULSES PER REVOLUTION

Some users have reported problems when using rotary encoders with detents (“clicks”). The detents are typically specified as for example:

  • 15 pulses per revolution / 30 detents
  • 24 pulses per revolution / 24 detents

15 pulses per revolution / 30 detents  means “two detents per pulse” ; 24 pulses per revolution / 24 detents means “one detent per pulse”

The problems that have been reported is that there are two changes per click.

The rotary encoder routine used in the current version of the s/w is very simple: you generate an interrupt when there is a change in signal A and immediately compare the value of signal A with the value of signal B. The current version of the software specifies the interrupt handler like this:

  attachInterrupt(0, rotEncoder, CHANGE);

This means that for every pulse (or cycle) in the rotary encoder there are two interrupts: rising edge of the pulse (one change) and falling edge of the pulse (another change). If your rotary encoder has one detent per pulse (like the image below), then you will be processing two interrupts and therefore making two changes. See figure below.

In order to make a single change per detent, change the code to:

attachInterrupt(0, rotEncoder, FALLING);

or

attachInterrupt(0, rotEncoder, RISING);

or

attachInterrupt(0, rotEncoder, LOW);

The above change will cause the interrupt handler to generate an interrupt only with the rising or the falling edge of the pulse but not both. The “LOW” option triggers the interrupt when the signal goes low.

The current code considers CCW (counter clock-wise) direction when signal A = signal B. CW direction is when signal A is not = signal B. This means that you could use either RISING, FALLING or LOW. For best results you can try each and see what works best for you.

WHAT WORKS BEST FOR ME

I have been using rotary encoders that are “two detentes per pulse”. Recently I’ve used a rotary encoder that is “one detente per revolution”. I tried all three settings for the attachinterrupt routine (FALLING, RISING and LOW).  “LOW” worked best for me. FALLING and RISING did not work as well: some clicks did not register, some clicks were read in the opposite direction (increasing motion was read as decreasing and vice versa)

If you have a rotary encoder with no detents, then making the change will cut the number of changes per revolution in half. If you feel your rotary encoder is “too sensitive”, then you can use the above change to make it
less “sensitive”.

For more info see the Arduino reference on attachInterrupt.

CHOICE OF ROTARY ENCODER

I have two rotary encoders that I have tested the code with: one with detents and one without detents. The One with detents is a discontinued (over 10 years ago!) Panasonic model (Panasonic EVQ-WTEF2515B) available in eBay for $6-$7 (Used to cost $1.50 at Electronics Goldmine, but sold out over there). I purchased this long time ago when I started to write code for the WM8741 and had forgotten how this rotary encoder behaves.

According to the datasheet, the Panasonic encoder has 15 pulses per revolution and 30 detents. This means two detents per pulse. That is why I had to use “CHANGE” as the condition for the interrupt handler.

I find ~30 clicks per revolution to be a good number for this application. Whether they are 1 or 2 clicks per pulse it probably doesn’t matter; you just have to make sure you use the interrupt routine properly as shown above

Stock of encoders change frequently so basically you need to look for a “mechanical encoder” with built-in switch and 30-40 detents.

BOURNS has two suitable encoders:

  • 30 detents/15 pulses: PEC11L-4220F-S0015 [link]
  • 30 detents/30 pulses: PEC09-2320F-S0015 [link]

ALPS also has suitable encoders: 30 detents/15 pulses (with switch) Model EC11B15242AE.

Since availability varies, you will need to search for the current stock. A recent search for Alps mechanical encoders with switch, 30-36 detents turned numerous different models [link]. You can compare the different models with this listing [link] from Alps and take note on how you want to mount the encoder. For example:

  • The 11B series is a horizontal configuration and threaded shaft (so you can attach it to a panel)
  • The 11E and 11K series is a vertical configuration and not threaded (cannot be easily attached to a panel)

Notice the location of the detents with respect to the pulse and compare with the diagram above. There we have the pattern for rotary encoders that are “two pulse per detente”.

ALPS Model EC11B15242AE

DSC03387

HOW TO SELECT A ROTARY ENCODER

(For the Hifiduino code)

Mandatory features:

  • Having a switch
  • Having detents (or clicks). 24 to 36 clicks work well

Optional features

  • Threaded if you intend to mount it on a panel
  • Either single or double detent per pulse works well and can be adapted by the code
  1. Anonymous
    September 14, 2011 at 06:43

    Hello,
    The rotary encoder problem has been solved:

    attachInterrupt (0, rotEncoder, LOW);

    plus

    INTERVAL_BOUNCE 1

    Far so good.
    THANK YOU!

  2. September 19, 2011 at 06:10

    I tried understanding everything about detents and pulses, but I would like to confirm that the encoder I’m using will work: http://ca.mouser.com/ProductDetail/ALPS/EC11B15242AE/?qs=PoKhxlfUXjIm2pRMScFQOQ%3d%3d

    It’s 15 PRR with 30 detents. Which line of code should I use?

    • BlogGeanDo
      September 20, 2011 at 02:36

      Use this:
      attachInterrupt(0, rotEncoder, CHANGE);

      which is what I use for my encoder. Good find, BTW…

  3. chryses
    December 10, 2012 at 23:42

    I’m an absolute beginner trying to follow along with your instructions, so my apologies in advance for asking what I’m sure is a silly question. I ordered the Alps encoder you recommended above, but cannot for the life of me figure out the right connector to use to wire it to the Arduino. The 5 prongs on the encoder are different from all the other components that I’m using (both for the Buffalo III and the other HiFiDuino parts) – they are very thin and the jumper cables that I seem to be able to use with everything else fall right off of them. And the encoder won’t fit on my breadboard. I’m sure there’s a common name for the type of connector that will work with the contacts on this encoder, but I’m clueless. Should I just directly solder wires to these contacts? Any suggestions would be much appreciated. Thanks!

    • BlgGear
      December 11, 2012 at 17:36

      I would just solder them and then add some heat-shrink tubing. The encoder is typically installed in a panel, so you don’t need the pins to be installed in a board. Good Luck. Let us know how you like the encoder…

  4. chryses
    December 19, 2012 at 06:24

    Soldered up the Alps encoder – so far I like it. I found that I had to drop INTERVAL_BOUNCE down to 1 millisecond in order to get the debouncing to work properly. With a 2 millisecond value there were sporadic issues when I spun the shaft quickly (i.e., turning the shaft quickly in a clockwise direction would result in the volume value doing something like this: 0, 1, 2, 3, 2, 3, 2, 3, 4, 5, 6 …).

    • BlgGear
      December 20, 2012 at 18:01

      Thanks for sharing. Yeah, if you turn faster than 1 ms per click (but that is >500 clicks per second!), you could skip one click and then the code thinks you are moving the other direction – could also be noise… Try also h/w debouncing.

  5. Anonymous
    December 21, 2012 at 22:01

    Sorry for yet another question. I originally set up a test system with just the rotary encoder and an lcd screen and some code that printed out the encoder “position” onto the lcd. I was able to spin the encoder quite quickly and have the Arduino recognize and display each change in encoder position. I’ve now hooked up my Buffalo III-SE and am using the full HiFiDuino code package and changing the volume with the rotary encoder is very slow – no matter how quickly I turn the encoder, the Arduino Uno appears to recognize only a click or two every second. I’m guessing this is because the poor little processor is simply overwhelmed and it takes it a while to make it though each iteration of the loop() function. Is everyone else seeing the same behavior? Has anyone tried using a Teensy 3 or an Arduino Due? Would they be significantly more responsive with respect to this behavior?

  6. chryses
    December 23, 2012 at 23:38

    Looks like my stupidity was the problem, not the processor on the Arduino. I forgot to remove the firmware chip on the Buffalo! I’m actually amazed things were working at all. Popped the chip out and everything is humming along.

    • BlgGear
      December 24, 2012 at 10:01

      Good to hear. The rotary encoder code is so simple, there is not much that can go wrong in the s/w side. Enjoy!

  7. David Quayle
    March 17, 2013 at 08:11

    I have managed to get the rotary part of the encoder to work but believe it or not I cannot get the switch part to work, I have checked everything, the pin goes low when pressed but the code just ignores it. I have implemented it’s function via the remote but I would really like to get the switch working to free up the remote keys.

    any ideas?

    The codes the same as yours or at least as far as I can tell it is, I have a program that compare files to check it with, looks the same.

    • BlgGear
      March 19, 2013 at 23:08

      Comment out the switch debounce code and try.

  8. David Quayle
    March 20, 2013 at 10:20

    I’ve tried that & every other thing known to man 🙂 I have tested the pin to make sure it goes low when the button is pressed, ie multimeter from pin to ground then press button, goes from 5V to 0V. As my code, is basically your code, with DIMDIM’s changes re screen etc & then my bit’s on top, I can only think there is some bit of code somewhere that stops it from working, compiles OK. I’m seriously stumped.

    • BlgGear
      March 20, 2013 at 17:30

      Put some debug code and see if the loop ever enters that part of the code

  9. David Quayle
    March 21, 2013 at 11:57

    I found the problem, after hours of torture it turned out to be a } that was causing the issue. It would compile fine but was stopping that part of the code working, thanks for helping. Once you have looked at the code for a long time you cant see the woods for the trees.

    • BlgGear
      March 21, 2013 at 15:59

      Glad you are “enjoying” the s/w side of audio 🙂

  10. Haris
    August 20, 2015 at 19:35

    hi,
    How many pulses arduino uno can handle per second easily from quadrature encoder?
    if want to read about 1k pulses /sec what changes should be made in code ?

  11. September 14, 2016 at 19:01

    Louboutin femme

  1. August 4, 2016 at 19:00

Leave a comment