Rotary encoder pulses and detents, and interrupts vs polling - Page 1
Forum section: electronics / beginners

author: Peabody
author_rank: Super Contributor
timestamp: January 28, 2018, 12:41:56 am
content: The typical incremental quadrature rotary encoder may have the same number of pulses as detents (i.e. - 30/30), or half as many pulses as detents (15/30). A "pulse" is defined as a complete cycle of both switches from one state to the opposite state and back to the original state. I want to make sure I understand how these different types affect things, and how you would decide which one to use in a particular application.My understanding is that both types of encoders produce one "tick" per detent, and it's either incrementing or decrementing depending on the direction of turning. But it seems to me that the 15/30 type imposes only half the processing load of the 30/30 type. You would only need to service half as many interrupts, or poll half as often, to process a given turning pattern. The 30/30 type has to process two complete changes of state per detent, whereas the 15/30 only has to process one. And as far as i can see, the processing routines are of similar length. Does that sound right?The major disadvantage of a 15/30 type is that half the time on average the encoder will end up at a detent at which both switches are closed, and current will be flowing through both pullup resistors even though the encoder is idle. The 30/30 type always has open switches at a detent, so current flows only when it's being turned.As for switch-triggered interrupts versus timer-based interrupt polling, I have found polling to be very simple to program, requires no debouncing either in hardware or software, and is pretty much foolproof. However, you'd be polling at something like 500 times a second (maybe less) whether anything is happening or not. So it would kinda depend on what else is going on, and whether you need to, or could, poll or process other things while you're at it.Is my thinking right on all this or not? Any other factors I haven't considered?

author: phil from seattle
author_rank: Super Contributor
timestamp: January 28, 2018, 02:27:14 am
content: It's all about tradeoffs. A series of randomly organized thoughts about quad encoder input:- If this is for user input, the speed is not that important. If you can debounce and determine direction in 50 mS, the user will perceive that as instantaneous. I'd bet even 100 mS would be acceptable.- Interrupts directly from the switches without some form of HW fltering or debouncing are not a good idea as you could get a large number of interrupts from bouncing contacts. If you have a dso, take a look at the contact bounce to get a good sense of how nasty it is.- Polling at a 2 mS period (500 hz as you mentioned) is faster than needed. You will probably need at least 10 to 20 mS for the contacts to settle down. I typically use a 40 mS debounce period with no loss of responsiveness. I will poll at 100 - 125 hz and a string of 4 consecutive readings the same means the switch is made or broken.- Timer interrupts are a great way to poll switches.On the pullups, if power consumption is an issue, try 100K. At 3.3V that's 66 uA. While not 0, it's not going to drain batteries anytime soon.

author: frozenfrogz
author_rank: Frequent Contributor
timestamp: January 28, 2018, 02:36:21 am
content: I would like to recommend the very comprehensive write up by Ben Buxtonon dealing with rotary encoders.

author: Wimberleytech
author_rank: Super Contributor
timestamp: January 28, 2018, 02:57:56 am
content: Quote from: Peabody on January 28, 2018, 12:41:56 amOK, I read this about four times, so let me take a stab at it. See if I can make it worse...or hopefully...better.Detents are mechanical points of stability. They have nothing to do with the waveforms.I think you are right that the 30/30 case that causes the switch to rest in an "open" position is better.I dont think the software is any different between the two cases.Last year, I implemented a hardware interface to a rotary switch because I did not want the software to have to deal with it. It is just a D flip flop. The DFF has no idea where the detents are. Could be hundreds per cycle.

author: sleemanj
author_rank: Super Contributor
timestamp: January 28, 2018, 05:02:55 am
content: My preferred means for handling encoders is a lookup table....http://makeatronics.blogspot.co.nz/2013/02/efficiently-reading-quadrature-with.htmlit is efficient and simple, can be trivially written as a pin change interrupt handler, two discrete isrs, or polling, and both invalid states and no-change are zero.As for detents and pulses it all depends on definitions. On at least the mechanical rotary encoder's I am familiar with, you get 4 edges per detent, looking at a single channel it's 1 pulse per detent, or two channels and it's 2 pulses per detent. That there are 4 edges means you essentially have 4 counts per detent.

author: Peabody
author_rank: Super Contributor
timestamp: January 28, 2018, 07:15:52 pm
content: Quote from: phil from seattle on January 28, 2018, 02:27:14 amMy approach to polling an encoder is completely different, and doesn't ever wait for a switch to settle. I operate on the assumption that the switches will never be bouncing at the same time. Now I accept the possibility that the assumption may not be true for crappy encoders, or for any encoder if it's turned fast enough. But looking at the datasheet for a typical Bourns encoder that I like, it specs the maximum rotation rate at 60 RPM, or one full revolution per second. For a 30/30 type encoder, that's 120 edges per revolution, or one every 8ms. For a 15/30 encoder, you would have 16ms between edges, so it would be even more unlikely to have concurrent bouncing. They also spec the maximum bounce duration at 2ms, but that's with an unknown amount of R/C hardware debouncing. In any case, in the examples I know of where a polling method similar to mine has been used, based on the assumption, it has worked quite well. So I think the assumption is pretty realistic for decent encoders and reasonable spin rates. And, you know, if both switches ever do bounce at the same time, you're going to be in trouble no matter what servicing routine you use.So here is the routine I like for polling. It's not code as such, just the logic.Assume:-------Switch bits are adjacent bits in I/O port.Right-most (LS) bit changes first on CW rotation.Setup:------Target = 00bRead & mask switch state bits, save as CurrentIf Current = 00b then Target = 11bSet up timer interrupt at 500 per second (2 mSec) or whatever worksEnd of SetupTimer Interrupt Service Routine:--------------------------------Copy Current to PreviousRead & mask switch state bits, save as CurrentIf Current = TargetTarget = Target XOR 11bDirection = Current XOR Previous // 10b = CW, 01b = CCWProcess one tick for that DirectionReturnElseReturnNote: For 30/30 type encoder, process only when both go high:Target = Target XOR 11bIf Target = 11b then Return // add this lineDirection = ... etc.For a 15/30 type encoder starting with both bits high, on each interrupt the routine saves the most recent state in Previous, then reads the new Current state. But it doesn't do anything else until the first time both switches are low (the Target it's looking for is 00b). So it takes no further action when the first switch goes low, and bounces, but only continues to save the current value each time until the the first reading when the second switch goes low. When that happens it immediately changes the Target to 11b, and then it processes one tick as per the Direction value based on which switch was the last to go low.The second switch will continue to bounce for a while after this, but Current readings will never match the new Target of 11b because the first switch is already settled low during that bouncing, hence a Current reading of 11b is not possible no matter what the second switch does.Continuing, it will not react to the first switch going back high, or bouncing then, because the second switch has now already settled low. It is only when the second switch first goes high that both are high, whereupon the routine again moves the goalposts by inverting the target to 00b, then processes the new tick. So basically, the routine records a tick on the FIRST reading when both switches are in the same state, but instead of doing any formal debouncing, it just looks forward for the next state which will result in a tick.As stated before, this all depends on the two switches never bouncing at the same time - when one switch is changing state and bouncing, the other must have already settled. I have found that this works quite well.QuoteHow about this: Don't tie the pullups high, but connect them to a spare I/O pin. Then bring that pin high at the beginning of the polling interrupt service routine, take the switches reading, then take it back low before you return. You only use current when you're reading the switch pins. There shouldn't be any bounce associated with doing that. What do you think?Edit: You would probably just use the internal pullup resistors on the pins the switches are connected to. For a processor which also has pull-down resistors, you would just change between pulldown and pullup when reading the pins. If there are no internal pulldowns, you could still change the pin from output-low to input-with-pullup. You just can't have a floating input when a switch is open.

author: chris_leyson
author_rank: Super Contributor
timestamp: January 28, 2018, 07:54:35 pm
content: I'm with sleemanj on this one, I use pin change interrupt and state table lookup method and it's fast and bullet proof.https://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino/Also a post from jonnyfp herehttps://www.eevblog.com/forum/projects/hardware-debouncing-a-rotary-encoder/I too have used Oleg Mazurovs Arduino code and modified it for PIC24, you really can't go wrong with the state table method.

author: Peabody
author_rank: Super Contributor
timestamp: January 29, 2018, 12:18:17 am
content: Quote from: chris_leyson on January 28, 2018, 07:54:35 pmI have studied the state table method, and I have reservations about how it works, and don't think it is foolproof. The basic problem is that it cannot distinguish a real reversal of direction from bounce noise. Take the case of both switches being high, then one goes low, and the lookup table says going from 11 to 01 is one CW tick. But then that switch bounces for a bit, and during the bouncing it goes back high, and another reading takes place at that point. The table will say that going from 01 back to 11 is a legitimate CCW tick, but in fact it's just noise.My routine will ignore the noise, and will recognize only a full transition from 11 to 00 as a tick, and will determine the direction from the current and previous states at that time. Also, the lookup table method produces an event at every transition of either switch, so that for a 15/30 type encoder you will get two increments or decrements per detent, and for a 30/30, four per detent, which will have to be divided down to one. With my routine, you get one change per detent.I know that Oleg's lookup table method is the one most people use, but I like mine better, and think it produces better results, at least for polling. I'm dealing right now with the DSO150 kit scope from JYETech. It has a 15/30 rotary encoder, and it doesn't work very well. They poll using the lookup table method, and continue to try to improve it with every new firmware release, but really, it still doesn't work very well. You move the encoder through one click, and nothing happens, or you get a change of two, or even a reversal. And at higher speed, it eventually gets you there, but only the general direction over time is predictable. So no, it's not foolproof.

author: cowasaki
author_rank: Frequent Contributor
timestamp: January 29, 2018, 12:28:11 am
content: I used a rotary encoder with a push shaft switch as an input device on my last product with a matching 10K linear pot as the menu position selector (so to the user they looked that same). The combination of the two worked well but I went through a few to find the best one for the job. Little things like the size of the knob on top make a big difference. Personally I'd get some samples and have a play.