Rotary encoder not working properly

I have an arduino uno, with this I want to make a programme that allows me to walk through a menu on a display using a rotary encoder. Now I can't smoothly walk through the menu with the rotary encoder. I have to very quietly walk through the menu one turn at a time, if I turn a bit harder it happens to falter a bit. Also, I often have to press several times to start a programme. I have everything connected as it should be and expect this to be in the programme.

I am at a loss as to what else to do.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ezButton.h>

LiquidCrystal_I2C lcd(0x27, 16, 4);
int menu = 1;
const int RELAY_PIN = 7;  // the number of the relay pin
const int RotaryCLK = 2;  // CLK pin op de rotary encoder
const int RotaryDT = 3;   // DT pin op de rotary encoder
const int RotarySW = 4;   // SW (push button) pin op de rotary encoder


ezButton button(RotarySW);  // Maak een ezButton-object voor de push-knop van de rotary encoder.

int relayState = LOW;   // the current state of the relay
bool relayBlinking = false;  // flag to indicate if the relay should blink


void setup() {
  lcd.init();
  lcd.backlight();
  pinMode(RotaryCLK, INPUT_PULLUP);
  pinMode(RotaryDT, INPUT_PULLUP);
  pinMode(RotarySW, INPUT_PULLUP);
  pinMode(RELAY_PIN, OUTPUT); // set Arduino pin to output mode
  updateMenu();
  Serial.begin(9600);         // initialize serial
}

void loop() {
button.loop(); // MUST call the loop() function first

int encoderValue = readEncoder();
  if (encoderValue > 0) {
    menu++ ;
    updateMenu();
    delay(25);
  } else if (encoderValue < 0) {
    menu-= 1;
    updateMenu();
    delay(25);
  }

  if (button.isPressed()) {
    executeAction();
    updateMenu();
    delay(2);
  }

  if (relayBlinking) {
      relayBlinking = false;  // Stop blinking
      digitalWrite(RELAY_PIN, LOW); // Turn the relay off
    } else {
      relayBlinking = true;   // Start or resume blinking
    }
}

int readEncoder() {
  static int encoderPos = 0;
  static int lastEncoderPos = 0;
  int encoderValue = 0;
  static bool isClockwise = false;

  int CLKState = digitalRead(RotaryCLK);
  int DTState = digitalRead(RotaryDT);

if (CLKState != lastEncoderPos) {
    if (DTState != CLKState) {
      // Alleen verhogen als de richting kloks wijzerzin is.
      if (isClockwise) {
        encoderValue++;
        isClockwise = false;
      } else {
        isClockwise = true;
      }
    } else {
      // Alleen verlagen als de richting tegen de klokwijzers in is.
      if (!isClockwise) {
        encoderValue--;
        isClockwise = true;
      } else {
        isClockwise = false;
      }
    }
  }

  lastEncoderPos = CLKState;
  return encoderValue;
}

void updateMenu() {
  switch (menu) {
    case 0:
      menu = 1;
      break;
    case 1:
      lcd.clear();
      lcd.print(">Ademhaling 1");
      lcd.setCursor(0, 1);
      lcd.print(" Ademhaling 2");
      lcd.setCursor(0, 2);
      break;
    case 2:
      lcd.clear();
      lcd.print(">Ademhaling 2 ");
      lcd.setCursor(0, 1);
      lcd.print(" Ademhaling 3");
      lcd.setCursor(0, 2);
      break;
    case 3:
      lcd.clear();
      lcd.print(">Ademhaling 3");
      lcd.setCursor(0, 1);
      lcd.print(" Ademhaling 4");
      lcd.setCursor(0, 2);
      break;
    case 4:
      lcd.clear();
      lcd.print(">Ademhaling 4");
      lcd.setCursor(0, 1);
      break;
  }
}

bool exitLoop = false;  // Flag to indicate whether to exit the loop

void executeAction() {
  switch (menu) {
    case 1:
  action1();
      while (relayBlinking && !exitLoop) {  // Check both relayBlinking and exitLoop conditions
        digitalWrite(RELAY_PIN, HIGH);
        delay(2000);
        digitalWrite(RELAY_PIN, LOW);
        delay(500);
        
        // Check if the up or down button is pressed to exit the loop
        if (!digitalRead(RotaryCLK) || !digitalRead(RotarySW) || !digitalRead(RotaryDT)) {
          exitLoop = true;  // Set the flag to exit the loop
        }
      }
      
      // Reset the flag after exiting the loop
      exitLoop = false;

      break;
    case 2:
    action2();
      while (relayBlinking && !exitLoop) {  // Check both relayBlinking and exitLoop conditions
        digitalWrite(RELAY_PIN, HIGH);
        delay(500);
        digitalWrite(RELAY_PIN, LOW);
        delay(500);
        
        // Check if the up or down button is pressed to exit the loop
       if (!digitalRead(RotaryCLK) || !digitalRead(RotarySW) || !digitalRead(RotaryDT)) {
          exitLoop = true;  // Set the flag to exit the loop
        }
      }
      
      // Reset the flag after exiting the loop
      exitLoop = false;

      break;
    case 3:
    action3();
     while (relayBlinking && !exitLoop) {  // Check both relayBlinking and exitLoop conditions
        digitalWrite(RELAY_PIN, HIGH);
        delay(5000);
        digitalWrite(RELAY_PIN, LOW);
        delay(1000);
        
        // Check if the up or down button is pressed to exit the loop
       if (!digitalRead(RotaryCLK) || !digitalRead(RotarySW) || !digitalRead(RotaryDT)) {
          exitLoop = true;  // Set the flag to exit the loop
        }
      }
      
      // Reset the flag after exiting the loop
      exitLoop = false;

      break;
    case 4:
    action4();
     while (relayBlinking && !exitLoop) {  // Check both relayBlinking and exitLoop conditions
        digitalWrite(RELAY_PIN, HIGH);
        delay(6000);
        digitalWrite(RELAY_PIN, LOW);
        delay(3000);
        
        // Check if the up or down button is pressed to exit the loop
       if (!digitalRead(RotaryCLK) || !digitalRead(RotarySW) || !digitalRead(RotaryDT)) {
          exitLoop = true;  // Set the flag to exit the loop
        }
      }
      
      // Reset the flag after exiting the loop
      exitLoop = false;
  }
}

void action1() {
  lcd.clear();
  lcd.print("2 SEC AAN");
  lcd.setCursor(0, 1);
  lcd.print("0.5 SEC UIT");
}
void action2() {
  lcd.clear();
  lcd.print("0.5 SEC AAN");
  lcd.setCursor(0, 1);
  lcd.print("0.5 SEC UIT");
}
void action3() {
  lcd.clear();
  lcd.print("5 SEC AAN");
  lcd.setCursor(0, 1);
  lcd.print("1 SEC UIT");
}
void action4() {
  lcd.clear();
  lcd.print("6 SEC AAN");
  lcd.setCursor(0, 1);
  lcd.print("3 SEC UIT");
}

I moved your topic to an appropriate forum category @quintgiesberts.

In the future, please take some time to pick the forum category that best suits the subject of your topic. There is an "About the _____ category" topic at the top of each category that explains its purpose.

This is an important part of responsible forum usage, as explained in the "How to get the best out of this forum" guide. The guide contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.

1 Like

i found that i needed to use interrupts even when turning an encoder by hand (and a lot of other stuff to do).

you're probably better off just recognizing the change in state of one input and looking at the other input to determine direction and either inc/decrement the encoder value

I use the encoder library and stopped worrying about managing the encoder myself :slight_smile:

I use Toggle from @dlloyd for the buttons.

Whenever you code:

delay(some nontrivial time);

stop and ask yourself, is my code going to miss something, while the processor sleeps? If the answer is yes, refer to the Blink without delay examples/tutorials.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.