Rotary encoders, 74LS14's and 74LS74's

Hello all,

I have a few 288T232R161A2 rotary encoders and want to hook them up to my Arduino, naturally. They are relative encoders, so they only output 'up' or 'down' rather than absolute positions, so I figured this would be fairly straightforward.

I searched the forum before and found this circuit diagram posted by Grumpy Mike:
Twitpic (can't work out how to upload the full size image with Twitpic...)

So now I've wired all that up plus the Vcc and Gnd on pins 7 and 14 on the 74LS74 and 74LS14, pin 1 and 3 of the 74 going to the Uno's pin 2 and 4 respectively, then uploaded the following code to my Arduino:

int stepPin = 4;
int dirPin = 2;

int stepVal = 0;
int dirVal = 0;

void setup(){
Serial.begin(9600);
pinMode(stepPin, INPUT);
pinMode(dirPin, INPUT);
}

void loop(){

stepVal = digitalRead(stepPin);
dirVal = digitalRead(dirPin);

Serial.print(stepVal, DEC);
Serial.print(",");
Serial.println(dirVal, DEC);
}

When run, the serial monitor just prints "0,1" for two of the four possible steps, but on the other two it will print "1,0", but the second digit will go high and low (seemingly) randomly and loop like that. It doesn't matter which way you turn it, either. I'm struggling to get my head around how the 74LS74 works and why I need the 74LS14, or in fact why I need a dual flip-flop when I seem to only be using one channel...

The datasheets, for convenience:
Encoder: http://www.ctscorp.com/components/datasheets/288.pdf
74LS74: http://docs-europe.electrocomponents.com/webdocs/0021/0900766b80021806.pdf
74LS14: http://docs-europe.electrocomponents.com/webdocs/0024/0900766b80024ea8.pdf

So yeah, if anyone has any idea what's going on (I assume there's a lot more to the circuit diagram than has been labeled!), I'd love to know your thoughts. Seeing as I went ahead and bought the IC's I'd prefer to work out how to use them instead of a work around that doesn't involve them, but the priority is to get the encoder working.

Thanks guys!

Did you see the original web page and description:-
http://www.thebox.myzen.co.uk/Workshop/Rotary_Max.html

why I need the 74LS14

To clean up the contact bounce on the signal edges. The capacitors slow the edges down and remove the bounce but logic doesn't like slow edges so the 74LS14 restores the rise time and cleans them up.

why I need a dual flip-flop when I seem to only be using one channel.

Cos they only come in pairs.

but the second digit will go high and low (seemingly) randomly and loop like that

Sounds like it is not wired up right or hasn't got any supply decoupling on the chips:-
http://www.thebox.myzen.co.uk/Tutorial/De-coupling.html

I only saw the diagram after searching for 'rotary encoder' and clicking some links, I do tend to jump the gun basically all the time so I saw the diagram and ordered the IC's without actually researching why I was buying them! I noticed (literally about half an hour ago) that the pins and the assignments don't match up; Pin 5 is labeled as D, but 1D is pin 2 and so on. I've tried wiring it up according to the assignments rather than numbers now, I've got it working a bit better, but still not working properly. Now if I run the serial monitor the 'step' is always high but the direction does change, but two of the four positions are "0" and the other two are "1", as if I'd just connected the encoder's A or B pin directly to the Arduino's 'direction' pin.

As I understand it, this circuit will basically output alternating high and low on the step pin, and then with the direction pin it'll be high if I rotate it one way and low the other way, is that right? Could I skip the 74LS74 and do the decoding in software? Problem is that would be far more cumbersome that way, and I would like to learn as much as possible so I'd like to do it with the 74.

I'm just off to read those links you sent, thank you very much for the help, once again! I didn't even know decoupling was a thing.

As I understand it, this circuit will basically output alternating high and low on the step pin, and then with the direction pin it'll be high if I rotate it one way and low the other way, is that right?

That is correct.

Could I skip the 74LS74 and do the decoding in software?

Yes you could but then you need to make sure you sample the encoder fast enough so you don't skip states.

Note there are two types of rotary encoder. One that holds all the states as you rotate it. The other where each click produces only a transitory state briefly and then returns to the normal state.

If you look at that schematic it is in two parts. The first is the capacitors and the 7414 that stop the contact bounce and the second is the D-type latch that sorts out the direction. The step output is simply one of the encoder's outputs and will change directly with it. On the rising edge of this signal the state of the other output from the encoder is latched or remembered. This will be always the same for the same direction of rotation.

There are two different pinouts for 7474 chips so check the data sheet for which one you have.

To do this in software you have to wait for a positive transition on one encoder output and sample the other immediately after, that will tell you if it is a clockwise or anti clockwise rotation just like the hardware, but you have to be looking at the step signal all the time or use interrupts. It depends on how important it is in your application not to miss a step.

Grumpy_Mike:
Note there are two types of rotary encoder. One that holds all the states as you rotate it. The other where each click produces only a transitory state briefly and then returns to the normal state.

If you look at that schematic it is in two parts. The first is the capacitors and the 7414 that stop the contact bounce and the second is the D-type latch that sorts out the direction. The step output is simply one of the encoder's outputs and will change directly with it. On the rising edge of this signal the state of the other output from the encoder is latched or remembered. This will be always the same for the same direction of rotation.

Ah, that could be the problem! As my encoder doesn't reset after each state, it will only 'step' once every two physical steps as each pin goes low, high, high, low... I think? I can't imagine how else I could just 'listen' to one pin for the step.

Also I'm looking at the pinout for my encoder and matching it to the debouncing diagram, but there's a problem in that the Q, CLK and D are labelled, then 6 and 4 are earthed, but I'm not sure which out of CLR, PRE and the Q with a line over it (in fact each of those are overlined) 6 and 4 in the diagram are and what to do with the pin that's left over.

Maybe I could do it in software and try to predict which way the encoder is going depending on which way it was going before a step was skipped? Or just get an optical (at least I'm guessing that's how they can reset to a default position) encoder, if I could find some cheap enough. Just realised I forgot to check Farnell once again.

Does you application require absolute repeatability of position?

No, I probably should have explained what I want to do with it. All I really want it to do is tell the Arduino which direction the user is rotating it, that's all, in pseudo (not at all accurate) code it would be something like:

if (encoder == increased){
digitalWrite (outputUp, HIGH);
} else if (encoder == decreased){
digitalWrite (outputDown, HIGH);
}

All that matters is which way it's going, not where it starts and ends up.

Edit:
Originally I was hoping to have a variable for the current value of the two encoder pins, then when the encoder is rotated the Arduino would read the pins and decide which direction it was going. With Mike's circuit that would be made a bit easier in that it would just read a 'step' variable and wait for a pulse, then write the result of the direction pin to the required output.

and the Q with a line over it (in fact each of those are overlined)

When a logic name has a line over it it means NOT or negative logic. That is to say the name is true when the signal is a logic zero (or false). So an input named clear would clear the output (set to zero) when the input was at a logic one. However, clear with a bar over it would indicate that the output would be cleared only when there was a logic zero on the input.
The preset and clear lines should in this circuit be connected to a logic one (that's 5V). The flip flop has two outputs Q and Q bar, these are always the inverse of each other, so what ever state the output Q is then Q bar is the inverse of this.

Your rotary encoder is fine for what you want to do.

The problem you are making for your self is that you are not looking for an edge you are looking at the level. To see an edge you have to remember what the level was like last time you read it (use a variable) then only when last time was a zero and this time is a one you have a step.

Grumpy_Mike:
The problem you are making for your self is that you are not looking for an edge you are looking at the level. To see an edge you have to remember what the level was like last time you read it (use a variable) then only when last time was a zero and this time is a one you have a step.

I think I'm following you, but I don't understand how to actually implement it. Going back to one of your earlier posts:

Grumpy_Mike:
The step output is simply one of the encoder's outputs and will change directly with it.

This is the bit that confuses me the most. I understand that you mean the change from low to high on one encoder output basically 'clocks' the Arduino to tell it there has been a step, but if my encoder's outputs only switch from low to high on every other physical rotation step, how can it tell when there has been a step in between? If you refer to the encoder's data sheet, you can see the 2-bit model has one pin that goes low, high, high, low and the other is one step out of phase and goes low, low, high, high, so it would only 'clock' the Arduino once per two steps.

I kind of understand what you said directly after that, though I think I totally missed it the first time I read it:

On the rising edge of this signal the state of the other output from the encoder is latched or remembered. This will be always the same for the same direction of rotation.

However, I don't understand how to make the 7474 actually do that. It makes sense, though, I just can't quite get my head around it, but I feel like I'm getting close...

A 74LS74 is a latch. Its function is to transfer and hold the logic level on the D input to the Q output (and inverse on the Q bar output) when the clock signal goes from a zero to a one. That it it is an edge latched memory, it takes a snapshot of the D input every transition of the clock.

but if my encoder's outputs only switch from low to high on every other physical rotation step, how can it tell when there has been a step in between?

With that circuit you only get a sample on the positive edge, that is every other click for your encoder. If you want to get a sample every click then you need two of these circuits (remember there are two D-type latches in one package and six inverters). On the second circuit you need to feed it with the inverse of the signals (put them through a spare inverter). Then you have two steps and two direction signals, these could be combined with another gate (an OR or NOR gate) or fed directly to the arduino.

Or you can use interrupts generated off each edge like in these links:-
http://www.arduino.cc/playground/Main/RotaryEncoders
http://arduino.cc/playground/Main/RotaryEncoderAcceleration

Grumpy_Mike:
A 74LS74 is a latch. Its function is to transfer and hold the logic level on the D input to the Q output (and inverse on the Q bar output) when the clock signal goes from a zero to a one. That it it is an edge latched memory, it takes a snapshot of the D input every transition of the clock.

I stepped away from this for a while to work on something else, I've just come back and this has finally clicked... I've found that if I hold CLR and PRE high, I can get an output which stays high if I rotate it one direction and goes low if I rotate it the other, so that's something.

However I haven't gotten round this part yet:

If you want to get a sample every click then you need two of these circuits (remember there are two D-type latches in one package and six inverters). On the second circuit you need to feed it with the inverse of the signals (put them through a spare inverter). Then you have two steps and two direction signals, these could be combined with another gate (an OR or NOR gate) or fed directly to the arduino.

I've made a XOR gate from a SN74LS00N and fed the pre-7414 outputs from the encoder into it to get a step-per-step output (if you see what I mean?), however, obviously, I can't use that for the 7474's clock pulse because it'll un-latch the direction signal too often. If I use the clock input as in the original diagram for the direction signal and the XOR gate for the step signal it works fine, except, predictably, it'll sometimes take up to three steps in the opposite direction to get the encoder to change direction. I knew this wouldn't work, I just wanted to experiment.

I'm not sure exactly how to wire up the second channel of the 7474. I can't quite work out if I should be inverting the 7414's output or the 7474's. I'm also not sure if I should swap the encoder's outputs for the second channel, i.e. if I use encoder pin A for channel 1's CLK and B for D, should I use B for channel 2's CLK and A for D? I'm guessing I should, otherwise I'd just be inverting the clock signal which wouldn't really help me get a sample for every click. I'm also at a loss as to what I should do with D; I'm guessing they'll mirror each other so I could just use one and leave the other floating and use a code something like:

if (step == HIGH){
if (1D == HIGH){
variable ++;
} else if (1D == LOW){
variable --;
}
}

This schematic is based on me inverting the 7414's output rather than the 7474's. Is this anywhere near correct?

Oh yeah, I figured the clock's XOR gate was necessary to turn:
0110
0011

into:
0101.

Once again, thank you all for the help, Mike!

Is this anywhere near correct?

One obvious error is you have wired both Flip-flop's Q bar signals to ground. If you don't need them just leave them disconnected. What you have is a short circuit condition for those two output pins.

Lefty

Read that again:-

If you want to get a sample every click then you need two of these circuits (remember there are two D-type latches in one package and six inverters). On the second circuit you need to feed it with the inverse of the signals (put them through a spare inverter). Then you have two steps and two direction signals, these could be combined with another gate (an OR or NOR gate) or fed directly to the arduino.

You have sent the clock of the first 7474 into the D of the second one. The clock signal should always come from the same side of the rotary encoder only inverted into the second 7474. The same goes for the D signal.
Like lefty says the Q bar outputs should not be connected to ground.

Grumpy_Mike:
Read that again:-

If you want to get a sample every click then you need two of these circuits (remember there are two D-type latches in one package and six inverters). On the second circuit you need to feed it with the inverse of the signals (put them through a spare inverter). Then you have two steps and two direction signals, these could be combined with another gate (an OR or NOR gate) or fed directly to the arduino.

You have sent the clock of the first 7474 into the D of the second one. The clock signal should always come from the same side of the rotary encoder only inverted into the second 7474. The same goes for the D signal.
Like lefty says the Q bar outputs should not be connected to ground.

Ok, I know I'm missing something here... Surely if I invert the same output I'll just have the same signal, only two steps behind. If I want to get a pulse for every detent on the encoder, it would have to be one step behind.

I mean, if you rotate the encoder, A outputs:
011001100110

So if you invert that and combine it with the first you get:
011001100110
100110011001.

I can't see how you'd get a signal that goes 010101010101 from that... However, if you were to use the signal from B you could use a XOR gate to get the required signal.

There must be something I've missed, surely?
Thank you, as always!

There must be something I've missed, surely?

The clock signal transfers the value on the D input to the Q output on the positive edge of the clock.
If you invert the clock for the second latch then that captures the signal on the otherwise ignored falling edge.

If still leaves you with two step signals to combine.

The best way to get data on all four edges of the quadrature signal is to use this circuit:-
http://www.thebox.myzen.co.uk/Workshop/Rotary_Max.html

Grumpy_Mike:
The best way to get data on all four edges of the quadrature signal is to use this circuit:-
Rotary Max

I've just built that in a simulator and it seems to work perfectly, I don't know why I didn't try that the first time I read that post... Your site is great, thank you for sharing! I'll be sure to let you know if it works in real life, too, but until I've gotten the parts I'll just carry on with the 7474.

Thanks again!

(edit: In your article you say to interface the counter's output with the Arduino using an input shift register, will a 4021 PISO shift register do the job?)

will a 4021 PISO shift register do the job?

Yes anything that will get those bits in will do.

I was trying to use the original schematic posted by Grumpy Mike but found the pin numbers were wrong... Here is the schematic as I have it working with an arduino.

Thanks, there are two pinouts available on the 7474 chips and my original diagram used the alternative origional pinout for the chip.

Shouldn't that circuit be updated to use 74HC14 and 74HC74's ?