Need help using multiple 5 pin rotary encoders

Hello all. Let me start by saying I am very new to using arduino hardware and software and have little experience with this type of coding. I have a prjoect started that uses code from a YT video, and for a single encoder it works great. My project however will use 4, 5 pin rotary encoders. I have tried using an array (probably incorrectly) to list all 4 encoders together with no success, as well as listing out 4 separate lines for each encoder, also unsuccessfully.

This is the code I have currently. I am working off with an Arduino Mega 2560 as my project is fairly large. Currently, the code only works for this one encoder only, located in pins 28 (DT) 29 (SW) and 30 (CLK). The other 3 encoders are in groups of 3 on the board, (32-34, 36-38, 40-42). I've tried swapping the pin numbers in the code below to a different encoder and it doesn't work.

Question 1 - why does only one encoder work?
Question 2 - what is the best way to build out the code to work with all 4 encoders?

#include <BfButton.h>

//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 counter = 0;
int angle = 0; 
int aState;
int aLastState;  
 
//Button press hanlding function
void pressHandler (BfButton *btn, BfButton::press_pattern_t pattern) {
  switch (pattern) {
    case BfButton::SINGLE_PRESS:
      Serial.println("Single push");
      break;
  }
}
//2
 
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;
}

Any help is greatly appreciated!

If I understand correctly, this is the code that works, yes?

Do you think it might be helpful to also show us the code that doesn't work, so we can see what you might be doing wrong there?

Where you use btn make that an array so btn[4] needs to be created then all your code references to btn needs to be changed to btn[X] where X is the 1 of 4 encoders you want to use.
Of course you will need 4 btnPins as well.

Code like

btn.onPress(pressHandler);

needs to change to something like

btn[X].onPress(pressHandler[X]);

Hmm, I just noticed something. You say that pins 28, 29, 30 are for one encoder and other pins for additional encoders. That is fine, but your code does not show any possible way to specify all 3 pins, only the btnPin as in 29. I see no way to fix that given your code.

So changing these values to a different setup of pins for a different encoder doesn't work.

CURRENT

int btnPin=29;
int DT=28; //Change to value on board
int CLK=30; //Change to value on board

NEW - DOESN'T WORK

int btnPin=33;
int DT=32; //Change to value on board
int CLK=34; //Change to value on board

I'm assuming something here is the main problem, preventing any array fix as well.

I just noticed the library you are using has a sample with multiple buttons. Just modify that sample for your use.

BTW, that is NOT my favourite encoder/button library.

Here is a multi encoder/button library example I have used.

/**
 * This example demostrates how to create multiple encoders or buttons.
 * 
 * ** NOTE ** 
 * This example uses a single encoder and multiple buttons because UNOs and other Arduinos 
 * with limited hardware interrupts will struggle to perform well (read: reliably) with 
 * multiple encoders. 
 * ** Teensys will handle multiple encoders without any issues *** (they have hardware 
 * interupts on all digital pins).
 * See https://www.pjrc.com/teensy/td_libs_Encoder.html for details.
 * 
 */
#include <EncoderButton.h>

/**
 * Instatiate an EncoderButton.
 * For Arduino Uno, the hardware interrupts are pins 2 & 3
 * For Teensy, you can use any digital pin.
 */
EncoderButton firstEncoderButton(2, 3, 4);
EncoderButton secondButton(14); //The first button is on the encoder!
//. . .
EncoderButton nthButton(15);


/**
 * A function to handle the first encoder 'encoder' event
 */
void onFirstEncoder(EncoderButton& eb) {
  Serial.print("first encoder incremented by: ");
  Serial.println(eb.increment());
  Serial.print("first encoder position is: ");
  Serial.println(eb.position());
}

/**
 * A function to handle the first encoder 'clicked' event
 */
void onFirstButtonClicked(EncoderButton& eb) {
  Serial.print("First button clickCount: ");
  Serial.println(eb.clickCount());
}


/**
 * A function to handle the second button 'clicked' event
 */
void onSecondButtonClicked(EncoderButton& eb) {
  Serial.print("Second button clickCount: ");
  Serial.println(eb.clickCount());
}

/**
 * A function to handle the second button 'clicked' event
 */
void onNthButtonClicked(EncoderButton& eb) {
  Serial.print("Nth button clickCount: ");
  Serial.println(eb.clickCount());
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  delay(500);
  Serial.println("EncoderButton multiple encoder/button example");

  //Link the event(s) to your function
  firstEncoderButton.setEncoderHandler(onFirstEncoder);
  firstEncoderButton.setClickHandler(onFirstButtonClicked);
  secondButton.setClickHandler(onSecondButtonClicked);
  nthButton.setClickHandler(onNthButtonClicked);



}

void loop() {
  // put your main code here, to run repeatedly:
  // You must call update() for every defined EncoderButton.
  firstEncoderButton.update();
  secondButton.update();
  nthButton.update();
}

I am not familiar with the MEGA, can you show a diagram highlighting exactly what pins you are using? When I look at the pinout diagram from Arduino I do not see 28, 29, 30, I see D28, D29, D30.

EDIT: Nevermind, there is no D28, it's just 28.

I have a Mega and a 5 pin encoder sitting on a shelf beside me.

Show me a sketch that doesn't work and I can try it out.

The Mega2560 has six interrupts. Each rotary encoder needs two interrupt pins.
6 interrupts / 2 interrupt pins per encoder = 3 encoders.

Pin  2 (Interrupt 0) 
Pin  3 (Interrupt 1) 
Pin 21 (Interrupt 2) 
Pin 20 (Interrupt 3) 
Pin 19 (Interrupt 4) 
Pin 18 (Interrupt 5)

I changed the int btnPin line to this array int btnPin[4]= {29, 33, 37, 41};. This alone removes all button functionality.

The second part of your post says to change btn.onpress(pressHandler); to this btn[X].onPress(pressHandler[X]); Am I to declare each encoder button separately above? Like btn[1] btn[2]?

By the way; your original sketch? With the pins changed as in post #5? Worked just fine. So as I suspected, you're changing something else you haven't shown. Which is why I asked to see a sketch that didn't work. Twice.

Shrug. Can't help someone who won't even reply. I'm done here.

I shared everything in my sketch haha, sounds like you have better things to do anyway

When you say each encoder needs two inturrupts, does this mean physically on the board or somewhere in the code?

I don't understand your question.
I will restate.
Now that you have an array of btn's, everywhere you use btn you must change to btn[array-member]
The onPress of course requires the specific object reference as in btn[which object], but if you ever might have different onPress actions then you need either to be able to detect which btn in the handler and that may happen through the 1st parameter btn, or as I suggested just create 4 onPress handlers for 4 buttons. That way you can customize each button onPress function as much as you like.

I might be wrong, but is it not common to just poll for an encoder change, especially since it is directional. How does the interrupt work, rising for CW and falling for CCW? I have no clue, just hypothesizing.

The two pins will change levels (physically making and breaking contacts inside the encoder).
Direction is determined when one leads and the other lags.
CW = data leads clock, CCW = clock leads data

Yes. Two interrupt pins to read which pin has a level change first.

Be a sport and remove your Post #14. You are wrong.

This is legit my entire sketch. The wiring to the board has 4 encoders, in the pins I described previously, in the order DT,SW,CLK for each one. The is a common ground and 5v power wire. That is all. I don't understand what it is that I'm not sharing.

//Dashboard Button Box V1


//ROTARY ENCODER #1
#include <BfButton.h>

//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 counter = 0;
int angle = 0; 
int aState;
int aLastState;  
 
//Button press hanlding function
void pressHandler (BfButton *btn, BfButton::press_pattern_t pattern) {
  switch (pattern) {
    case BfButton::SINGLE_PRESS:
      Serial.println("Single push");
      break;
  }
}
//2
 
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);
  btn2.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;
}

You could also try a different library... this library seems to just do pin polling (maybe it uses pinchange, which every pin can do), and might allow for multiple instances... GitHub - mathertel/RotaryEncoder: RotaryEncoder Arduino Library · GitHub