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;
}
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.
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.
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.
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 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
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;
}