Rotary Encoder to Flip Flop? - Page 1
Forum section: electronics / beginners

author: robobeamer
author_rank: Newbie
timestamp: January 11, 2016, 08:13:22 pm
content: Hello, I'm trying to use a 2-Bit, PEC12R - 12 mm Incremental Encoder to a D type flip flop (MC74HC74A) to detect direction.Tied reset and set of flip flop to VCC.Encoder outputs, A and B, to clock and data pins.The Q output isn't consistent. I get highs when it should just stay low and lows when it should stay high as I'm turning the knob.I'm using 20K pull downs at encoder outputs.

author: KL27x
author_rank: Super Contributor
timestamp: January 11, 2016, 08:22:22 pm
content: Getting a noisy mechanical coder to work over a wide range of varying speeds requires some black magic, some sweat, and a lot of swear words. It might even be impossible to have complete accuracy without errors at certain RPMwithout a microcontroller.For a low volume, it may be more efficient for you to change to a more expensive optical encoder. It might save a lot of grey hairs.

author: free_electron
author_rank: Super Contributor
timestamp: January 11, 2016, 08:38:24 pm
content: 100NF CAP TO GROUND ?

author: KL27x
author_rank: Super Contributor
timestamp: January 11, 2016, 10:10:48 pm
content: ^ That's a start. But good luck. I hope OP has better luck than I.Do you have a part number that you have had success with this simple sort of decoding, before? I have tried several from Mouser/Digi and a variety of RC values (Starting with 0.1uF caps), and simple read B when A edges doesn't come close. And even if it worked perfectly, it would still skip a beat on a partial turn before a change in direction.Retaining memory of a number of states and checking for validity is also not easy. You can easily end up missing a lot of reads.

author: robobeamer
author_rank: Newbie
timestamp: January 11, 2016, 10:25:46 pm
content: Quote from: KL27x on January 11, 2016, 08:22:22 pmAhh. Was afraid of that. Thanks for the insight.

author: jwm_
author_rank: Frequent Contributor
timestamp: January 12, 2016, 03:33:53 am
content: The 4528 dual monostable multivibrator is nice for cleaning up rotary encoders (and you probably have some in your junk box). Trigger one with rotary channel A, inhibit with channel B, and vice versa for the other one. You will get nice directional pulses out, one triggers on counterclockwise, the other pulses on clockwise. You can feed them into a S/R latch to get a steady direction signal if you need it.http://www.onsemi.com/pub_link/Collateral/MC14528B-D.PDF

author: zapta
author_rank: Super Contributor
timestamp: January 12, 2016, 07:54:16 am
content: Quote from: KL27x on January 11, 2016, 10:10:48 pmI don't think you need multiple states or do any time dependent debouncing. The trick is that when A bounces B is stable and vice versa (it's a two bits gray code) so a state machine that just the current state should do.

author: KL27x
author_rank: Super Contributor
timestamp: January 12, 2016, 08:15:32 am
content: So are you suggesting that you could simply do edge detection, as long as you are triggering off of only one output at a time and alternating between the signals after each trigger? This sounds way too logical. Will have to try this. Will need to use a device that can interrupt on rising and falling edges, I suppose.

author: zapta
author_rank: Super Contributor
timestamp: January 12, 2016, 03:22:50 pm
content: I am suggesting a state machine that samples on each clock edge samples the two inputs and decided the next state. Probably easier to implement with a dirty cheap 8 pin MCU. You can also try to implement the truth table with discrete gates and use two flip-flops or a edge latch for the state.Edit: You can try this solver for the truth table, two variables for the current state, two variables for the A and B inputs and the two outputs give the next state.http://www.32x8.com/var4.html

author: KL27x
author_rank: Super Contributor
timestamp: January 12, 2016, 09:03:34 pm
content: QuoteThis isn't clear to me. What is the clock edge? This suggests to me constant polling, but that doesn't solve any problem.I am thinking this:1. Set interrupt on rising edge of Output A. Read B on interrupt.if B reads high, record as direction X and goto 2if B read low, record as direction Y and goto 32. Set interrupt on falling edge of Output B. Read A on interruptif A reads is high, record as direction Y and goto 4if A reads low, then record as direction X and goto 13. Set interrupt on rising edge of Output B. Read A on interruptif A reads high than record as direction X and goto 4if A reads low than record as direction Y and goto 14. Set interrupt on falling edge of Output A. Read B on interruptif B reads high, record as direction Y and goto 2if B reads low, record as direction X and goto 3It looks like it would debounce the signals without any time-dependence, simply by ignoring either output after it has triggered, until the other one has triggered. Is this the state machine you had in mind, or am I totally off the rails?The more I look at this, the more I think I already tried it. But that might be deja vu.

author: jwm_
author_rank: Frequent Contributor
timestamp: January 12, 2016, 10:21:36 pm
content: Are you okay with only one pulse per complete traversal of the state machine? Then what you can do is just outputemit CW pulse on rising edge of A and B is zeroemit CCW pulse on falling edge of A and B is zerodon't output anything if B is one.You are basically just paying attention to a single transition in the loop of the state machine, so you don't have to actually store anything in a flip flop, the direction of the edge and the state of the other one is enough.This has the big advantage over the "use rising edge of A as clock and B as direction" setup that it will never insert or lose steps, with the just sampling rising edges of A method as that emits the pulses at different transitions in the state machine, so it is possible if the encoder were wiggled at just the right point to get spurious events.My method always pays attention to the same edge rising and falling so they will always cancel out.You can use a schmitt trigger to detect rising and falling edgeshttp://www.musicfromouterspace.com/analogsynth_new/ELECTRONICS/mickeymouselogic.htmlPretty much any schmitt trigger chip you have can do. It will also debounce for you for free pretty much.

author: KL27x
author_rank: Super Contributor
timestamp: January 12, 2016, 10:43:06 pm
content: QuoteAs long as either1. There is no bounce2. If there is any bounce, your input device can react fast enough to catch each part of the bounce without missing anyA Schmitt trigger has hysteresis, but this is not complete debouncing.This may work fine, of course. The thing that struck me about Zapta's comment is that when one output of the encoder is bouncing, the other is defacto stable/bounceless. Seems like this could be taken advantage of. Only one trigger is active at a time, and it would theoretically always be set to trigger on the output that is currently stable. The first change is the only thing detected, and any bounce thereafter isn't even on the radar, because while it's bouncing the trigger is now only active on the other (stable) output.

author: jwm_
author_rank: Frequent Contributor
timestamp: January 12, 2016, 10:51:34 pm
content: No, it is immune to bounce too, because it pairs rising edges and falling edges of the _same line_. If there is bounce you will see a bunch of CW and CCW pulses, but they will add up to cancel out exactly. This is different than most naive ways that only look at rising edges so bouncing will cause it to precss forward as the rising edges give a CW pulse but the falling ones don't give a corresponding CCW pulse.That said, there are many ways to do it in hardware, all of which are much easier than getting it right in software which is surprisingly tricky, especially if your uC has to do anything else or you don't route your lines to the right I/O pins that can detect edge direction. Best way probably depends on which chips are in arms reach.

author: KL27x
author_rank: Super Contributor
timestamp: January 12, 2016, 10:59:54 pm
content: QuoteAs long asQuote, correct?I mean, A goes high, but it bounces down and back up. The first rising edge will be detected. The falling edge will be detected. But will the second rising edge be detected for certain? There has to be some minimum delay between the two consecutive rising edges for the second one to register, no matter how you are detecting them, no? Maybe this is not a practical problem, particularly if using a suitable RC filter and Schmitt trigger, but isn't this theoretically there?Anyhow, I believe you have a sound solution. Thanks. Will fall back on hardware if necessary.

author: jwm_
author_rank: Frequent Contributor
timestamp: January 12, 2016, 11:07:10 pm
content: Quote from: KL27x on January 12, 2016, 10:59:54 pmDepends on how you do your multivibrators, you can make them retriggering capable, but in general, this is plain logic that can run at tens of megahertz, so, unless your wheel is spinning really, really fast, it won't be an issue. In any case, if pure logic can't keep up then a uC certainly won't be able to.The big issue with a uC is that you need to atomically "see an edge, flip the direction of the edge you are looking for and sample the other line" at the exact same time. Most uCs don't make that easy to set up so rely on a very fast interrupt handler, which may be delayed due to other code being in a critical section. Every time i see an arduino thing route their encoder to some random atmel pins and assume they can just use the pin change interrupt and it will work out I want to shake my fist at the screen as they are in for a lot of flakyness.Oh, and once you have your clean CW and CCW pulses and if you want to get them into the uC, you can just set them up to trigger counters on the uC then subtract one from the other every time you want to 'read' the current position. pretty much all uCs have the ability to set up hardware counters on interrupts so you don't need to worry about latency in your code or a super fast interrupt handler.

author: KL27x
author_rank: Super Contributor
timestamp: January 12, 2016, 11:10:07 pm
content: I have full control over interrupt priority, direct coding. No issue there.But I think you're onto something with the pure logic being faster, and I will have your hardware solution to fall back on. Very nice. I take it you would use one of the encoder outputs to hold the monostable vibrators in reset. The other output triggers the vibrators. Two of them; one that triggers on falling, one that triggers on rising? Or is there an easier way to do this?

author: jwm_
author_rank: Frequent Contributor
timestamp: January 12, 2016, 11:21:26 pm
content: Quote from: KL27x on January 12, 2016, 11:10:07 pmJust use a dual multivibrator like the 4528 and it will be only one chip. it can trigger on either rising or falling depending on how you hook it up, wire each one differently. Then line B hold the /RESET line to inhibit generating pulses when it is zero.There are other chips that can do it, the 4528 is really clean IMHO and gives you both normal and inverted outputs, I am sure you can do it with a 556 or a few schmitt inverters and some passives if you wanted to really optimize gate count.

author: KL27x
author_rank: Super Contributor
timestamp: January 12, 2016, 11:22:29 pm
content: ** on second thought, I'm still not fully conviced. There has to be some minimum pulse width and pause which is output to your control circuit which is receiving these pulses, and which must certainly be longer than the duration of bounce. So I don't see how you can catch all the bouncing to balance them all out unless you were feeding info into a buffer which then produced readable pulses, after the fact if need be.

author: jwm_
author_rank: Frequent Contributor
timestamp: January 12, 2016, 11:31:44 pm
content: Quote from: KL27x on January 12, 2016, 11:22:29 pmThat's the beauty of it, the pulse width of output is set by the RC of your multivibrator and the maximum frequency of observable bounces is set by the RC before the schmitt trigger, just make the second one greater than the first and you cannot miss transitions, you will always be able to get a full pulse out before the next bounce. Since the A line is fed through a single inverter, it must have an equal number of rising and falling transitions that have a maximum frequency set by whatever RC constant you use. what changes is not the pulses themselves which will be a steady stream of CW and CCW pulses, but whether they are inhibited or not by the relatively static B line.

author: pmbrunelle
author_rank: Regular Contributor
timestamp: January 13, 2016, 12:04:22 am
content: Can't you just poll the pins from a timer interrupt? Then, in the interrupt, figure out the state machine logic.Your timer interrupt frequency and/or latency just needs to be quick enough to guarantee that you don't miss a state when rotating the encoder at maximum RPM. Every state must be polled at least once.

author: MarkF
author_rank: Super Contributor
timestamp: January 13, 2016, 12:45:38 am
content: Why not just use a Rotary Decoder Interface (ELM404) to do all the decoding.

author: jwm_
author_rank: Frequent Contributor
timestamp: January 13, 2016, 12:46:32 am
content: Quote from: pmbrunelle on January 13, 2016, 12:04:22 amYes, that would be a way to do it on a uC, but it is tricky to get right. for instance, if you notice pretty much every arduino based thing that uses an encoder gets flaky if you go too fast, that's because its delay function blocks interrupts, causing all sorts of oddness in interrupts that should be fast, the pin change doesn't tell you which edge it was so you may poll it after the next bounce. And even if you use hardware edge detection, you might not be able to flip the sign of the detection fast enough before the next bounce. It is solvable, but then your uC is babysitting your encoder and imposed with various real time constraints rather than whatever else you wanted to be doing with it.It's amazyng how much commercial hardware gets flaky if you twist the encoders too fast let alone hobby projects... sigh.With logic you inherently cannot have these race conditions, the maximum frequency the pin can physically flip is hard limited by your RC delay, so you know the time budget the rest of your logic has to process it.Not saying it's impossible to do with a uC, far from it, just that it takes some work to integrate that usually can't be amortized between projects, I'd rather dedicate a uC to it, but then i might as well just use the sixteen cent logic chip that doesn't need programming, can be multi-sourced, and can run on anything from a coin cell to a car battery without regulation once i am adding a new chipJohn

author: jwm_
author_rank: Frequent Contributor
timestamp: January 13, 2016, 12:56:11 am
content: Quote from: MarkF on January 13, 2016, 12:45:38 amThat chip is $8, single sourced (with unknown production capacity), requires a regulated supply, and is not available from big distributors as far as i can tell. That is opposed to a logic chip that is twenty cents and fabricated by at least 5 different companies so will never have supply issues.There are many ways to skin this cat.

author: kwass
author_rank: Frequent Contributor
timestamp: January 13, 2016, 05:55:07 am
content: Quote from: jwm_ on January 13, 2016, 12:46:32 amIt is tricky, and it it took me a while to find a good solution. I use cheap encoders a lot and have a bunch of old Parallax (aka Scenix) SX uC that I often use with them. Polling the encoders in a timed interrupt at 1000Hz and comparing the last state to the current one works just right.

author: rs20
author_rank: Super Contributor
timestamp: January 13, 2016, 07:02:36 am
content: Quote from: KL27x on January 12, 2016, 09:03:34 pmI know I'm digging up an old post here; but this is wrong, wrong, wrong. Switch debouncing is very effectively performed by having a Q flip flop that constantly polls the state of the switch. That converts your noisy, bouncy mechanical signal into a nice clean waveform. Then you can feed it into any other rotary encoder decoder solution, including your Q flip-flop based one, and it will operate reliably.Quote from: pmbrunelle on January 13, 2016, 12:04:22 am^ This.Quote from: jwm_ on January 13, 2016, 12:46:32 amThere's your problem! As you pointed out, Arduino libs are a joke when it comes to this sort of thing. Don't be hating on interrupts because Arduino is bad at it!Quote from: jwm_ on January 13, 2016, 12:46:32 amMissing bounces isn't a problem; as long as you're not using a rotary encoder that's so terrible that the bounces actually never stop, simple state machines will work. I do take your point that keeping timer interrupts from being starved can be difficult; it depends entirely on whether you're trying to handle higher priority interrupts and whether you've got too much code in those interrupts, which can be a question of some subtlety. So I do agree with you that in many cases, a dedicated MCU is a reasonable solution.

author: jwm_
author_rank: Frequent Contributor
timestamp: January 13, 2016, 06:47:28 pm
content: Quote from: rs20 on January 13, 2016, 07:02:36 amI'm not hating on interrupts, I have written perfectly good uC rotary decoders before otherwise I wouldn't feel qualified to comment on it. I am just saying it is a non-trivial problem and making things easy with hardware is so trivial in comparison. Unless I was making a billion of something, saving a few cents on cost for many hours of debugging and reduced flexibility in the main uC is not worth it. And every time you write a firmware upgrade or try to add functionality, you have to take how it interacts with the decoder into account so it is an ongoing dev cost you are committing to that can't be amortized between projects because the particular solution is always tailored to whatever else the uC is actually doing it has to interact with.I was mainly using arduino as a visible example of what happens when people don't think about it and just assume "it can be done in software" as i see it all the time. Most of the arduino libraries have this issue where they don't combine well, people will get the rotary encoder sketch working and think great, then try the lcd driver sketch and it is working, then design their hardware and suddenly be up the creek when they try to use both libraries at once and find they do not play well together at all without completely rewriting both to take each others timing constraints into account. And then if you didn't have the foresight to route your encoder to the edge interrupt capable pins, that's some bodge wires you are going to be soldering. sigh.I think a lot of open hardware designs suffer from this especially, since the hardware tends to be designed first then it is up to the community to write software (not that there is anything wrong with that order of doing things). But spending a slight amount more time in the hardware offloading as much as you can from the uC (whether it will actually be strictly necessary or not) makes everything really nice in the future when you try to write the firmware.Note this doesn't apply to a dedicated uC properly implemented, because then you know beforehand there is nothing else the uC is doing that might cause an issue in the future, whether you do that or have some discrete logic depends on what you are doing. For reusable circuits, I tend to design a discrete logic solution with jellybean chips once and never worry about it again. The schematic is good forever with many different logic families and doesn't depend on any particular manufacturer part or devel environment still existing in ten years when I revisit it or just want to use it as a black box in something new. If it turns out something I design is going to be produced by the millions where saving a dime makes a huge difference to he bottom line then I can afford to spend the time rethinking things for a respin which will probably need to happen anyway.

author: mikerj
author_rank: Super Contributor
timestamp: January 14, 2016, 04:31:46 pm
content: Quote from: jwm_ on January 13, 2016, 12:46:32 amThe underlying problem here is the massive overuse of the delay() function in a lot of Arduino code rather than e.g. using state machines and millis()

author: zapta
author_rank: Super Contributor
timestamp: January 14, 2016, 05:28:08 pm
content: Quote from: mikerj on January 14, 2016, 04:31:46 pmDelay() is good for blinky hello world but a dead end after that.Does Android come with a standard timer functionality? That is start/stop/get_time? If not, it should.Edit: Android -> Arduino

author: mikerj
author_rank: Super Contributor
timestamp: January 15, 2016, 02:21:29 pm
content: Quote from: zapta on January 14, 2016, 05:28:08 pmI don't think so, but I don't really use the Arduino language, though I sometimes use the Arduinos themselves as cheap eval boards. The millis() function returns an unsigned long millisecond counter, which is sufficient, though a few small functions would make for tidier code.

author: zapta
author_rank: Super Contributor
timestamp: January 17, 2016, 10:19:34 pm
content: Quote from: mikerj on January 15, 2016, 02:21:29 pmI have a small wrapper class around millis that provides timer instances and restart and getTime operations. Arduino should have it standard IMO, with a matching blinking example.

author: jwm_
author_rank: Frequent Contributor
timestamp: January 19, 2016, 04:27:49 pm
content: Quote from: zapta on January 17, 2016, 10:19:34 pmYeah, I think the ecosystem suffers because once someone becomes skilled enough to write such a class properly, they are also past the point where the realize how crappy the arduino libraries and software infrastructure is to begin with so drop it alltogether. The best thing about arduino is it gives a nice ebay search term for "probably somewhat documented and interfacacable via standard logic peripherals" which is quite handy.

author: zapta
author_rank: Super Contributor
timestamp: January 19, 2016, 06:32:28 pm
content: Quote from: jwm_ on January 19, 2016, 04:27:49 pmI can contribute such a class if the process it not too difficult.mbed comes standard timer class.