Need help using multiple 5 pin rotary encoders

I'm not sure that's true. I believe 2 interrupt pins per encoder is the best, but 1 interrupt pin per encoder is still pretty good, and no interrupt pins per encoder can be quite poor. It all depends what level of performance you need. I suspect the common 5-pin encoders, which have detents, probably don't benefit much, if at all, from having 2 interrupt pins each, because of those detents?

I see, use one interrupt. I "learned" to use two (like a two-break-beam sensor), but can re-learn better ways. I just started reading one rotary encoder library to see how it does the job. I admire the authors' work.

The original source I got this code from is here. They mention in a comment that you can duplicate this piece to add additional encoders but that more code would be needed below.

BfButton btn(BfButton::STANDALONE_DIGITAL, btnPin, true, LOW);

I've added a second line to use the inputs from the second encoder, first encoder still works great but no inputs from the second. What code would I need to add below to make a second encoder work?

Duplicated and renamed second instance of top code.

//ENCODER #1
int btnPin=29;
int DT=28; //Change to value on board
int CLK=30; //Change to value on board
BfButton btn(BfButton::STANDALONE_DIGITAL, btnPin, true, LOW);
//ENCODER #2
int btnPin2=33;
int DT2=32; //Change to value on board
int CLK2=34; //Change to value on board
BfButton btn2(BfButton::STANDALONE_DIGITAL, btnPin2, true, LOW);

That's a bad sign! Duplicating code is generally considered a "sin" amongst experienced coders.

You would need setup() and loop() functions, at the very least! I'm sure you get my point. If you have 90% of the code, we will probably fill in the other 10% for you. If you expect us to fill in 90% for you.... We could do that easily, but, we want you to learn to fish.

Fair enough. Would it be easier to just make a new section like this for each encoder? Or can I just do the setup() and loop() lines with btn in them?

Full button section

//Button press hanlding function
void pressHandler (BfButton *btn, BfButton::press_pattern_t pattern) {
  switch (pattern) {
    case BfButton::SINGLE_PRESS:
      Serial.println("Single push");
      break;
  }
}
 
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.println(angle);
  pinMode(CLK,INPUT_PULLUP);
  pinMode(DT,INPUT_PULLUP);
  aLastState = digitalRead(CLK);
 
  //Button settings
  btn.onPress(pressHandler);
}
 
void loop() {
  // put your main code here, to run repeatedly:
 
  //Wait for button press to execute commands
  btn.read();

  aState = digitalRead(CLK);
 
  //Encoder rotation tracking
  if (aState != aLastState){     
     if (digitalRead(DT) != aState) { 
       counter ++;
       angle ++;
     }
     else {
       counter--;
       angle --;
     }
     if (counter >=100 ) {
       counter =100;
     }
     if (counter <=-100 ) {
       counter =-100;
     }
     Serial.println(counter); 
  }   
  aLastState = aState;
}

Yes, it would be easier. But that would mean duplicating the code. Which is, of course, a sin...

Lost me there... You can't duplicate the setup() or loop() functions, that would give an error.

One way is by using arrays:

  • step through each encoder
  • read each pushbutton
  • debounce each pushbutton
  • read each clock state for change
  • read each data state
  • determine CW or CC by clock and data states

This working simulation is not a "drop-in" replacement for your project, but can show you how you might use multiple encoders. The code does not use external interrupts or libraries (but acknowledge the use of built-in libraries and their use of interrupts). Beware; simulation code might not work with real hardware, but it usually does well.

code for wokwi preserved here
// multiple encoders
// https://forum.arduino.cc/t/need-help-using-multiple-5-pin-rotary-encoders/1442587/

byte clockpin[] = { 2, 5, 8, 11, 14, 17 };                                    // "clock" pin array
byte datapin[] = { 3, 6, 9, 12, 15, 18 };                                     // "data" pin array
byte pushpin[] = { 4, 7, 10, 13, 16, 19 };                                    // "push" pin array
const byte arraysize = sizeof(clockpin) / sizeof(clockpin[0]);                // number of encoders
byte pushstate[arraysize];                                                    // state of each button
byte clockstate[arraysize], lastclockstate[arraysize], datastate[arraysize];  // states
byte encocount[arraysize];                                                    // encoders count 0 to 255
byte pushcount[arraysize];                                                    // pushbuttons count 0 to 255

unsigned long pushtimer[arraysize], timeout = 90;  // adjust timeout for lowest value


#define BAUD 115200

void setup() {
  Serial.begin(BAUD);                              // initialize Serial Monitor
  for (byte i = 0; i < arraysize; i++) {           // configure DIO pins
    pinMode(clockpin[i], INPUT_PULLUP);            //
    pinMode(datapin[i], INPUT_PULLUP);             //
    pinMode(pushpin[i], INPUT_PULLUP);             //
    lastclockstate[i] = digitalRead(clockpin[i]);  // first state reading
  }
}

void loop() {
  for (byte i = 0; i < arraysize; i++) {

    // pushbutton
    pushstate[i] = digitalRead(pushpin[i]);                              // read each pushbotton
    if ((pushstate[i] == LOW) && (millis() - pushtimer[i] > timeout)) {  // debounce pushbutton
      pushtimer[i] = millis();                                           // set new timer
      ++pushcount[i];                                                    // increment pushbutton count
      showstates("Button : ", i, " | Presscount: ", pushcount[i]);       // send data to formatter
    }

    // clockstate
    clockstate[i] = digitalRead(clockpin[i]);  // read clock state for each encoder
    if (clockstate[i] != lastclockstate[i]) {  // if clock state changed
      lastclockstate[i] = clockstate[i];       // store state

      // datastate
      datastate[i] = digitalRead(datapin[i]);                         // datastate for each encoder
      if (datastate[i] == 1 && clockstate[i] == 0) {                  // states for CC rotation
        encocount[i]++;                                               // increment counter
        showstates("Encoder: ", i, " | CW | Count: ", encocount[i]);  // send data to formatter
      }
      if (datastate[i] == 0 && clockstate[i] == 0) {                  // states for CW rotation
        encocount[i]--;                                               // decrement counter
        showstates("Encoder: ", i, " | CC | Count: ", encocount[i]);  // send data to formatter
      }
    }
  }
}

void showstates(char *name, int number, char *action, int count) {  // Serial Monitor formatting
  Serial.print(name);
  Serial.print(number);
  Serial.print(action);
  Serial.print(count);
  Serial.println();
}
diagram.json for wokwi and for the nerds
{
  "version": 1,
  "author": "fish and chips",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-arduino-nano", "id": "nano", "top": 33.6, "left": -0.5, "attrs": {} },
    { "type": "wokwi-ky-040", "id": "encoder1", "top": -27.1, "left": -144.8, "attrs": {} },
    { "type": "wokwi-ky-040", "id": "encoder2", "top": -103.9, "left": -144.8, "attrs": {} },
    { "type": "wokwi-ky-040", "id": "encoder3", "top": -180.7, "left": -144.8, "attrs": {} },
    { "type": "wokwi-ky-040", "id": "encoder4", "top": -257.5, "left": -144.8, "attrs": {} },
    { "type": "wokwi-ky-040", "id": "encoder5", "top": 107.3, "left": -144.8, "attrs": {} },
    { "type": "wokwi-ky-040", "id": "encoder6", "top": 184.1, "left": -144.8, "attrs": {} }
  ],
  "connections": [
    [ "nano:2", "encoder4:CLK", "orange", [ "v0" ] ],
    [ "nano:5", "encoder3:CLK", "orange", [ "v0" ] ],
    [ "nano:8", "encoder2:CLK", "orange", [ "v0" ] ],
    [ "nano:11", "encoder1:CLK", "orange", [ "v0" ] ],
    [ "nano:3", "encoder4:DT", "blue", [ "v0" ] ],
    [ "nano:6", "encoder3:DT", "blue", [ "v0" ] ],
    [ "nano:9", "encoder2:DT", "blue", [ "v0" ] ],
    [ "nano:12", "encoder1:DT", "blue", [ "v0" ] ],
    [ "nano:4", "encoder4:SW", "green", [ "v0" ] ],
    [ "nano:7", "encoder3:SW", "green", [ "v0" ] ],
    [ "nano:10", "encoder2:SW", "green", [ "v0" ] ],
    [ "nano:13", "encoder1:SW", "green", [ "v9.6", "h-19.2", "v-105.7" ] ],
    [ "nano:5V", "encoder4:VCC", "red", [ "v0" ] ],
    [ "nano:5V", "encoder3:VCC", "red", [ "v0" ] ],
    [ "nano:5V", "encoder2:VCC", "red", [ "v0" ] ],
    [ "nano:5V", "encoder1:VCC", "red", [ "v0" ] ],
    [ "nano:GND.1", "encoder4:GND", "black", [ "v0" ] ],
    [ "nano:GND.1", "encoder3:GND", "black", [ "v0" ] ],
    [ "nano:GND.1", "encoder2:GND", "black", [ "v0" ] ],
    [ "nano:GND.1", "encoder1:GND", "black", [ "v0" ] ],
    [ "encoder5:CLK", "nano:A0", "orange", [ "h0" ] ],
    [ "encoder5:DT", "nano:A1", "blue", [ "h0" ] ],
    [ "encoder5:SW", "nano:A2", "green", [ "h0" ] ],
    [ "encoder5:VCC", "nano:5V", "red", [ "h0" ] ],
    [ "encoder5:GND", "nano:GND.1", "black", [ "h0" ] ],
    [ "encoder6:CLK", "nano:A3", "orange", [ "h0" ] ],
    [ "encoder6:DT", "nano:A4", "blue", [ "h0" ] ],
    [ "encoder6:SW", "nano:A5", "green", [ "h0" ] ],
    [ "encoder6:VCC", "nano:5V", "red", [ "h0" ] ],
    [ "encoder6:GND", "nano:GND.1", "black", [ "h0" ] ]
  ],
  "dependencies": {}
}

Built on this reference: wokwi-ky-040 Rotary Encoder Reference | Wokwi Docs

Good looking out! This is definitely helpful as I am a visual learner.

I got this to work perfectly on a wokwi example, but when I copy that code into Arduino IDE, I still ony get one working encoder. I used the same code you provided, just changed the values for the pins to match my project.

Prolly.

Try reading all the states while nothing is being pressed or turned. Identify which encoder works, and move it around, and also move the non-working encoders into the working position.

I moved the working encoder to 3 new pins, works fine. Tried the other encoders where the first one was, nothing. All the wiring seems to be good. Really not sure at this point

"Other encoders" are either broken or mis-wired. [edit] or they use "half-pulse" per detent

Also... try a library to find broken encoders, or make your project work... this one has "multiple encoders" example: NewEncoder/examples/MultipleEncoders/MultipleEncoders.ino at master · gfvalvo/NewEncoder · GitHub

I'm leaning towards bad encoders. Tried every possible wiring solution on the board, still only get the one to work. I'll test the voltage on the the 3 that aren't working and go from there, try to redo the wiring. I appreciate the help