# Rotary encoder mistakes knob turned for button pressed

I'm using this encoder https://www.cuidevices.com/product/resource/acz09.pdf to scroll through a menu and I'm having an issue where when you turn it clockwise, it thinks the button was pressed (this does not happen when I turn it counter-clockwise). They're both on two different interrupt pins (2,3 on Arduino Pro Mini) and my code is included below as well as the schematic.

#include <SoftwareSerial.h>
#define Button1 2
#define pinA 3
#define pinB 4

//encoder setup
String bits[] = {"00","01","10","11"};
int bump[] = {0,0,-1,1};
byte state = 0;
int Level = 1;
byte M_pressed = 0;
byte T_pressed = 0;
unsigned long lastButtonPress = 0;
int page = 0;
int setting = 0;
String Motor;
int MotorState = 0;
String Heat;
int HeatState = 1;
byte change = 1;
byte Tempchange = 1;
unsigned long windowStartTime = millis();
float SetTemp;
int TempState =1;

double Setpoint, Input1, Output1, Input2, Output2;

SoftwareSerial OpenLCD(1,7); //RX,TX
byte contrast = 2;

void setup() {

Serial.begin(115200);

//encoder
pinMode(pinA,INPUT_PULLUP);
pinMode(pinB,INPUT_PULLUP);
digitalWrite(pinA,HIGH);
digitalWrite(pinB,HIGH);
pinMode(Button1,INPUT_PULLUP);

//interrupts
attachInterrupt(0,knobTurned,RISING);
attachInterrupt(1,buttonpressed,LOW);

OpenLCD.begin(9600);
}

//////Interrupts/////////////////////////////////////////////////////
void knobTurned(){

static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
// If interrupts come faster than 200ms, assume it's a bounce and ignore
if (interrupt_time - last_interrupt_time > 250)
{
state = 0;
state <<= 1;
//Serial.println(state);
if (setting == 0){                       //if you are in general menu, scroll through temp/motor
Level = Level + bump[state];
if (Level > 2) Level = 2;                //Level 2 is motor menu
else if (Level < 1) Level = 1;           //Level 1 is temp menu
Serial.println(Level);
}

else if (setting == 2){                       // if you are in motor menu, scroll through motor settings
MotorState = MotorState + bump[state];
if(MotorState > 4) MotorState=4;
else if (MotorState <0) MotorState=0;
Serial.println(MotorState);
}
else if (setting == 1){                    // if you are in temp menu, scroll through temp (res 0.5)
SetTemp = SetTemp + bump[state]*.5;
if (SetTemp > 75) SetTemp = 75;
else if (SetTemp < 25) SetTemp = 25;
Setpoint = SetTemp;
Serial.println(SetTemp);
}
change = 1;

}
}

void buttonpressed(){

static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
// If interrupts come faster than 200ms, assume it's a bounce and ignore
if (interrupt_time - last_interrupt_time > 250)
{

//Serial.println("pressed");
if (Level ==1){                       //if button is pressed at temperature setting
if (setting == 0){                   // enter into temperature menu if in general menu
setting =1;                       //Allow to scroll through temperature
Serial.println("enter Temp");
}
else if (setting ==1){               //if in temperature menu
Setpoint = SetTemp;
setting =0;                         //returns to main menu
Serial.println("Back T");

}
}
else if (Level ==2){                  //if button is pressed at motor setting
if(setting ==2)  {                 //if in motor menu
Serial.println("Back M");
}
setting =2;                       //Allow to scroll through motors
Serial.println("enter Motor");
}
}
delay(50);
}
last_interrupt_time = millis();
change = 1;

}

////////////////////////////////////////////////////////////////////

void loop() {
// put your main code here, to run repeatedly:
}

if (change == 1){
if (setting == 0){                // if in the general menu
if (Level == 1){                // if on temp arrow
OpenLCD.write('|');
OpenLCD.write('-');
OpenLCD.write(254); //Send command character
OpenLCD.write(128 + 20 + 0); //Change the position (128) of the cursor to 2nd row (64), position 0 (0)
OpenLCD.print("-> Set Temp: "); //For 16x2 LCD;
OpenLCD.print(SetTemp); //For 16x2 LCD
OpenLCD.print(" C");

OpenLCD.write(254);
OpenLCD.write(128 + 84 + 3);
OpenLCD.print("Set Motor");
}
else if (Level == 2){         //if on the motor arrow
OpenLCD.write('|');
OpenLCD.write('-');
OpenLCD.write(254);
OpenLCD.write(128 + 20 + 3);
OpenLCD.print("Set Temperature");
OpenLCD.write(254);
OpenLCD.write(128 + 84 + 0);
OpenLCD.print("-> Set Motor: ");
if (MotorState <= 0) Motor = "off";
else Motor = String(MotorState);
OpenLCD.print(Motor); //For 16x2 LCD
}
}
else if (setting == 1){        //Temperature menu
OpenLCD.write('|');
OpenLCD.write('-');
OpenLCD.write(254);
OpenLCD.write(128 + 20 + 6);
OpenLCD.print(SetTemp);
OpenLCD.print(" C");
OpenLCD.write(254);
OpenLCD.write(128 + 84 + 0);
OpenLCD.print("<- Click to Return");
}
else if (setting == 2){
OpenLCD.write('|');
OpenLCD.write('-');
OpenLCD.write(254);
OpenLCD.write(128 + 20 + 9);
if (MotorState <= 0) Motor = "off";
else Motor = String(MotorState);
OpenLCD.print(Motor);
OpenLCD.write(254);
OpenLCD.write(128 + 84 + 0);
OpenLCD.print("<- Click to Return");
}
change = 0;
}

if(setting ==0){
windowStartTime = millis();
OpenLCD.write(254); //Send command character
OpenLCD.write(128 + 0 + 3); //Change the position (128) of the cursor to 2nd row (64), position 0 (0)
OpenLCD.print("Temp = "); //For 16x2 LCD
OpenLCD.print(SetTemp);//12x
OpenLCD.print(" C"); //For 16x2 LCD
}
}


• I don't have an answer but a few things to check. I see you pull up the inputs and your knobTurned interrupt is on RISING. I am not sure if this is correct. Maybe change it to FALLING edge. I don't understand this row "state <<= 1;" What is this line of code supposed to do? You don't have an if statement there. Jul 16, 2021 at 18:48
• Spend some time making your schematic readable. At the moment it is pretty random. Have gnd pointing downwards. The r and c are reversed on the encoder. You want the encoder signal togo through the r then to the c and the port pin. Using interrupts for an encoder is not the most robust method - using a timer tick to sample and filter the inputs is a better solution. Jul 16, 2021 at 22:03
• Does this happen 100% of the time for every encoder tick or specific pattern of encoder ticks when turning left? If not then it is noise and you need to program filtering in for both button press and encoder. You just won't see a button press fake an encoder tick as often since there are much fewer of them. This happened to me once. Jul 17, 2021 at 1:48
• It is not every tick, just some of them usually when you turn the wheel very quickly. Changing the interrupt to FALLING fixed it for the most part; I've only had it happen twice since then. I don't quite understand why you mean by "program filtering in". How would that work? Jul 20, 2021 at 14:22