Multiplexing Rotary Encoders

Hello people,
Yesterday I managed to multiplex 4 rotary encoders using 2 hc4051c multiplexers.
Although everything was going ok when I tried for the first time, after some modifications (disconnected and reconnected my encoders and made an extra Serial.print in my code) only the rotary encoder on pin 7 was playing correctly, all other encoders had constantly their b pin high. Did I burn something?

When I was trying to make an encoder work with my arduino I figured I needed a pullup resistor otherwise I could make any code work.

Now that I have multiplexers in between, although I have set the input pins on the arduino to INPUT_PULLUP where the multiplexers send values, I don't know if this is the proper thing to do.

my code is:

int val;
int encoder0PinA = 5;
int encoder0PinB = 6;
int encoder0Pos = 0;
int encoder0PinALast = LOW;
int n = LOW;
int k = LOW;
byte encoders[4] = {4, 6, 7, 5};
int encoderValues[4] = {0, 0, 0, 0};
int previousEncoderPinAState[4] = {LOW, LOW, LOW, LOW};
int previousEncoderPinBState[4] = {LOW, LOW, LOW, LOW};

int midiNoteValues[8]; // array to hold the midi note number
int durationValues[8];
int velocityValues[8];
bool dirtyFlags[] = { true, true, true, true, true, true, true, true };
int *modeValues[] = { midiNoteValues, durationValues, velocityValues };
//char *notes = "aAbcCdDefFgG";
byte mode = 0;

const byte muxInput = A0;  // where the multiplexer in/out port is connected
const byte s0 = 4;
const byte s1 = 3;
const byte s2 = 2;

bool potValueChanged = true; //bool to know if pot value changed, needed for display update

int readSensor (const byte which)
{
  // select correct MUX channel on both muxes
  digitalWrite (s2, (which & 1) ? HIGH : LOW);  // low-order bit
  digitalWrite (s1, (which & 2) ? HIGH : LOW);
  digitalWrite (s0, (which & 4) ? HIGH : LOW);  // high-order bit
  //return analogRead (muxInput); // now read the sensor

  //read the values on encoderPinA and encoderPinB (the one comes from the first mux, and the other from the other).
  n = digitalRead(encoder0PinA);
  k = digitalRead(encoder0PinB);


  if ((previousEncoderPinAState[which] == LOW) && (n == HIGH)) {
    if (digitalRead(encoder0PinB) == LOW) {
      encoderValues[which] = encoderValues[which] - 1;
    } else {
      encoderValues[which] = encoderValues[which] + 1;
    }
    Serial.print("Encoder ");
    Serial.print(which);
    Serial.print(" value: ");
    Serial.println (encoderValues[which]);
  }
  previousEncoderPinAState[which] = n;

}

void getPotValues()
{
  for (int i = 0; i <= 3; i ++)
  {
    readSensor(encoders[i]);
  }
}

void setup() {
  pinMode (encoder0PinA, INPUT_PULLUP);
  pinMode (encoder0PinB, INPUT_PULLUP);
  pinMode (s0, OUTPUT);
  pinMode (s1, OUTPUT);
  pinMode (s2, OUTPUT);
  Serial.begin (9600);
}

void loop() {
  getPotValues();
}

Thank you!

1 Like

+1 Karma for using code tags and posting a proper schematic.

Your schematic could be simplified and improved by using a few 5V and GND symbols so there aren't so many crossed lines making the wiring hard to follow.

What I don't understand is why you are using two multiplexer chips to save only 3 Arduino pins, when you don't seem to be short of Arduino pins?

Thank you!
I'm using 2 multiplexers because my circuit will include 9 buttons and a lcd screen. I know I could use a bigger arduino but right now I'm in the process of learning. I started one month ago, and now I know the pins of hc4051 by heart :slight_smile:

Thank you for you advise

Also ++Karma for the same reason :slight_smile:

As you only want to select 4 outputs you don't need C connected to the Adruino, connect it to 5V, then only inputs 4,5, 6 and 7 ill be active and you save another pin.

I don't understand why you have not used inputs 0, 1, 2 and 3. It doesn't matter but I am curious to why.

I confess to not reading your code, but does it take into account that D2 must always be high for reading the last 4 inputs on the encoders?

You could use a 4052 which has 2 * 4 input multiplexers in one package.

Using the internal pull up resistors should be fine. I don't think you have done anything that will cause harm.

To test further I suggest you write some test code that outputs a very slowly changing (maybe every 15 seconds) binary output (00, 01, 10, 11) on D3 and D4 and use a meter or 'scope to check which encoder is actually connected to D5 and D6.

I'm about to use 4 more encoders, that is why I'm using these inputs.
Nice idea Perry, I'll try it as soon as I have me multimeter delivered to me.
Thank you for your suggestions!

:slight_smile:

So... 8 encoders, 9 buttons, an LCD (16x2 or 20x4?) and serial comms for midi (pins 0 & 1) ?

I would recommend getting a serial (i2c) backpack for the LCD. Makes the wiring simpler and needs only two Arduino pins (must be A4 & A5 on Nano).

For the buttons and encoders, you could wire them as a matrix. A 5 X 5 matrix would be just enough for your encoders and buttons and would need 10 Arduino pins. No multiplexer chips required.

The screen is 20x4 and has already i2c connection.

I've never thought about matrices because some operations have to be simultaneously one two, even three controls (maybe I'm wrong in thinking that this cannot be done with matrices).

Do you have any suggested read about this subject?

Also, whist tinkering with what I've made so far, I realized that pushing the encoders to the breadboard sometimes made them function properly, but not all of them.
Whenever I have a single encoder directly to arduno pins, it works as expected without any need for pushing.
I soldered on a perfboad my design (because the encoder feet are flimsy, but either a single one works (a random one), either none of them does.

I had the same effects when I was trying to make one to work until I activated pin pull up on the arduino pins.

I haven't found anything yet describing a design with muxes and rotary encoders, I'm still not sure if indeed they work together. :frowning:

You can ensure that a matrix can accurately read switches pressed simultaneously in a matrix by attaching a small diode in series with each switch (so two diodes for each rotary encoder). This prevents the "ghosting" effect that can cause false switch detections if diodes are not used.

The problem that can happen with rotary encoders and multiplexers is that pulses can be missed if the scanning is not fast enough. This is also true if they are part of a matrix. Even encoders connected directly to the Arduino pins can miss pulses if the code is not written correctly. With basic encoders this should not be an insurmountable problem. With high precision encoders which can be moved at a high speed, interrupts are sometimes needed to avoid loosing pulses.

Your problem still sounds like a wiring issue. A multimeter should help you find the problem.

1 Like

The problem that can happen with rotary encoders and multiplexers is that pulses can be missed if the scanning is not fast enough.

I agree with that. When I was trying to read 4 encoders I discovered that I needed to read them every millisecond at least to get a reliable output. I checked the output with an oscilloscope and discovered I didn't need to turn them very fast to get a pulse about 1ms wide, hence the need to read them that often. If you are going to read 4 of them in a matrix or via multiplexers you have to scan the lot every millisecond, so every 250 microseconds you have to be scanning an encoder.

It is possible to transfer the encoder work to a dedicated IC.

PerryBebbington:
I discovered that I needed to read them every millisecond at least to get a reliable output.

It will depend on how many steps per revolution the encoder has and how fast you turn it.

For a basic, 24-step, 2-channel encoder, for example, you would get 96 "edges" per revolution (48 per channel). Revolving at one revolution per second, the edges would be about 10ms apart.

If using a 5 x 5 matrix, scanning one row/column per ms would be just about fast enough.

But if the OP's encoders are higher resolution or will be spinning faster, then things will be more difficult.

Optimising the code by using direct port manipulation might help, but there could still be problems if anything momentarily delays the scanning.

Thank you guys. It was a wiring problem. Today I borrowed a multimeter and I saw that one of my multiplexers was not getting +5volts. I had some cold joins (is this what they call them?).

When I fixed my soldering everything worked just perfect! As for the speed, it is adequate. I'm making a midi sequencer, not medical equipment or some other time critical operations.

Now, the rotary encoders feature a push button. I could use a third multiplexer to utilize them, but I'm thinking that I could use a matrix, just to learn about them.

I don't know what the pros and cons are but I'll have a look and I'll decide. Multiplexers are inexpensive and, if they require less wiring they might be preferable.

Thank you all for your help.

:slight_smile:

Search for pictures of "wet" vs. "dry" solder joints on Google.

Multiplexers don't require less wiring than a matrix and are not faster. They will certainly make your circuit more complex. I can't see any point using mixing multiplexers for some buttons and a matrix for others in the same circuit.

What you could do, however, is use multiplexers to drive a matrix. This would save even more Arduino pins. Using one multiplexer to drive the matrix rows and another multiplexer to drive the columns, you could make a matrix of 64 buttons using only 7 Arduino pins, for example.

The push buttons on the encoders: are these 8 more buttons that you did not mention before, or are they 8 of the 9 buttons you mentioned?

If they are extra, you have a total of 33 buttons to scan. So your matrix could be 5x8 or 6x6.

It may be possible to combine two multiplexers into a 16-way multiplexer, so your matrix could be 3x16.

PaulRB:
The push buttons on the encoders: are these 8 more buttons that you did not mention before, or are they 8 of the 9 buttons you mentioned?

These are the eight of the nine I mentioned.
And here is the job so far...

Terumi,
I find this very useful for that kind of wiring on strip board and similar
Vero wiring tool

Today I borrowed a multimeter

You really should buy one. Even one costing £20 or so will make life so much easier. Not having one is like a joiner not having a hammer :slight_smile:

Hey people,
Not sure if I have to ask in another thread but, because in this one, there's a "history" I'll ask here.

The encoders, as I said feature a push button each.
When I'm connecting them to either a multiplexer or in a matrix, do I have to use pull down resistors? And what determines the value of each resistor?
If I'm using a multiplexer, do I have to have one on the ground pins of the ic, or do I need one for each button (I believe the latter).

Thank you

You only need one resistor per input pin. Wire your switches between the input pin and ground, and you can use the Arduino's internal pull-up resistors. The value of pull-up/pull-down down resistors is not critical. If using external resistors, anything between 4K7 and 47K should be fine. The internal pull-up resistors are around 30~40K.