Quadrature Rotary encoder - Page 1
Forum section: electronics / projects

author: mr1979
author_rank: Contributor
timestamp: August 30, 2017, 06:30:16 pm
content: I need to read rotation direction of a quadrature rotary encoder without any delay because I need to drive an up/down counter very accurate. Encoder will be used to select a value on a control panel. I need to realize the circuit only with discrete logic without using any software or programmable logic. Please help me to find a solution. Thank you in Advance. MarcoInviato dal mio PLK-L01 utilizzando Tapatalk

author: Benta
author_rank: Super Contributor
timestamp: August 30, 2017, 06:43:58 pm
content: D flip-flop is the usual way, provided the encoder is debounced already.

author: mr1979
author_rank: Contributor
timestamp: August 30, 2017, 06:51:07 pm
content: I tried with D flip flop but there is a transition between 2 detent in a particular position where i loss one or two steps before recognizing the change of direction. Can you post an example circuit?Inviato dal mio PLK-L01 utilizzando Tapatalk

author: mr1979
author_rank: Contributor
timestamp: August 30, 2017, 07:18:25 pm
content: I found a lot of example circuit on Internet but none of them seems to work well. If only a phase is used to clock data in D flip flop i loose a direction detection when this phase doesn't change and change only the other phase. Did you experienced this problem? Maybe i' m doing some mistake.Inviato dal mio PLK-L01 utilizzando Tapatalk

author: max_torque
author_rank: Super Contributor
timestamp: August 30, 2017, 08:40:07 pm
content: i Assume this is for some education project? Because in the real world, in 2017, you'd be mad not to use a small cheap micro, which now retail for less than even the price of some old school "glue logic" ICs...........

author: mr1979
author_rank: Contributor
timestamp: August 30, 2017, 09:03:43 pm
content: No it's not for education. Is an application in which also simple software is not permitted.Inviato dal mio PLK-L01 utilizzando Tapatalk

author: mr1979
author_rank: Contributor
timestamp: August 30, 2017, 09:04:55 pm
content: Using a micro is very simple and cost effective, but in this application is not allowed.Inviato dal mio PLK-L01 utilizzando Tapatalk

author: Ian.M
author_rank: Super Contributor
timestamp: August 30, 2017, 09:54:50 pm
content: If you want to implement a QEI to Up/Down pulse interface in pure LSI/MSI logic hardware, the best option would be a clocked synchronous implementation of the classic QEI state machine.Here's a C implementation of the classic 4 bit QEI state machine for reference:Code:/*State | A B | direction------+-----+----------1 | 1 0 | ^ reverse (B leads A)2 | 1 1 | ^3 | 0 1 | ^4 | 0 0 | .1 | 1 0 | v2 | 1 1 | v3 | 0 1 | v forward (A leads B)Logic Equations===============NoMove = /A'./B'./A./B + /A'.B'./A.B + A'./B'.A./B + A'.B'.A.BForward = /A'./B'.A./B + A'./B'.A.B + A'.B'./A.B + /A'.B'./A./BReverse = /A'./B'./A.B + /A'.B'.A.B + A'.B'.A./B + A'./B'./A.BError = /A'./B'.A.B + A'./B'./A.B + /A'.B'.A./B + A'.B'./A./B*/// vector is packed bits: A' B' A Bvector=(vector<<2)&0xA; // Preserve old A,B as A',B'if(A) vector|=2; // Read encoder inputsif(B) vector|=1;// Convert to up/down countswitch(vector) {case: 0b0000 // /A'./B'./A./Bcase: 0b0101 // /A'.B'./A.Bcase: 0b1010 // A'./B'.A./Bcase: 0b1111 // A'.B'.A.B// No movementbreak;case: 0b0010 // /A'./B'.A./Bcase: 0b1011 // x4 // A'./B'.A.Bcase: 0b1101 // x2 // A'.B'./A.Bcase: 0b0100 // x4 // /A'.B'./A./B// Forwardcount++;break;case: 0b0001 // /A'./B'./A.Bcase: 0b0111 // x4 // /A'.B'.A.Bcase: 0b1110 // x2 // A'.B'.A./Bcase: 0b1000 // x4 // A'./B'./A.B// Reversecount--;break;case: 0b0011 // /A'./B'.A.Bcase: 0b1001 // A'./B'./A.Bcase: 0b0110 // /A'.B'.A./Bcase: 0b1100 // A'.B'./A./B// Error: both signals changedbreak;}// Comment out lines tagged // x4 to halve the count rate.// Commenting out lines tagged // x2 and // x4 will quarter the count rate.Edit: Corrected inconsistencies between comments and code + added logic equations: . is AND, + is OR and / is NOT.The above code needs to be either polled faster than A or B can change or triggered by an interrupt on change of A or B. The delay with even a 10KHz polling rate would be negligible for a manual UI control knob, even if it has a spinner.Considering a hardware implementation in 74HCxx logic, I belive it can be done in five chips: The state of A and B would be captured by a 74HC74 dual D type flipflop, Another 74HC74 would capture both Q outputs of the first one to preserve the previous state of A and B. All the flipflops in both 74HC74 chips would be clocked by the external sampling clock. The four Q outputs from both 74HC74 chips form the four bit statevectoras in the code above. The vector goes to a 4 to 16 line decoder (built from two 74HC138 chips, with A0 to A2 connected to the low three bits of the vector and the high bit connected to an EN of one and /EN of the other. The remaining /EN pins are strapped low and EN pin strapped high). This section is equivalent to theswitch(vector)statement. Finally, the decoded state outputs from the '138 chips, each one being equivalent to acasein the code above, feed a 74HC20 dual 4 input NAND gate. Each NAND combines four states to get one directional count pulse, equivalent to thecount++andcount--statements above. The output pulse will go high for one clock period if the encoder has moved in that direction.An asynchronous self-clocked implementation would be similar, but you'd need a mess of XORs and monostables to generate two clock pulses shortly after every input transition.

author: Cerebus
author_rank: Super Contributor
timestamp: August 30, 2017, 11:00:35 pm
content: If you want a one chip solution, look at the Agilent HCTL-2000 Quadrature Decoder/Counter Interface IC and its close cousins (probably now a Broadcom part as I believe this part of Agilent was sold off to them).Even if you don't want a single chip solution (or want to program a corner of a CPLD or FPGA to do the job) the datasheet is still worth a look as there is a passable 'theory of operation' section in it, including a simple but effective digital filter for debouncing before feeding the quadrature signals into a state machine and counter.

author: Someone
author_rank: Super Contributor
timestamp: August 31, 2017, 01:09:54 am
content: Quote from: mr1979 on August 30, 2017, 09:03:43 pmDoing this in logic introduces significant challenges in meeting the timing requirements of the logic. Since you said this is for a user control the timescales of possible input changes is so slow that logic is a poor choice for the problem, analog comparators might be more appropriate!

author: Ian.M
author_rank: Super Contributor
timestamp: August 31, 2017, 02:00:42 pm
content: I've taken the QEI state machine concept I posted earlier and implemented it in (simulated) 74HCT logic. 5 chips if externally clocked or 6 if self clocked. Its *FUGLY* but it should work. Complete zipped LTspice sim attached.

author: mr1979
author_rank: Contributor
timestamp: August 31, 2017, 07:09:46 pm
content: Quote from: Ian.M on August 31, 2017, 02:00:42 pmThank you for your support!!! You have help me a lot!!!!Inviato dal mio PLK-L01 utilizzando Tapatalk

author: BrianHG
author_rank: Super Contributor
timestamp: September 01, 2017, 05:46:32 am
content: Quote from: Ian.M on August 31, 2017, 02:00:42 pmChange your 74HC74 with a 74HC574. 1 clock wire, feed 2 d inputs and their output to the next stage d inputs. GND the unused D inputs. Simplifies breadboarding...Also, you can get rid of the 74HCT86 and feed the enables with a CLK signal instead. This will slightly delay the count pulse depending on the clock rate, but, what the hell, just feed this circuit a 4MHz clock. If you think the quadrature res-once circuitry will affect location with a sample time of 1 - 4 millionth of a second, you must have a rotary encoder approaching relativistic speeds. (A significant portion of the speed of light...)Also, you don't necessarily need to debounce the encoder signal, all a bounce would do it move the counter position back and forth during that middle ground. If the bounce output of your encoder exceeds the time between a transition on both A&B source signals, you are moving the encoder too fast for reliable motion acquisition.Also in the schematic, is says you can feed an external clock, but, that clock signal is shorted with the 74HCT86 output. Be careful here. I believe that they mean use and external clock like I recommend and completely get rid of the 74HCT86, or, use the 74HCT86 as your clock generator as stated 'SELF CLOCKING OPTION'...

author: Ian.M
author_rank: Super Contributor
timestamp: September 01, 2017, 06:47:06 am
content: Thanks for the feedback.I could do that, and, if one was building the externally clocked version, that would leave enough flipflops for a second QEI interface in the same chip. Also, while I'm using TTL with far too many pinsI could also switch to 74HC154 4 to 16 line decoders. That would get the chip count down to 2.5 per QEI. and then all you need to do is add some up/down counters, tristate buffers and address decoding and you've got an old-skool (crappy) bus mouse interface.However I was sticking to 'vanilla' 14 pin 74xx series logic + the LTspice74HCTlibrary (+symbols) I'm using doesn't have 74xx154 or 74xx574,and I certainly cant be ars3d to build it for real when I could just drop in a small PIC or AVR .It does require debouncing, otherwise in the real world, it increases the risk that it will occasionally loose counts due to metastability causing an invalid transition to be be decoded. Your proposed 4MHz external clocked version would do well to use the spare flipflops in the 74xx574 to implement a multi-flop synchroniser for A and B, and assuming you haven't splurged on some Schmitt input buffers, the first stage of it could do with a feedback resistor from Q to D to add hysterisis.Also you may have noticed the text 'Self ClockingOption' and the dotted line round the 74HCT86 clock pulse generator gilded turd. Hopefully its obvious that its an either/or option - use the self-clocking furball of RC delays without a proper monostable or Schmitt trigger input in sight OR(my preference)delete that section and provide an external clock.Sorry I was lazy and didn't separate out the daggy bit and hook it up with net labels.Unfortunately LTspice doesn't have a 'cut here' scissors symbol!

author: bson
author_rank: Unknown
timestamp: September 03, 2017, 12:31:42 am
content: Detect change on the sine, direction on the cosine. If you feed it into a bidirectional counter you could clock it on A, either rising or falling edge, and use B for the counting direction. This is exactly how you'd do it in software: interrupt on A, read B to determine direction. Obviously you need to debounce it if needed - which in software means leaving the interrupt disabled for the debounce interval (aka rearming delay). In hardware it means RC.

author: exe
author_rank: Unknown
timestamp: September 23, 2018, 04:50:37 pm
content: Quote from: Ian.M on August 30, 2017, 09:54:50 pmSorry for ressurecting old thread, just wanted to say thanks for the code. Here is what I ended up (removed switch/case to states that do not change counter, fixed some minor typos):Code:class QEI {public:ioportid_t port;u32 pad1;u32 pad2;u8 state = 0;u16 count = 0;u16 value = 0;QEI(ioportid_t _port, u32 _pad1, u32 _pad2): port(_port), pad1(_pad1), pad2(_pad2) {palSetPadMode(port, pad1, PAL_MODE_INPUT_PULLUP);palSetPadMode(port, pad2, PAL_MODE_INPUT_PULLUP);}int scan() {// idea from// https://www.eevblog.com/forum/projects/quadrature-rotary-encoder/msg1291497/#msg1291497bool pad1_state = palReadPad(port, pad1);bool pad2_state = palReadPad(port, pad2);state = (state << 2) & 0b1111;if (pad1_state) { state |= 0b01; }if (pad2_state) { state |= 0b10; }switch(state) {// Forwardcase 0b0010:case 0b1011:case 0b1101:case 0b0100:count++;break;// Reversecase 0b0001:case 0b0111:case 0b1110:case 0b1000:count--;break;}if (count % 4 == 0) {value = count / 4;}return value;}};

author: OM222O
author_rank: Frequent Contributor
timestamp: September 23, 2018, 05:54:30 pm
content: I think I have a fairly simple solution for youYou need to get a quad XOR gate chip. It will be used to detect the edge both rising and falling edge of one of the phases. This can be used as a trigger (clock) signal to D flip flop.You need some additional gates to work out the direction. for example if (A is High and B is low) or (A is low and B is high) (which is basically another XOR of A and B) you're moving forward. the output of the the logic that determines the direction, can be fed to the data input of the flip flop. then you have both your clock and direction signals and you can do the switching based on that.I'm gonna quickly make the circuit diagram if my explanation is confusing.

author: OM222O
author_rank: Frequent Contributor
timestamp: September 23, 2018, 06:32:58 pm
content: Ok, here is the simulation:http://tinyurl.com/y7a56zo5As you can see, phase B is offset by -90 degrees and the output of the D flip flop is constantly HIGH.If you change phase B to be offset by +90 degrees (change of direction) the output of the flip flop would be constantly low. You can change that by double clicking on the "CLK" next to "PHASE B" text and writing the offset value as you desire.You can also get double the clock frequency if you use the rest of the 2 XOR gates but try this first and see if it works for your application. I'll post the other circuit simulation as well.

author: OM222O
author_rank: Frequent Contributor
timestamp: September 23, 2018, 06:42:38 pm
content: And here is the final circuit simulation with double the clock frequency:http://tinyurl.com/y9253f45Note that if you connect the phases backwards, you can switch the direction output. i.e: clockwise rotation would be HIGH in one case, and if you switch the phases, it would be LOW in the other case.I hope you found this useful and it's not too confusing for you. it's basically 2 chips: a quad XOR and a D flip flop with a resistor and a capacitor which is as basic as you can get.If you're rotating the encoder really fast, try decreasing the value of the resistor and capacitor to lower the trigger pulse ON time. you should test it in your application with your specific use case and see how low of a value you can get away with.

author: RoGeorge
author_rank: Super Contributor
timestamp: September 23, 2018, 07:11:40 pm
content: LS7183 or LS7184

author: MarkF
author_rank: Super Contributor
timestamp: September 23, 2018, 09:51:52 pm
content: Here is a circuit I found online a while back that may be useful.I never wired it up. So, I don't know how well it works.

author: chris_leyson
author_rank: Super Contributor
timestamp: February 16, 2022, 09:59:30 am
content: The state machine approach works well, for examplehttps://chome.nerpa.tech/mcu/reading-rotary-encoder-on-arduino/