Arduino - Rotary Encoder - Function

Hello,

I'm trying to create a menu based on rotary encoder with LCD but im getting some weird issue.

First of all, i'm using a common part of code to handle a rotary encoder (still learning) and it's working fine - the "menuOption" reacts smooth and instantly.

   currentStateClock = digitalRead(Clock);
  //Serial.println(currentStateClock);
  if (currentStateClock != lastStateClock  && currentStateClock == 1){
      if (digitalRead(Data) != currentStateClock) {
        menuOption ++;
        currentDir ="Counterclockwise";
        menuOption = setCorrectValue(menuOption);
      } else {
        // Encoder is rotating CW so increment
        menuOption --;
        currentDir ="Clockwise";     
        menuOption = setCorrectValue(menuOption);       
      }
  }
  lastStateClock = currentStateClock;
  Serial.print(menuOption);
  //lcd_menu(menuOption);
  Serial.print("\n");

  delay(1);

But when i'm trying to put that 'menuOption' into the function then it's working like the rotary encoder has missing steps. For example without funtcion when i turn the encoder then it displays at serial output values without any problem, but in function i have to rotate it multiple times in one direction to jump into different value.

The function is:

int lcd_menu(int option){

    Serial.print(option);
    Serial.print("\n");
    
      switch(option){
      case 0:
        displayText("Motor spd");
        //motorMenu();
        break;
      case 1:
        displayText("Curing spd");
        //curingMenu();
        break;
      case 2:
        displayText("Start");
        //curingMenu();
        break;
      default:
        displayText("Error");
        break;

    }  
    
}

And the displayText function:

void displayText(String text){
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.invertDisplay(true);
  display.clearDisplay();
  display.setCursor(5, 24);
  display.println(text);
  display.display(); 
  //delay(1);
}

I'm also have a little function to set correct Value of the encoder (menu etc):

int setCorrectValue(int value){
  if(value > menuMax){
    value = 0;
  }  

  if(value < 0){
    value = menuMax;
  }

  return value;
}

And right now i'm totally dont know why it happens. It's also happened when i'm using a 'if' statement with comparing the 'menuOption' with value for example 'menuOption' == 1, to perform specific action.

Could someone tell me what i'm missing? Connection to the arduino is very easy - GND and + are connected to the 5V (main GND with arduino also), then CLK and DT and SW are connected to the D8, D9, D10 pins.

Post the full code

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);


#define buzzer A2
#define uv 2
#define Clock 9
#define Data 8
#define Push 10

// menu position
int menuPos = 0;
// last menu position
int lastMenuPos = 0;
// how many menues are
int menuMax = 2;
// motor speed
int motorSpeed = 0;
// curing time
int curingTime = 0;


unsigned long currentTime = 0;
unsigned long recordTime = 0;
unsigned long diffTime = 0;

int menuOption = 0;                    //Use this variable to store "steps"
int currentStateClock;              //Store the status of the clock pin (HIGH or LOW)
int lastStateClock;                 //Store the PREVIOUS status of the clock pin (HIGH or LOW)
String currentDir ="";              //Use this to print text 
unsigned long lastButtonPress = 0;  //Use this to store if the push button was pressed or not


void setup() {
  Serial.begin(9600);

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  delay(2000);
  display.clearDisplay();

  pinMode(buzzer, OUTPUT);
  pinMode(uv, OUTPUT);
  digitalWrite(uv, LOW);
  
  pinMode(Clock, INPUT_PULLUP);
  pinMode(Data, INPUT_PULLUP);
  pinMode(Push, INPUT_PULLUP);
  lastStateClock = digitalRead(Clock);
}

void loop() {
   currentStateClock = digitalRead(Clock);
  //Serial.println(currentStateClock);
  if (currentStateClock != lastStateClock  && currentStateClock == 1){
      if (digitalRead(Data) != currentStateClock) {
        menuOption ++;
        currentDir ="Counterclockwise";
        menuOption = setCorrectValue(menuOption);
      } else {
        // Encoder is rotating CW so increment
        menuOption --;
        currentDir ="Clockwise";     
        menuOption = setCorrectValue(menuOption);       
      }
  }
  lastStateClock = currentStateClock;
  Serial.print(menuOption);
  //lcd_menu(menuOption);
  Serial.print("\n");

  delay(1);
  
/////////////////////////////

  //lcd_menu(menuOption);
/*
  if(menuOption == 0){
    displayText("Motor spd");
  }else if(menuOption == 1){
    displayText("Curing spd");
  }else if(menuOption == 2){
    displayText("Start");
  }else{
    Serial.println("Err");
  }
*/
/////////////////////////////

  // Getting time using millis
  currentTime = millis();
  diffTime = currentTime - recordTime;
  
  if(diffTime >= 10000UL){
    recordTime = currentTime;
    
    //buzzerNotify();
  }

  if(diffTime >= 5000UL){
    recordTime = currentTime;
    //uv_led();
  }

}

int setCorrectValue(int value){
  if(value > menuMax){
    value = 0;
  }  

  if(value < 0){
    value = menuMax;
  }

  return value;
}

void uv_led(){
  //Serial.println("UV LED ON");
  digitalWrite(uv, LOW);
}

void buzzerNotify(){
  int interval = 0;
  while(true){
    tone(buzzer, 1000);
    delay(500);
    noTone(buzzer);
    delay(500);
    interval++;
    if(interval == 5){
      break;
    }
  }
 
}

int lcd_menu(int option){

    Serial.print(option);
    Serial.print("\n");
    
      switch(option){
      case 0:
        displayText("Motor spd");
        //motorMenu();
        break;
      case 1:
        displayText("Curing spd");
        //curingMenu();
        break;
      case 2:
        displayText("Start");
        //curingMenu();
        break;
      default:
        displayText("Error");
        break;

    }  
    
}

void motorMenu(){
/*
  for(int i = 0; i <= 100; i++){
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.invertDisplay(true);
    display.clearDisplay();
    display.setCursor(1, 5);
    display.println("Motor speed settings"); 
    display.display(); 
    display.setTextSize(5);
    display.setTextColor(WHITE);
    display.invertDisplay(true);
    display.setCursor(32, 20);
    display.println(i);
    display.display(); 

    delay(25);
  }


  delay(1000);
*/
}

void curingMenu(){
/*
  for(int i = 0; i <= 100; i++){
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.invertDisplay(true);
    display.clearDisplay();
    display.setCursor(1, 5);
    display.println("Curing time settings"); 
    display.display(); 
    display.setTextSize(5);
    display.setTextColor(WHITE);
    display.invertDisplay(true);
    display.setCursor(32, 20);
    display.println(i);
    display.display(); 
    
    delay(25);
  }


  delay(1000);

  */
}

void displayText(String text){
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.invertDisplay(true);
  display.clearDisplay();
  display.setCursor(5, 24);
  display.println(text);
  display.display(); 
  //delay(1);
}

Yea, the MotorMenu contain the delay but it's under comment, take a look at the /* and */ at the beginning and ending of function. And take a look at the "//motorMenu();" it's commented. So the function is not called.

void motorMenu(){
/*
  for(int i = 0; i <= 100; i++){
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.invertDisplay(true);
    display.clearDisplay();
    display.setCursor(1, 5);
    display.println("Motor speed settings"); 
    display.display(); 
    display.setTextSize(5);
    display.setTextColor(WHITE);
    display.invertDisplay(true);
    display.setCursor(32, 20);
    display.println(i);
    display.display(); 

    delay(25);
  }


  delay(1000);
*/
}

It's an empty function right now.

And no, it's not ignoring the encoder for a second or more, it's behave like skipping steps while i'm rotating the encoder. I have to rotate it multiple times to increment or decrement the values.

And yeah, i know how to write a nonblocking code using millis() (I’m not a master in that but I can do that :wink: and I’ve got it in my main code) but, i'm testing it right now and i dont want to run the whole code under the tested feature.

Like i said. i've got problem here:

switch(option){
      case 0:
        displayText("Motor spd");
        //motorMenu();
        break;
      case 1:

In switch-case: when i'm trying using it like that it's skipping and i have to rotate it multiple times to increment or decrement values. Without function with switch-case (clear serial output) or if statement it's working fine.

And also I’ve tried to put if or switch case just under the rotary encoder block (without function) but it’s working similar - multiple rotates to increment value - so there is no delay or any other blocking the code. And without it, it’s increment normally.

this seems to work better with ==0

Check it here..

have fun.. ~q

This text is so compact and leaves out so much information that I don't understand your text.
Each and every "it" should be replaced by the real name that specifies exactly what is meant by "it"

You would have to separate the multiple cases that you included in this writing

No problem @Delta_G :wink: i think it might be my fault when i explained how my code works.

Hi,

Yeah, i'm sorry for unintelligible text, i will do my best to be better in the future.

Hi,

Oh! Thanks a lot, i didn't even know that exist that kind of web app.
Thanks once again.

1 Like

"Hi" to whom?

what web-app???

he is replying to @qubits-us. You can see that above the post

so the web app would be wokwi

Correct. I thought "reply" on this forum showed the current message from the person who was replied to, but it doesn't. Forum shows only the little mark above post.

Edit: Thanks for any advice, now it's working.

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