Issues using a rotary encoder - Page 1
Forum section: electronics / beginners

author: SamKook
author_rank: Newbie
timestamp: January 14, 2023, 11:19:19 pm
content: I'm not the most knowledgeable with electronics but I can solder and follow along a decently described projects so things usually go fairly well when I build something.This time, I'm trying to build a usb knob that emulates a couple of keyboard keys when turned and noticed later that the part for the rotary encoder the person used is a board with filtering but I just ordered the rotary encoder alone.I tried the rotary encoder alone at first(hadn't realized they used a board version yet) and was getting weird results. The button would switch on its own, possibly because I was using my fingers directly on the metal to turn it and the keys weren't getting pressed at all.After a bit of research, realized they had filtering for it and I didn't so I found the diagram for the board used in the project and tried to recreate it on a breadboard for testing but I don't seem to be getting any input from the rotary encoder at all and I'm stumped for what could be the issue.This is the project I'm trying to create:https://hackaday.io/project/164043-the-infinity-usb-knobThis is the github page with the rotary encoder board schematic I'm trying to recreate:https://github.com/Arduinolibrary/DFRobot_SEN0235_EC11_Rotary_Encoder_ModuleThis is the rotary encoder I got:https://canada.newark.com/bourns/pec11r-4230f-s0024/incremental-encoder-12mm-60rpm/dp/53W9548Here's a picture of the breadboard that's hopefully clear enough: See post attachment, don't know how to add the thumbnail here on this forum.The wires are color coded the same as the original project except that their light blue is my orange.I'm using 47k resistors and a 10uF 63v(local shop didn't have 100v that I usually see with microcontrollers so hopefully 63v is enough). The long lead of the capacitor is on the side of the red wire(which I'm fairly certain is how you do it) since that cap doesn't have a band on the side indicating the negative side.If I plug it in, the ring and the microcontroller lights up as expected from the code, but pushing down on the rotary encoder or turning it(using some Styrofoam so my fingers don't touch it directly) does nothing. Touching it directly with my fingers also doesn't do anything, unlike when there was no filtering.Before I actually found the diagram for the board they used in their project, I tried just finding a filtering diagram for a rotary encoder and saw many different values for them, some even saying the ones from the rotary encoder datasheet didn't work for them which is why I used the values for the board used in the project but that made me wonder, how do you even decide which values to use?Any help would be greatly appreciated and bonus point for answering the question from the previous sentence.

author: ifonlyeverything
author_rank: Regular Contributor
timestamp: January 15, 2023, 12:22:47 am
content: You know the code works on the unfiltered encoder and I'm assuming you can observe the voltage swing up/down on the filtered encoder, as you press the button and rotate it? If so then it's the slow rise/fall times causing an issue. One way to fix this is to use a Schmitt trigger. Another way is to do the filtering in software: a state machine works nicely for the rotation part, and a non-blocking delay for the button press. I used this person's code for the state machinehttps://forum.arduino.cc/t/reading-rotary-encoders-as-a-state-machine/937388and this code for the button presshttps://learn.adafruit.com/make-it-switch/debouncingQuote from: SamKook on January 14, 2023, 11:19:19 pmI noticed the same thing when I was researching debouncing. If you want to do it mathematically would have to take into consideration the number of detents per full revolution of the encoder and the maximum rotation speed which one might 'realistically' use, and then take into consideration the thresholds on the Schmitt trigger... or you can just eyeball the parts and swap out resistors or capacitors as needed to raise or lower the RC time constant, until it performs as you would like it to. Or you can just do the entire thing in software.

author: SamKook
author_rank: Newbie
timestamp: January 15, 2023, 01:30:44 am
content: I tried the unfiltered encoder again to make sure I wasn't messing up something before and I'm getting nothing from rotating it and pushing the button actually shuts off the whole thing while pushed down and it restarts after I release it(forgot it was doing that, been a few months since I last tested it unfiltered and I don't understand why it does).I haven't been monitoring the voltage, my debugging knowledge is very low when it comes to electronics. I've just been plugging it to a computer and looking at the ring light to see if the button works and I'm running a software that catches keyboard keys being presses to see if turning does anything.Not too sure how I'd go about monitoring the voltage other than just shoving my multimeter probes somewhere in the breadboard.

author: ifonlyeverything
author_rank: Regular Contributor
timestamp: January 15, 2023, 02:05:15 am
content: Measure the voltage across ground and each of three encoder pins that are feeding to the MCU. You should see them pulled up to your power rail and then pulled down to ground as you push the button or rotate the switch. What value pull up resistors are you using?

author: SamKook
author_rank: Newbie
timestamp: January 15, 2023, 03:36:01 am
content: I'm seeing voltage fluctuating between roughly 9.5 to 10v at random, turning or pushing the button doesn't seem to have an effect at all.I don't think my breadboard circuit is right with values like that.If I only use 1 red wire that goes between the resistor for the positive pin on the rotary encoder and the cap and one black for the negative and another at the other side of the cap, I'm getting a more reasonable 6v or a bit less.Pin A and the common C are always at full voltage and pin B is at 0 when not used and climbs when used which I assume is what I want to see.Although, when I connect the multimeter to pin B, the ring light starts switching colors which should be the buttons job.I'm pretty sure the 3 pins are connected properly since I realized they weren't at first because the board the guy used rearranged the common to be at the end on his board even though it's in the middle, But for the positive and negative, I don't see them identified in the spec sheet so I assume it doesn't matter, I used the same orientation as the rotary board diagram.If I flip the positive and negative on the rotary encoder, I get around 5v instead of 6 so guess I'll use that orientation from now on.I'm assuming the pullup resistors are the ones from the filtering which would be 47k ohms.I assume I messed something up somewhere or the many times I connected stuff improperly might have broken something, although everything seems to work and no magic smoke appeared so there's at least that.

author: tooki
author_rank: Super Contributor
timestamp: January 15, 2023, 02:06:56 pm
content: Quote from: SamKook on January 14, 2023, 11:19:19 pmThe Dfrobot encoder board doesn’t have filtering. It has pull-up resistors on the encoder phases. The push button switch has a pull- resistor and a debouncing capacitor.Quote from: SamKook on January 14, 2023, 11:19:19 pmTouching the bare metal of the encoder has nothing to do with the problem.The reason touching it made things happen before is because, without the pull-up resistors, the inputs were floating and thus their states easily affected by touch.Quote from: SamKook on January 14, 2023, 11:19:19 pmThe “schematic” on the hackaday page is of little help, since the pinout of the encoder module is different from that shown in the “schematic”. If you connect the bare encoder as shown in the schematic, it will not and cannot work.It’s hard to tell with certainty what you’ve done since you haven’t provided a schematic of what you actually built (the schematics of the projects you linked aren’t what you actually built) and your photo is blurry and has wires obscuring where they connect, but it looks like you’ve connected the wires from the MCU to the bare encoder as if it were the encoder board, and then added resistors according to the encoder board’s schematic, but without accounting for the board’s external connections.Assuming I deciphered it correctly, the result is that the encoder inputs (phases and button) are permanently pulled high, and the actual button isn’t ever connected to an input.Quote from: SamKook on January 14, 2023, 11:19:19 pmYour microcontroller is running at 5V (most likely) or 3.3V; either way, FAR below the 63V maximum of your capacitor. Capacitor voltages are maximum ratings: applying a voltage higher than that will damage it. That’s it.If there’s no stripe, it could just be minus signs printed down one side.Quote from: SamKook on January 14, 2023, 11:19:19 pmThe “filtering” is, as I said, just pull-up resistors. All three inputs are pulled high.Quote from: SamKook on January 14, 2023, 11:19:19 pmAssuming you mean an actual debouncing circuit (like the encoder module uses on the pushbutton), it’s actually by choosing the “RC time constant” τ (tau), that is, the product (multiplication) of the resistor and capacitor values:R (ohms) x C (farads) = τ (seconds)Tau, by definition, is the amount of time it takes the capacitor to charge/discharge to 63% of the voltage change that is applied.For example, using the values from the dfrobot encoder board’s button, 47kohm x 10μF = 47000 ohms x 0.00001 farads = 0.47 seconds. Since that board keeps the capacitor charged, pressing the button discharges it, so we are going from e.g. 5V to 0V, so our voltage change is -5V.-5V x 63% = -3.15V.Take our starting value (5V) and add the change (-3.15V) to it and we get the value after one tau (0.47s here): 1.85V.So holding the button for 0.47s will discharge the capacitor from 5V to 1.85V. The capacitor voltage is what is (supposed to be) connected to the microcontroller input, giving a stable voltage.But 0.47s is very slow, since it means normal quick button presses will be missed. A much more reasonable debouncing time is a few milliseconds. The datasheet for your Bourns encoder, for example, suggests 10k ohms and 0.01μF for the encoder phases, which multiplied give a tau of 0.1ms, ensuring encoder pulses won’t get missed.I wouldn’t be surprised if the 10μF in the dfrobot module is a typo, and they actually intended to install a much smaller value like 1μF or 100nF.For standard CMOS inputs, the thresholds for “high” and “low” are 70% and 30% of the supply voltage, respectively. The 63% (37%) of one tau isn’t quite 70% (30%), but should be close enough for most purposes. Just err on the side of a lower tau and you’ll be fine. If you use X5R or X7R ceramic capacitors, whose capacitance falls with applied (“DC bias”) voltage, that capacitance loss alone should easily take care of this.So if you want debouncing to ignore pulses shorter than, say, 25ms, then choose R and C values that equal that or a little bit less,. Since resistors are cheap (regardless of value) while capacitors are more expensive and their cost rises with value, select a cheap capacitor first, then calculate the resistor value to match. E.g. 25ms/1μF = 25k ohm, so use a 22k ohm resistor.There are of course formulas to calculate it more precisely, but given that capacitors usually have a tolerance of 10-20%, I think a simplified process like this is sufficient.Quote from: SamKook on January 15, 2023, 03:36:01 amAssuming it’s your 5V USB supply, you shouldn’t be seeing anything above 5.5V.Quote from: SamKook on January 15, 2023, 03:36:01 amYeah it’s wired all sorts of wrong thanks to the hackaday’s crappy, incorrect schematic.Quote from: SamKook on January 15, 2023, 03:36:01 amAs I said, they’re just pull-ups, not filters.If you’re not familiar with how pull-up/pull-down resistors work, I’d strongly suggest doing some research on that first.

author: tooki
author_rank: Super Contributor
timestamp: January 15, 2023, 02:55:14 pm
content: Here's what your schematic needs to be.In all cases, because the contacts on your encoder are rated for 10mA max, make sure your resistor values are never smaller than 500 ohms (5V/10mA = 500 ohms). Since it's better to not run it at its limits, a smaller current is better, like the the 0.5mA that the datasheet-suggested 10k ohms would give.I dunno what resistor and capacitor values you have laying around the house, but for the pure pull-ups (R1, R2) I'd shoot for anywhere from 2.2k ohms to 10k ohms, but it's really not critical other than not going below 500 ohms. For testing your 47k should still work.For R3 and C1, I'd choose something like 10k ohms and 1uF to 100k ohms and 100nF. If you have no capacitors other than the 10uF, then use a 1k ohm resistor.Of course, ground and Vcc need to be connected to the MCU's ground and power.

author: DavidAlfa
author_rank: Super Contributor
timestamp: January 15, 2023, 03:08:08 pm
content: Where's the code reading the encoder?

author: tooki
author_rank: Super Contributor
timestamp: January 15, 2023, 03:42:47 pm
content: It's linked on the project page.

author: DavidAlfa
author_rank: Super Contributor
timestamp: January 15, 2023, 07:42:31 pm
content: Seems a pretty bulky encoder function, not sure it cares much about bouncing.You might try this, recycled from aprevious post:Code:void manage_encoder(void){static bool stable;static int8_t dir;uint8_t now = digitalRead(encoderPinA) | digitalRead(encoderPinB)<<1;if (now==3 && stable) { // Both inputs high after stable condition reacheduint8_t m=Mode;encoderValue += dir;NewValue=readEncoderValue();stable=0;if(dir<0) m+=5; // Add offset for counter-clockwise rotation.switch(m){case 0:ShortcutActionCW0();AnimationStop(NewValue, Red, Green, Blue);break;case 1:ShortcutActionCW1();AnimationContinuous(NewValue, Red, Green, Blue);break;case 2:ShortcutActionCW2();AnimationContinuous(NewValue, Red, Green, Blue);break;case 3:ShortcutActionCW3();AnimationContinuous(NewValue, Red, Green, Blue);break;case 4:ShortcutActionCW4();AnimationContinuous(NewValue, Red, Green, Blue);break;case 5:ShortcutActionCCW0();AnimationStop(NewValue, Red, Green, Blue);break;case 6:ShortcutActionCCW1();AnimationContinuous(NewValue, Red, Green, Blue);break;case 7:ShortcutActionCCW2();AnimationContinuous(NewValue, Red, Green, Blue);break;case 8:ShortcutActionCCW3();AnimationContinuous(NewValue, Red, Green, Blue);break;case 9:ShortcutActionCCW4();AnimationContinuous(NewValue, Red, Green, Blue);break;}}else if(!now_a && !now_b && !stable) {stable = 1; // Reached stable state, apply "dir" value when both pins get high}else if(!stable) { // Only one pin low, sample pins and update directiondir = now_a ? 1 : -1;}}

author: SamKook
author_rank: Newbie
timestamp: January 15, 2023, 11:44:30 pm
content: Thank you very much for the very detailed answer tooki, I learned a lot and it did fix the problem, everything is working properly now.And yeah, I was way off reading the DFrobot schematic, I didn't realize the 5 circles on the right were the actual connection points on the board partly because of the D that's supposed to be a C so your theory that the 10uF is a typo is quite likely since that wouldn't be the only one.Quote from: tooki on January 15, 2023, 02:06:56 pmNo minus signs either. There is NP on the shorter lead side so I guess maybe that could be the indicator, hard to say if it's part of the infos or not since it's not quite directly aligned on it.Quote from: DavidAlfa on January 15, 2023, 07:42:31 pmI'll have to modify the code a bit to better fit my needs so I'll have a look at that while I do, thanks.Quote from: tooki on January 15, 2023, 02:55:14 pmFor the capacitor, I'm using the 10uF one with 1k resistors for now as per your suggestion. The only other option(other than salvaged capacitors in unknown conditions) I have would be 10 years old(but unused)0.1uF Y5p ceramic capacitorsbut the maximum resistance value I have on hand is 47k. Sounds like even if the tau is about half as what you suggested it wouldn't be a problem from what you said unless it can cause issues if that's too fast.So I was wondering if it would be better to keep the electrolytic 10uF capacitor or go with my old ceramic one?

author: tooki
author_rank: Super Contributor
timestamp: January 16, 2023, 12:20:54 am
content: Great that it worked now!As for the cap: honestly, I'd try both and see what works better. You may not notice any difference at all. (Especially since the code has a 50ms debounce built in. You could play with this, too, of course!)But for what it's worth, in terms of long term use, I'd use a ceramic: electrolytics are much more likely to fail, since they have electrolyte inside. Ceramic caps basically don't go bad with age.Remember that you can always put resistors in series to get higher values, or in parallel to get a lower value. (e.g. 2x47k in series = 94k; 2x47k in parallel = 23.5k)Resistors in series: Rtot= R1+R2+...+RnResistors in parallel: Rtot= 1/(1/R1+1/R2+...+1/Rn)You can also do the same for capacitors, except the formulas are swapped: in parallel for a higher value, in series for lower. (e.g. 2x100nF in series = 50nF; 2x100nF in parallel = 200nF).Caps in series: Ctot= 1/(1/C1+1/C2+...+1/Cn)Caps in parallel: Ctot= C1+C2+...+Cn

author: SamKook
author_rank: Newbie
timestamp: January 16, 2023, 12:47:18 am
content: Right, I totally forgot putting stuff in series/parallel was a thing, hard to remember stuff when your memories not great to begin with and there's quite a few years gap between everything I do related to electronics.Thanks for all the help and suggestions, I'll mess around with it a bit and see how it goes.

author: SamKook
author_rank: Newbie
timestamp: January 16, 2023, 07:54:08 pm
content: Using either capacitor, I had issues with the encoder skipping steps and the media player receiving the keyboard presses would freeze after a few dozen inputs.After a bit of research, I ended up ditching all the rotary encoder handling from the project code in favor of using amodified version of buxtronix libraryto handle rotary encoders and ditching the interrupts in favor of just checking if the state changed in the loop and it's working flawlessly. No steps skipped that I can tell regardless of the speed I turn it at and the media player doesn't freeze anymore.I'm not sure if it's just one of those thing that did it or both or even what fixed what problem but that means I'll finally be able to solder the final version with the ceramic cap since that's the one I tested with the new code and is the preferred solution.

author: tooki
author_rank: Super Contributor
timestamp: January 16, 2023, 08:31:09 pm
content: Another library I’ve used for encoders is IOabstraction, which also makes it easy to use encoders on port expanders.

author: Bud
author_rank: Super Contributor
timestamp: January 16, 2023, 09:36:08 pm
content: Quote from: SamKook on January 15, 2023, 11:44:30 pmI would avoid using anything "Y5" capacitors, they have terrible capacitance loss dependence on DC bias and temperature. If your encoder runs but suddenly does not, could be the Y5 capacitor. Change them for X7R or X5R type.

author: Doctorandus_P
author_rank: Super Contributor
timestamp: January 17, 2023, 02:10:55 am
content: Those ceramic "debouncing" capacitors can deliver high peak currents, and those are well beyond the contact rating of the switches used in these encoders. Result is that they will damage the encoder contacts over time. To prevent that you also have to add series resistors for these capacitors to limit their current.

author: MadScientist
author_rank: Frequent Contributor
timestamp: January 17, 2023, 03:37:53 am
content: Most cheap encoders have horrible contact Bounce and even exhibit illegal states while movingYou need illegal state filtering not just contact bounce filtering or you need to detect and eliminate illegal transitory states as the switch is moved it’s more complex then push buttonsCapacitor filtering isn’t sufficient as the illegal states persist for too long

author: SamKook
author_rank: Newbie
timestamp: January 17, 2023, 06:29:21 am
content: Quote from: tooki on January 16, 2023, 08:31:09 pmGood to know.Quote from: Bud on January 16, 2023, 09:36:08 pmQuote from: Doctorandus_P on January 17, 2023, 02:10:55 amSo I'd probably be better off with the other capacitor is what I'm understanding? Getting something else would be problematic so I'd rather stick to these two options for now at least.But if I were to use the ceramic one, how much of a resistor value would they need(same thing as the rest?) and on one or both leads? My circuit making skills are extremely low, I'm able to do these things by following someone else work pretty much.Quote from: MadScientist on January 17, 2023, 03:37:53 amFrom what I understand, the library I'm using has an algorithm that can handle some amount of bad state. I haven't noticed any problems at all with the limited testing I did and I wouldn't know how to do what you suggested anyway so not too worried atm, but I'll keep it in mind.

author: tooki
author_rank: Super Contributor
timestamp: January 17, 2023, 11:42:42 pm
content: Quote from: MadScientist on January 17, 2023, 03:37:53 amThey’re using a Bourns, which is a high quality product.

author: Doctorandus_P
author_rank: Super Contributor
timestamp: January 20, 2023, 01:37:17 am
content: Quote from: SamKook on January 17, 2023, 06:29:21 amIt's quite simple. Worst case is a fully charged capacitor shorted to GND, which means that the protection resistor is simply Ohms law. When I assume a 5V power supply and a 10mA contact rating, then the minimum resistor value would be R = U/I = 5/0.01 = 500 Ohm.

author: ratatax
author_rank: Regular Contributor
timestamp: January 20, 2023, 12:09:22 pm
content: Quote from: tooki on January 17, 2023, 11:42:42 pmDisagree with that. I made a product using Bourns encoders, they were horribly wobbly and started to fail after 1 year of normal use. I don't known, maybe it's just that specific series (PEC11L)As for reading encoders, I recommend doing a full software debouce. it's quite easy, simpy poll it fast enough a use a variable that can go for example from 0 to 10, and increment/decrement it depending on the reading. When it reaches 0 its low, 10 it's high.Adjusting the max value (10) adjusts the "software smoothing".Now I didn't knew about illegal states on some encoders. What are they exactly ? I tried some algorithms (state machines) to enforce state changes in encoders, but i get rid of them since in some cases it didn't worked that well (I guess if you miss a good state because of too much bouncing when turning it quickly, you're fucked and the state machine doesn't repredent the real state of the encoder anymore)

author: MadScientist
author_rank: Frequent Contributor
timestamp: January 21, 2023, 11:16:44 am
content: Quote from: ratatax on January 20, 2023, 12:09:22 pmWhat you find on cheap encoders is as the cams move you get illegal states , which survive conventional denounce routines as the state persists longer than typical denounce times. This is due to the nature of the switch construction. Hence you don’t get monotonic continuous states but you can get way out of sequence events . WhT I add is illegal state filtering , ie basically if you are counting 1.2.3 etc then clearly getting 10 as the next state is wrong and can be eliminatedThis was the only way I could get very reliable encoder states simple time ( 30 ms) based contact denounce isnt enough to avoid skipped states

author: SamKook
author_rank: Newbie
timestamp: January 22, 2023, 03:43:14 am
content: You can read more about how the algorithm I'm using works on the original authors blog there:http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.htmlBut it claims to handle common issues well and in practice, it does seem true. I've been coding stuff most of the week on my free time and testing animations a lot and I've yet to notice issues with the rotation detection.I even managed to add cycling back every half a sec when holding the button with the modified library which is quite nice since I can add as many modes as I want and not have to suffer the pain of cycling through them all if I accidentally click on it.Edit: To be specific, I'm not using any of the code from the original hackaday project, it wasn't good.Edit2: Unless you're telling me that doing the software debounce would allow me to get rid of the resistors and capacitor and it would still work, but I'm fairly certain the library I'm using is doing that already, unless I'm not understanding something.A comment taken from the library itself(but you did say you had bad experience with some state machine algorithm):Code:* The biggest advantage of using a state machine over other algorithms* is that this has inherent debounce built in. Other algorithms emit spurious* output with switch bounce, but this one will simply flip between* sub-states until the bounce settles, then continue along the state* machine