Pages: 1 [2]   Go Down
Author Topic: Rotary encoders, 74LS14's and 74LS74's  (Read 6493 times)
0 Members and 1 Guest are viewing this topic.
UK
Offline Offline
Jr. Member
**
Karma: 1
Posts: 53
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

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?)
« Last Edit: May 16, 2011, 04:44:51 pm by neema_t » Logged

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 634
Posts: 34551
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
will a 4021 PISO shift register do the job?
Yes anything that will get those bits in will do.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Logged

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 634
Posts: 34551
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

0
Offline Offline
Shannon Member
****
Karma: 215
Posts: 12467
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

[ I won't respond to messages, use the forum please ]

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the circuit Grumpy Mike... it does work great to simplify encoder input for my UI.

BTW the pin-outs are the same for the HC parts so here is the updated drawing:

Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 227
Posts: 6637
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Personally, I don't use extra ICs for connecting rotary encoders to the Arduino. They're just not necessary. Used properly, these encoders don't need to be debounced either.

To connect a single rotary encoder, connect its centre pin to ground and the 2 outer pins to Arduino pins configured as inputs with pullup enabled. If you use pins 2 & 3 on a Uno, you can have an interrupt generated when the encoder moves, saving the need for polling it.

To connect 2 encoders, duplicate this arrangement (4 Arduino pins needed).

To connect N > 3 encoders without using 2N pins, connect each centre pin of an encoder to its own Arduino output pin. The left pins of the encoders each connect to the cathode of a signal diode (1N4148 or similar), the anodes being commoned and connected to an Arduino input pin with pullup enabled. Same arrangement for the right pins but different Arduino input pin. Total pins needed = N + 2 for N encoders.

Here's the code I use for the encoder:

Code:
class RotaryEncoder {
  unsigned int state;
  int pin0, pin1;
  int ppc;
  int change;
  static RotaryEncoder *encoderUsingInterrupts;  

  unsigned int readState() {
    return (digitalRead(pin0) == HIGH ? 1u : 0u) | (digitalRead(pin1) == HIGH ? 2u : 0u);
  }

  static void interruptPoll() {
    if (RotaryEncoder::encoderUsingInterrupts != 0) {
      RotaryEncoder::encoderUsingInterrupts->poll();
    }
  }

public:
  RotaryEncoder(int p0, int p1, int pulsesPerClick) :
  pin0(p0), pin1(p1), ppc(pulsesPerClick), change(0), state(0) {
  }

  void init() {
    pinMode(pin0, INPUT);
    pinMode(pin1, INPUT);
    digitalWrite(pin0, 1);
    digitalWrite(pin1, 1);
    change = 0;
    state = readState();
    if ((pin0 == 2 && pin1 == 3) || (pin0 == 3 && pin1 == 2)) {
      RotaryEncoder::encoderUsingInterrupts = this;
      attachInterrupt(0, interruptPoll, CHANGE);
      attachInterrupt(1, interruptPoll, CHANGE);
    }
  }

  void poll() {
    static int tbl[16] = {
      0, +1, -1, 0,  -1, 0, 0, +1,  +1, 0, 0, -1,  0, -1, +1, 0   };
    unsigned int t = readState();
    change += tbl[(state << 2) | t];
    state = t;
  }

  int getChange() {
    int r;
    noInterrupts();
    if (change >= ppc) {
      r = change/ppc;
    }
    else if (change <= -ppc) {
      r = -((-change)/ppc);
    }
    else {
      r = 0;
    }
    change -= (r * ppc);
    interrupts();
    return r;
  }
};

RotaryEncoder *RotaryEncoder::encoderUsingInterrupts = 0;

Then declare an encoder like this:

Code:
RotaryEncoder encoder(encoderPin1, encoderPin2, 4);
 

and call encoder.init() in setup(). If you're not using a single encoder connected to pins 2 and 3, you'll need to call encoder.poll() every millisecond or so. For 3 or more encoders connected with diodes, poll each encoder in turn with its own output pin set low and the output pins for the other encoders set high.
« Last Edit: August 09, 2011, 12:39:24 pm by dc42 » Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 634
Posts: 34551
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I don't use extra ICs for connecting rotary encoders to the Arduino. They're just not necessary. Used properly, these encoders don't need to be debounced either.
I would totally disagree with you. True optical encoders don't bounce but contact ones do. Your code will miss some bouncing pulses. My circuit was developed for a situation where I couldn't afford to miss a pulse. Maybe you experience of different makes of encoders is limited.

It would be good if you could modify the post, select the code and hit the # icon to get it into a box.
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 227
Posts: 6637
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes of course the contacts bounce, but if you use use the fact that the encoder is outputting Gray code and monitor all changes in the state of the contacts (as my code does), then a bounce just looks like the encoder advanced a quarter click, went back again, then advanced again - rather than advancing a quarter click in one go. If you poll the encoder very quickly then your application might see this, but it typically doesn't matter because the final result is the same. In the unlikely event that it makes a difference to your app, you can add software debounce to my code (I originally included it but removed it). OTOH if you use the make or break of one of the contacts as a clock to sample the other, then you certainly need to debounce the contact you are using as the clock.

Thanks for the hint about # for code - I hadn't spotted that.
« Last Edit: August 09, 2011, 12:41:24 pm by dc42 » Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Pages: 1 [2]   Go Up
Jump to: