Hardware debouncing a rotary encoder - Page 1
Forum section: electronics / projects

author: Chris.M
author_rank: Contributor
timestamp: June 13, 2012, 02:09:31 pm
content: Hello All,I'm trying to hardware debounce a rotary encoder, where the bounce occurs when the encoder is turned fairly fast.The encoder that I have is fromhttp://australianrobotics.com.au/products/rotary-encoder,however it appears to be a generic rotary encoder.I have tried an RC low pass filter, however I cannot get it to remove enough of the bounce. Perhaps I need to use something else other than a filter, or I may not be using the right resistor capacitor combination.I have included some images to show what the bounce looks like.Image 1 is a zoom-in of the bouncing.Image 2 is the zoom-in as image 1 but has the desired outline of the output in red.Image 3 and 4 show more of the bouncing when zoomed-out.Thanks,Chris

author: mukymuk
author_rank: Contributor
timestamp: June 13, 2012, 02:18:13 pm
content: I worked on a design a few years ago with something that behaved very much like that. Debouncing had to be done digitally. I didn't use any analog filtering. The algorithm basically looked for an edge followed by a "stable" signal level. The bottom line is that you can only turn them so fast before you start missing states. That's just how they work.I happened to have an fpga on the board and ended up putting the logic in it because it was so time consuming to do in the micro.

author: free_electron
author_rank: Super Contributor
timestamp: June 13, 2012, 04:24:32 pm
content: wow.. that's one hell of a dirty encoder....it looks like you only have the bounce ( or most of it ) when switchin to ground. notice how there is no 'bounce' when the signal is high ?are you switching 'high' with the encoder ? ( meaning the common isconnected to vcc )here is typically what i use to debounceencoder common to ground.. encoder channel via 10 k to vcc. capacitor of 100nF from encoder out to ground.the output goed to a schmittrigger like a 74hc14.if there is 'long bounce to ground' the capacitor will simply discharge again and the schmittrigger will never trip. if there is bounc the other way ( short bounce to ground ) and the schmittrigger has tripped , the capacitor will not discarge enough to trip the schmittrigger again.oh, forgot one thing , i put 2k2 from the encoder pin to the cap..wait... let me draw schematic...Code:vcc --+---------+-----------------| |10k 10k ______| | | __ || +-----| _// |O--- A| | |______|| | | __ |+---------|-----| _// |O--- B| | |______|| | ______| | / \| +------|-O O- || | | +----+----------------|-O O- | || | \______/ |_|_ _|_ |--- --- || | |gnd---+---------+-----------------------+---i switch ground because the schmittriggers invert it back.the additional 2k2 avoids hard shorting the capacitor (this would cause glitches again...) you can play with the 2k2 and make it 3k3 for example. you need to take a look where the trigger levels are in the schmittrigger. and tune the 2k2 so that you can get below the lower level ( the 10k and 2k2 form a voltage divider ) . you will always be able to get to VCC , it's the lower level you need to worry about.for slow turning (like fornt panel) you can alter this schematic:Code:vcc --+---------+-----------------| |2k2 2k2 ______| | | __ || +---------+--| _// |O--- A| | | |______|| | | | __ |+---------|---+--------| _// |O--- B| | | | |______|| | | | ______| | | | / \| +-----------------|-O O- || | | | +----+---------------------------|-O O- | || | \______/ |_|_ _|_ |--- --- || | |gnd----------------------+-----+--------------+-- -now the capacitor needs both charging and discharging throught the 10k... ( it charges with 10k+2k2 and discharges with 10k only )so this recreates a nice waveform. note thatifyou start turning fast the encoder will simply stop working.. both outputs remain low. ( assuming a full cycle per detent encoder lke you have )so , to decode this : tie one output to an interrupt pin. when the interrupt comes , sample the other pin. high meansleft ,low means right ( or vice versa )

author: johnnyfp
author_rank: Frequent Contributor
timestamp: June 13, 2012, 11:49:42 pm
content: Do it in Code. Saves on components.I found this great snippet of code that works really well. This is based on Arduino, but I'm modified mine to work in PIC.http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino/comment-page-1#comments.The pic code looks likeCode:const static int enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};static unsigned char old_SW4 = 0;char SW4Pos=0;signed char processRotary(char lowBitMask,char lowShift,char hiBitMask,char hiShift,unsigned char* oldVal,unsigned char* newVal,char portRead) {signed char encState;*oldVal <<= 2;*oldVal |= (portRead&lowBitMask)>>lowShift|(portRead&hiBitMask)>>hiShift;encState = ( enc_states[( *oldVal & 0x0f )]);if ((*newVal>=(char)DECSTEP)&& encState==INCSTEP) *newVal=MAXPWM;else if ((*newVal<=INCSTEP) && encState==DECSTEP) *newVal=MINPWM;else *newVal += encState;if (*newVal<MINPWM) *newVal=MINPWM;return encState;}signed char read_encoder_1(){int encReturnState=0;portaRead = PORTA;encReturnState |= processRotary(0b00001000,3,0b00100000,4,&old_SW4,&SW4Pos,portaRead,0)!=0;return encReturnState;}Obviously adapt it to your ports.Jfp

author: poorchava
author_rank: Super Contributor
timestamp: June 14, 2012, 01:12:44 pm
content: I would do as free electron says - use some form of lowpass filter (either RC or LC) and 7414 ttl chip. You only need to calculate values so that you don't skip pulses when turning encoder quickly.

author: free_electron
author_rank: Super Contributor
timestamp: June 14, 2012, 01:33:26 pm
content: Quote from: johnnyfp on June 13, 2012, 11:49:42 pmTheres two problems with that code.1) it only works for a gray code encoder. Ts has a full cycle per detent.... That is different.2) you need to spend an absurd amount of processing power at polling the encoder.Olling is not the way to go... Use interrupt driven systems.

author: Rufus
author_rank: Super Contributor
timestamp: June 14, 2012, 01:45:55 pm
content: Quote from: Chris.M on June 13, 2012, 02:09:31 pmA cheap crap mechanical switch encoder that can't track at what looks like 2500 rpm, what did you expect?

author: free_electron
author_rank: Super Contributor
timestamp: June 14, 2012, 05:00:58 pm
content: holy bimbam, now that i look at the timebase of the scope.. 3ms for a cycle. that 300 detents a second ... times 60 seconds... that 18000 detents a second . assuming a 12 detent encoder that is wel over 1000 RPM.... that ain;t gonna fly...theis kind of encoder is made for hand operation by humans on frontpanels.... if you want to use this for motor applications it will die in 10 seconds flat... such encoders are only good for 100.000 cyclesget an optical one...

author: johnmx
author_rank: Frequent Contributor
timestamp: June 14, 2012, 08:03:51 pm
content: Check the encoder maximum operating speed. They don’t work above that limit.Mechanical rotary encoders are rubbish.At work, I have been using magnetic encoders (model: EM11B) for my prototypes, but they cost 25€ each. Ouchh! Yeahh, not for every pocket. But in my case this is only a penny compared to the typical final prototype cost of 1k€ to 10k€.free_electron said it all: “get an optical one...”

author: Chris.M
author_rank: Contributor
timestamp: June 14, 2012, 11:30:06 pm
content: Thanks for the replies.I want to run a few more experiments before I post the results, however I have taken the suggestions from the posts above and have been experimenting with different low pass filters and code to see what debouncing results I can achieve.It seems I'm almost there with a combination of a low pass filter, gray code decoding and a hex inverting schmitt-trigger.As free_electron has pointed out, I am turning the encoder much faster than it was probably designed for.Looking at other mechanical rotary encoders that are approximately double the price, they have a max of 60rpm. The encoder is being turned by hand, which is connected to an micro-controller that updates a 4-digit 7-segment display. However, when turning it very fast, I noticed that detents were being missed.I can see that I'm turning the encoder much faster than it's designed to handle and this would not be how it would be turned in everyday use, however if someone were to turn the encoder really fast, skipping pulses is not a desirable thing from a user interface perspective.Thus, my aim is to see if I can clean-up the bounces and it seems together with gray code decoding, see if I can catch these skipped pulses.Quote from: free_electron on June 14, 2012, 05:00:58 pmYes, an optical encoder would solve the bouncing problem altogether. They seem rather expensive though, from a hobby perspective.A 100rpm, which is still slower than the 300rpm I posted in the waveform in my first post is approximately $19. A little hefty huh...Can anyone suggest a relatively cheaper optical encoder?

author: Chris.M
author_rank: Contributor
timestamp: June 14, 2012, 11:36:08 pm
content: Putting the mechanical encoder aside and the fact that this is the bouncing produced by cheaper ones,is anyone able to comment on what the limiting factor is, to filter out the bouncing frequency?Is it achievable using filters? Are the pulses too short to drown out the given frequencies?Are there other mechanisms that can be used?

author: amspire
author_rank: Super Contributor
timestamp: June 15, 2012, 01:09:35 am
content: If this is a one off project, then instead of a knob and rotary encoder, you could salvage the wheel from a mouse. They seem far more reliable then most rotary encoders. I just wish the rotary encoder manufacturers would talk to mouse manufacturers, as the mouse manufacturers have had totally reliable encoders for well over 20 years. Why are there rotary encoders on the market with lives of the order of 20,000 rotations when the encoders in an old ball-type mouse can easily do millions of rotations without any problem? Not sure if the wheel in a modern mouse is optical or contact, but they are also very reliable.Richard.

author: ivan747
author_rank: Super Contributor
timestamp: June 15, 2012, 02:12:15 am
content: So they have a max speed. That's why 2000's Volkswagen's radio volume encoders actually increased volume when the volume was turned down too fast.

author: DrGeoff
author_rank: Frequent Contributor
timestamp: June 15, 2012, 02:30:11 am
content: MC14490 might be worth looking at.http://www.onsemi.com/PowerSolutions/product.do?id=MC14490

author: Mechatrommer
author_rank: Super Contributor
timestamp: June 15, 2012, 07:17:02 am
content: Quotei did that and encoded with pic10f200... 100rpm maxed with my code. maybe an arm (cortex M3) will do the 1000rpm. i hope those kind of mouse still around. i think i want to open recycling shop to collect those. nonsensical expensive for that little optical encoder alone in ebay or something.

author: amyk
author_rank: Super Contributor
timestamp: June 15, 2012, 08:41:42 am
content: Quote from: amspire on June 15, 2012, 01:09:35 amAll the ones I've seen are optical. Mechanical would probably have friction problems with the ball. However they're nothing more than a phototransistor-LED arrangement with a slotted wheel, no housing.

author: Chris.M
author_rank: Contributor
timestamp: June 15, 2012, 01:43:02 pm
content: It looks like the best combination for the low pass filter was a 10K pull-up with a 10n cap and a 2k discharge resistor.The output of the low pass filter was then passed into a hex inverting schmitt-trigger, and the output of the schmitt-trigger into the micro-controller.The circuit is the same was what free_electron suggested, however I found it better to take the schmitt-trigger input from the rotary encoder output directly:vcc --+---------+-----------------| |10k 10k ______| | | __ || | ------| _//--- A| | | |______|| | | | __ || | | ---| _//--- B| | | | |______|| | | | ______| | | | / \| +----|--+-|-O O- || | | | +----+--------------+----|-O O- | || | \______/ |_|_ _|_ |--- 10n --- 10n || | |gnd---+---------+-------------------------+---In addition, I used the gray code decoding algorithm linked by johnnyfp:http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino/comment-page-1#commentsand adapted it so the states wereCode:enc_states[] = {0,0,0,0,1,0,0,-1,0,0,0,0,0,0,0,0};This way if a 0-to-1 or 1-to-0 transition is missed for what ever reason (bouncing caused by turning the encoder to fast), then the remaining transitions until the next detent are skipped. The code was placed in an interrupt service routine as suggested by free_electron. There is a follow on article from the link above that shows how the interrupt service routine can be used to read the rotary encoder:http://www.circuitsathome.com/mcu/rotary-encoder-interrupt-service-routine-for-avr-microsThe resulting wave form is shown below in the images.Image 1 is a zoom in of the remaining bouncing.Image 2 is zoomed out.

author: Chris.M
author_rank: Contributor
timestamp: June 15, 2012, 02:09:50 pm
content: Quote from: free_electron on June 13, 2012, 04:24:32 pmThanks for the circuit free_electron. I had a little trouble understanding why you took the schmitt trigger input from the 10k resistor side, rather than directly from the rotary encoder. What is the significance of the voltage divider that it creates? From my experiment, it looked like the "floor voltage" was slightly raised above 0v.Quote from: johnnyfp on June 13, 2012, 11:49:42 pmThanks for the link johnnyfp.Quote from: DrGeoff on June 15, 2012, 02:30:11 amThanks for the suggestion DrGeoff. I will look into whether the chip would help eliminate bouncing that doesn't settle.Quote from: amspire on June 15, 2012, 01:09:35 amQuote from: amyk on June 15, 2012, 08:41:42 amIt looks like an optical encoder from a mouse might be a viable alternative to these cheap rotary encoders. I will look into this some more when I have time. Thanks for the idea.

author: free_electron
author_rank: Super Contributor
timestamp: June 15, 2012, 03:52:45 pm
content: it's not the voltage divider.. it is preventing a hard short of the capacitor ... when the encoder switch closes this would still create bounce on one side ( towards ground ) now there is a resistor in series.... so the cap can only gradually charge and discharge...if you short the cap you can only gradually charge , but discharge is hard and can stll bounce that way ( bounce happens both ways ... having a seires resitance averages it out.)the levels don't matter : the schmittrigger cleans those back up to logic levels.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: June 15, 2012, 04:09:00 pm
content: I've fount that a little external RC filtering as above can generally get bounce time up to the point where it can be dealt with more easily in software.

author: hlavac
author_rank: Frequent Contributor
timestamp: June 15, 2012, 04:55:40 pm
content: Quote from: free_electron on June 15, 2012, 03:52:45 pmHow? The cap is discharged hard when the contact is first made, even if thecontact bounces off the cap remains discharged, it can't bounce back! Only way the logic level can go back is back up through the schmitt trigger hysteresis window, and that is through the slow charging thru the resistor pullup. That will not bounce.I think the series resistors are more important for different reason - to avoid high current spikes through the contacts that could wear them off.

author: free_electron
author_rank: Super Contributor
timestamp: June 15, 2012, 05:56:12 pm
content: lets say the switch is opening. it has been open for quite a while and the capacitor has charged to pierce the top level of the schmittrigger. now there is a very short glitch to ground ... you immediately pierce the bottom level of the schmittrigger. if the resistor is there you cannot pull the cap charge hard to ground. it takes tame so the glitch will fall inside the schittrigger window and will be rejected. no harm done.Now, there's other things to consider. This stuff all works very well with cmos logic. Try this with true ttl ( so bipolar construction ) and you get other effects..the input of a TTL chip is actually not an 'input'.. it is an output , in the sense that you can pull current out of the input. a TTL gate can actually supply 2 to 3 milliampere on its input. the input stage of a ttl chip is actually the emitter of a transistor. the base goes via 220 to 300 ohm to vcc. the collector disappears inside the chip.So the input of a ttl chip , if shorted to ground will supply you with 2 to 3 mA. ( this is where fan-out comes from... the output of a ttl chip can only sink 20 to 25 mA. connect 10 'inputs' and you are looking at sinking 20 to 30 mA ... connect more inputs and you have trouble since the output can't handle that current !this screws up debouncing circuitry. if a schematic shows a HC or HCT chip , you cannot just slap in a 74 or 74LS or 74F the cmos parts provide no current on their input since you are steering a gate. the bipolar parts provide current !

author: Chris.M
author_rank: Contributor
timestamp: June 16, 2012, 01:56:27 am
content: Quote from: free_electron on June 15, 2012, 03:52:45 pmThanks for the explanation free_electron. I can see how the 2k resistor helps create a slower discharge, preventing the hard short.Part of what I am also trying to figure out is if it matters where you take the schmitt-trigger input from? From the voltage divider or the encoder pin? Does it make a difference? I can't really see any differences from the scope output.Quote from: mikeselectricstuff on June 15, 2012, 04:09:00 pmYes, my experiments are showing the same thing. The RC filtering removes a great deal of the bounce, enough so that the schmitt-trigger produces the correct output, and the gray code decoding deals with whatever remaining glitches get through.

author: Chris.M
author_rank: Contributor
timestamp: June 16, 2012, 02:06:37 am
content: I have found that the bounce can be reduced further by changing the 2k resistor to a 180ohm resistor and using a 22n capacitorvcc --+---------+-----------------| |10k 10k ______| | | __ || +-----| _//--- A| | |______|| | | __ |+---------|-----| _//--- B| | |______|| | ______| | / \| +------|-O O- || | | +----+----------------|-O O- | || | \______/ |_|_ _|_ |--- 22n --- 22n || | |gnd---+---------+-----------------------+---The images of the output are below.This RC and schmit-trigger combination looks to be working 99% of the time. The gray code decoding sorts the other 1%. I'm quite happy with that.

author: Chris.M
author_rank: Contributor
timestamp: June 16, 2012, 02:11:54 am
content: Quote from: free_electron on June 15, 2012, 05:56:12 pmI was not aware of this. I am using a cmos hex inverting schmitt-trigger so I should not have this problem.

author: IanB
author_rank: Super Contributor
timestamp: June 16, 2012, 05:00:42 pm
content: Quote from: amspire on June 15, 2012, 01:09:35 amNow there's an age test. Does anyone remember what a "mouse ball" is these days?

author: T4P
author_rank: Super Contributor
timestamp: June 16, 2012, 06:16:47 pm
content: Quote from: IanB on June 16, 2012, 05:00:42 pmOOOH the unreliable rolly goldy days ... The days we would see ball mouses everywhere - in the junkyard

author: Mechatrommer
author_rank: Super Contributor
timestamp: June 17, 2012, 05:42:58 am
content: at least it still can scroll on a nice flat shiny surface? not for my laser mouse here, i have to put some picture on the bottom.and i dont know how to make use of the pattern recognition chip inside in case it decides to be broken.

author: SeanB
author_rank: Super Contributor
timestamp: June 17, 2012, 06:39:04 am
content: I have repaired quite a few mice, most common is a broken cable near the mouse ( funny is the cable can be shortened to about half length before it has to be replaced, and the replacement cables come from old dead mice) and a faulty left button switch. I keep a few dead ball mice as donors for the switches and the cables. Wireless mice most often fail from corroded batteries, this often is terminal, and turns them into switch donors.

author: T4P
author_rank: Super Contributor
timestamp: June 17, 2012, 09:11:05 am
content: Quote from: SeanB on June 17, 2012, 06:39:04 amAnd some wireless mouse fails magically for no reason. (Didn't check, wasn't a EE then)

author: SeanB
author_rank: Super Contributor
timestamp: June 17, 2012, 10:44:37 am
content: Yes, they do just die, generally after a short period of obeying Newton's laws. Often it only manifests itself a while later as intermittent then dead. Often the user will deny that it ever fell, even if it has cracked casings, loose broken bits inside and tape holding it together.

author: Rudolfo
author_rank: Contributor
timestamp: June 18, 2012, 08:29:03 pm
content: Looks like a lot of effort to debounce a mechanical encoder with integrated circuits. Todays magnetic encoder IC just need one chip and one magnet to get clean counting signals or even saw tooth output. You might look for solutions similar to the 8-bit iC-MA (http://www.ichaus.biz/product/iC-MA) or iC-MP (http://www.ichaus.biz/product/iC-MP). Similar solutions are available from other supplier as well. More on single-chip encoder you find here:http://www.ichaus.biz/wp_boost_performance.

author: T4P
author_rank: Super Contributor
timestamp: June 18, 2012, 08:41:23 pm
content: I've seen classic encoders used in tape drives all the time,they have been tried and tested obviously i can't really point you to any of them, but they are based on IR

author: Chris.M
author_rank: Contributor
timestamp: June 19, 2012, 12:20:33 am
content: Quote from: johnmx on June 14, 2012, 08:03:51 pmQuote from: Rudolfo on June 18, 2012, 08:29:03 pmThanks johnmx and Rudolfo for the magnetic encoder suggestions.I could not find the iC-MP located in Australia but I did find a similar chip, the AS5030ATSU.The optical encoders I have found seem to start around the $20 mark, whereas the AS5030ATSU IC is around the $10 mark, but you need to make the housing yourself.Is this a common experience for magnetic encoders, you need to make the housing yourself?These prices are a little steep for a hobbiest application. Has anyone seen a magnetic or optical rotary encoder for $10 or under?

author: SeanB
author_rank: Super Contributor
timestamp: June 19, 2012, 04:37:39 am
content: Pawnshop or cupboard for a old mouse with a ball. Rip apart and use the encoder wheel and the slotted optoswitch to make the 2 signals. Gives the important parts but you have to do a little work on the housing.

author: pdegregorio
author_rank: Newbie
timestamp: April 11, 2014, 04:24:11 pm
content: Quote from: free_electron on June 13, 2012, 04:24:32 pmThanks free_electron for the complete example. I used the circuit for a hand-turned rotary encoder and it appears to work well.

author: kony
author_rank: Regular Contributor
timestamp: April 11, 2014, 05:40:40 pm
content: Just my two cents on this: when constrained on PCB place (although I find myself using it in all cases) it comes handy to use the little logic family, 74LVC2G17 for this case. Not only it is smaller and just about the same in price, it also gives You much nicer PCB layout, too.