Interrupts and encoders  - Page 1
Forum section: electronics / general

author: Unknown
author_rank: Unknown
timestamp: January 07, 2013, 12:19:19 am
content: I am trying to get a Arduino project up and running. I did not have the interrupts because the program was small enough where it did not matter. Now I am looking to expand so I attached them as interrupts and the encoders are not working anymore. do they require hardware debounceing?

author: nctnico
author_rank: Super Contributor
timestamp: January 07, 2013, 12:43:32 am
content: Yes. Its better to use a timer interrupt to read the encoder inputs at a specific interval. Perhaps do some filtering in software as well (for example: input low/high for at least 3 interrupt periods).

author: mazurov
author_rank: Frequent Contributor
timestamp: January 07, 2013, 04:03:55 am
content: Here's a couple of articles from my blog about reading rotary encoders with Arduino using lookup table method. This method does not require debouncing. Both polling and interrupt are demonstrated:http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduinohttp://www.circuitsathome.com/mcu/rotary-encoder-interrupt-service-routine-for-avr-micros

author: Teemo
author_rank: Regular Contributor
timestamp: January 09, 2013, 05:13:56 pm
content: It seems logical to me to use "interrupt on change" to read encoder, instead of timer interrupt.

author: mamalala
author_rank: Unknown
timestamp: January 09, 2013, 06:09:32 pm
content: Quote from: Teemo on January 09, 2013, 05:13:56 pmThe problem is a lack of debouncing. The IRQ will trigger several times due to contact bouncing. It makes the routine more complex, and thus more time consuming. Using a timer IRQ is simpler.Greetings,Chris

author: Kremmen
author_rank: Super Contributor
timestamp: January 09, 2013, 06:46:43 pm
content: Nah, let it bounce. Quad encoders are trivial to read from an interrupt routine. The bouncing doesn't matter provided you can catch all bounces. Usually it is easy as contacts bounce in the millisecond range.If you don't need all of the encoder resolution, then just interrupt from changes in one channel, otherwise both. Say your ISR is bound to changes in channel A. Now you have 2 alternatives, either A reads high or it reads low. You know it transitioned into that state so now you know the direction of the A edge that triggered. Next read B channel. The rest is just decoding the transition from the combination of current states and the last change (which you can deduce - it need not and should not be stored).If the contact bounces you either don't see it at all (if the non-interrupting channel bounces) or you see a series of up-down changes in the interrupting channel. That decodes as back-and-forth motion but not constant motion in one direction. If your application can't tolerate that then there are a number of easy solutions depending on how the encoder works in detail. Many cheap encoders have a detent for a complete cycle, (i.e. 4 transitions in the signals). It is easy to follow the cycle and only indicate change of position when the encoder is in the final step of the cycle. If it dithers there, no matter. And you can come up with other means to "debounce" the count depending on what you need.

author: Teemo
author_rank: Regular Contributor
timestamp: January 09, 2013, 07:21:37 pm
content: Bouncing does not matter, if you toggle the "interrupt on change" to other channel at every interrupt. Direction of the turn can be read by the other channel state (the channel that did not cause the interrupt). That's what I'm thinking.

author: Bored@Work
author_rank: Super Contributor
timestamp: January 09, 2013, 07:39:23 pm
content: The bouncing eats away CPU power, because of the unnecessary triggering of interrupts which the CPU then needs to process.And since bouncing can get worse over time you can end up with an application that starts to act strange with aging encoders, while it worked "perfectly" on the developer's bench.Debouncing, independence of how a Gray code is read, is implicit part of the Gray code decoding - if the decoding is done rigth.

author: Kremmen
author_rank: Super Contributor
timestamp: January 09, 2013, 10:18:52 pm
content: (De)bouncing should only be relevant to mechanical contacts and the frequency will hardly matter to any "real" MCU. It can freely bounce at ~1kHz forever and won't cause any real CPU load if the ISR is written even half competently. Well of course that depends on how high the basic load is but anway.Optical encoders with real resolution don't bounce so there you don't have this problem at all. Of course you probably will do the counting hardware assisted anyway.At least this is my experience and how i have always done it.

author: nctnico
author_rank: Super Contributor
timestamp: January 09, 2013, 11:32:57 pm
content: Quote from: Bored@Work on January 09, 2013, 07:39:23 pmThe golden rule is to only allow interrupts from signals with a known interval even in fault conditions.One of my fellow engineers once used an interrupt on a pin connected to several meters of wire for a doorbell. The pin was not filtered at all; just a pull-up to 3.3V. The device turned out to be very unstable and we couldn't figure out why until at some point we connected some other hardware to the pin that kept it at a level which caused the pin to oscillate between logic levels. The device came to a grinding halt.What you often see in resistive touch-screen drivers is that they use an interrupt to start the polling when the screen is touched and stop with polling when the screen is no longer touched.

author: Psi
author_rank: Super Contributor
timestamp: January 09, 2013, 11:58:57 pm
content: +1 for using a timer interrupt.I always use one of the hardware timers and split it into as many slower clocks as i need.eghttp://www.eevblog.com/wiki/index.php?title=Embedded_Programming_Tips_and_Tricks_for_Beginners#Repeating_Code_Using_Timer_Overflow_Interrupts

author: Teemo
author_rank: Regular Contributor
timestamp: January 10, 2013, 01:08:26 am
content: I mean, if to use pin change interrupts, then the first thing the interrupt routine must do is disable further interrupts from that pin. This avoids interrupts from contact bouncing. Then it should be fine, I guess.

author: ve7xen
author_rank: Super Contributor
timestamp: January 10, 2013, 02:56:30 am
content: Quote from: Teemo on January 10, 2013, 01:08:26 amOnly if your interrupt handler runs for milliseconds. Or you come up with some timer to re-enable them after a while. Lots of approaches but periodic polling is the simplest and most reliable.

author: jahonen
author_rank: Super Contributor
timestamp: January 10, 2013, 08:09:36 am
content: While an optical encoder does not bounce, it can be stopped just to the edge of the transition where it can produce lot of transitions, which can cause too high interrupt load.Regards,Janne

author: Kremmen
author_rank: Super Contributor
timestamp: January 10, 2013, 08:39:30 am
content: Quote from: ve7xen on January 10, 2013, 02:56:30 amBut i am trying to tell you that it may not be the simplest. Nor necessarily the most reliable either. It all depends i guess. If the structure of your program is "trivial", say one simple loop where you do simple sequential things then maybe yes, reading an encoder might be straightforward to insert into that loop. Still that begs the question how do you then debounce the contacts in that loop? Unless you assume/know the maximum frequency for the pulses, you risk missing transitions if the loop is too slow. And it gets more complicated if your code is not just a simple loop. It is all doable of course but my viewpoint is that only the dedicated interrupt method stays the same in every environment. The debouncing does not create any extra overhead for the interrupt method, because you either must do it or not, regardless of the way you capture the state transitions.Quote from: Psi on January 09, 2013, 11:58:57 pmAs do we all. That is the basic method of scheduling since dawn of time. You either do it explicitly in your code or then implicitly using an OS that embeds the timing inside the kernel. If all of your code is inside one of the timed loops then 2 things follow:1. You can only react to external events as fast as the fastest loop permits.2. The amount of code you can run depends on and is limited by the absolute values of your timer loops and how the amount of code is divided between them. The faster the loop, obviously the less code you can run in it before overwhelming the MCU.If the application is anything but trivial you should (or at least I do) run tasks like the human interface on the idle loop, outside the timed code. Of course you can still run your encoder input in a timer loop but i don't do it like that because i don't want issue #1 above in my code.My design principle is to run non-time critical code in the idle loop, time deterministic code such as various DSP algorithms, in the timing loops or similar, and finally capture external asynchronous events by interrupt handlers. This principle is easily implemented by using a simple operating system such as FreeRTOS, just to mention one. The overhead is reasonable and some MCUs even support task switching in the register architecture making it even more a no-brainer.Quote from: nctnico on January 09, 2013, 11:32:57 pmSome of that makes sense but doesn't really change my point. I can only suggest that if a thing like simple contact bounce or interference gets totally out of hand then maybe some physical signal conditioning is indicated. The bounce does not go away just because you use a different method of inputting it, although i grant you would want an uncontrollable burst of interrupts even less. For some reason i have never had that problem but then i tend to design defensively.The touch screen driver idea makes sense, because the initial detection delay is most likely imperceptible to a human user. I didn't guite get the point of the Gray decoding however. A Gray encoder just ensures that only one signal at a time changes but that in itself has nothing to do with contact bounce. A bouncing Gray signal results in exactly the same up-down dither as a bouncing quad encoder. The idea of Gray code is that since only one signal changes at a time, you will never get an incorrect transient state due to signals changing at different instants.Quote from: jahonen on January 10, 2013, 08:09:36 amA point, but depends on what load is too big. To produce the transitions the encoder shaft has to oscillate physically. You may find a system somewhere where the mechanical resonance frequency of the system is in the high kHz but i haven't yet. Anything significantly lower and you can just live with it. "Real" optical encoders that are used for say positioning in a numerically controlled machine have far too much pulses per rev anyway to be readable by channel interrupts, and definitely not by timer loops or anything like that. In practice they are always hardware assisted so the problem kinda goes away.In the end this question to me is not unlike the question of handling any peripheral device, embedded or external. Nobody bats an eyelid at handling a thing like say USART or SPI or indeed, a timer, in an ISR. To me an external event is more of the same. Granted, there (too) are EMI issues and randomness, but those can and should be handled, not forgotten.As they say, this is just my 2c worth. If it does not work for you, then you must do whatever floats your boat. I am not saying my opinion is engraved in stone either. There might be circumstances where i would see things differently, but not quite yet.