Need help with a rotary encoder

Hello! This is my first post on this forum.

I have some trouble with a rotary encoder. My current project is making a menu system with submenus that is controlled using a rotary encoder and displayed on a 16x2 LCD screen. The problem is that I tried using a loading variable (currentMenu in the code below) that should act as check for the current menu I am in. However, printing the value through serial shows me that whenever I press the button, currentMenu resets back to 0 and I cannot cycle through any of the submenu's options. Can you please help me?

This is my code (the menu options are written in Romanian, but that should not be a problem for reading):

#include <LiquidCrystal.h>
#include <rotary.h>                 // rotary handler

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

#define A_output 9
#define B_output 8
#define SW_output 7

Rotary r = Rotary(A_output, B_output, SW_output);

int currentMenu;
int columns = 16;

char *menuList[] = {"Motoare", "Contrast", "LED Test", "Opt. lumina", "Despre", "Resetare"};
char *menuListMotor[] = {"Servo1", "Servo2"};
char *menuListOpts[] = {"Pornit", "Oprit"};

int menuItems = 6;
int menuItemsMotor = 2;
int menuItemsOpts = 2;

int CursorLine = 0;
int CursorLineMotor = 0;
int CursorLineContrast = 0;

int ledPin = 4;
int backButton = 2;


int contrastLevel = 10;
int backlightPin = 10;
int brightness = 255;
int fadeLevel = 5;

void (*resetfunc)(void) = 0;

void setup ()
{
  digitalWrite(A_output, HIGH);
  digitalWrite(B_output, HIGH);
  digitalWrite(SW_output, HIGH);
  analogWrite(backlightPin, brightness);
  analogWrite(6, contrastLevel);
  pinMode(backButton, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);

  lcd.clear();
  lcd.begin(16, 2);
  lcd.print("  Bun venit! :)");
  delay(2000);
  print_menu();
  currentMenu = 0;
} //end of setup

void loop ()
{
  if (currentMenu == 0) {
    menu_system();
  } else if (currentMenu == 1) {
    motor_system();
  }
  Serial.println(currentMenu);
} //End loop()


void menu_system() {
  volatile unsigned char result = r.process();

  if (result) {
    result == DIR_CCW ? CursorLine = CursorLine - 1 : CursorLine = CursorLine + 1;
    if (CursorLine < 0) {
      CursorLine = 0;
    } else if (CursorLine > menuItems - 1) {
      CursorLine = menuItems - 1;
    }
    print_menu();
  }

  if (r.buttonPressedReleased(25)) {
    lcd.setCursor(0, 0);  //(col, row)
    lcd.setCursor(0, 1);  //(col, row)
    selection();
  } //endif buttonPressedReleased
}

void motor_system() {
  int valueMenu = digitalRead(backButton);
  volatile unsigned char result = r.process();

  if (result) {
    result == DIR_CCW ? CursorLineMotor = CursorLineMotor - 1 : CursorLineMotor = CursorLineMotor + 1;
    if (CursorLineMotor < 0) {
      CursorLineMotor = 0;
    } else if (CursorLineMotor > menuItems - 1) {
      CursorLineMotor = menuItems - 1;
    }
    contrast_menu();
  }

  if (r.buttonPressedReleased(25)) {
    lcd.setCursor(0, 0);  //(col, row)
    lcd.setCursor(0, 1);  //(col, row)
    selection_motor();
  } //endif buttonPressedReleased

  if (valueMenu == LOW) // if button is pressed, turn LED on
  {
    lcd.setCursor(0, 1);
    lcd.print("Iesire");
    currentMenu = 0;
  }
}
void print_menu()
{
  lcd.clear();
  lcd.setCursor(0, 0);     //(col, row)
  lcd.print("  Meniu simplu  ");
  lcd.setCursor(0, 1);    //2nd row
  lcd.print("<"); lcd.setCursor(columns - 1, 1); lcd.print(">");
  lcd.setCursor(1, 1);
  lcd.print(menuList[CursorLine]);
}


void contrast_menu() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Selectie motor");
  lcd.setCursor(0, 1);
  lcd.print("<"); lcd.setCursor(columns - 1, 1); lcd.print(">");
  lcd.setCursor(1, 1);
  lcd.print(menuList[CursorLineMotor]);

}

void selection()
{
  switch (CursorLine) {
    case 0:
      currentMenu = 1;
      contrast_menu();
      break;
    case 1:
      break;
    case 2:
      //set a flag or do something....
      lcd.setCursor(0, 0);
      lcd.print("Testare LED!      ");
      lcd.setCursor(0, 1);
      lcd.print("                     ");
      digitalWrite(ledPin, HIGH);
      delay(1000);
      digitalWrite(ledPin, LOW);
      print_menu();
      break;
    case 3:
      lcd.print("Lumina de spate    ");
      digitalWrite(backlightPin, LOW);
      break;
    case 4:
      lcd.setCursor(0, 0);
      lcd.print("Built at    (C) ");
      lcd.setCursor(0, 1);
      lcd.print("FalconVille 2021");
      delay(3000);
      print_menu();
      //set a flag or do something....
      break;
    case 5:
      //set a flag or do something....
      lcd.setCursor(0, 0);
      lcd.print("Resetare...       ");
      lcd.setCursor(0, 1);
      lcd.print("                    ");
      delay(2000);
      resetfunc();
      break;
  } //end switch

  //delay(2000);
  //CursorLine = 0;     // reset to start position
} //End selection

void selection_motor() {
  switch (CursorLineMotor) {
    case 0:
      //turn on servo 1
      break;
    case 1:
      //turn on servo 2
      break;
    default:
      break;
  }
}

Also, here is the rotary library that I used (This is a version made specifically to make the encoder's button work):
https://easyupload.io/d1v89o

Hi @goteki45,

I tried to run your code, but I couldn't find the library "rotary.h" with a lowercase "r".
I only found it with "R" uppercase.

Can you send me a link to your library?

RV mineirin

Hello, sorry for the late response.
I left a link to my library in the original post.
https://easyupload.io/d1v89o

Here is an update to my code. I optimized it by including 2 bool variables that change whenever I switch to a submenu.And it works!
However, when I switch to the second menu, both lists of options change, and then both menus are filled with garbage memory if I scroll past the last option.

#include <LiquidCrystal.h>
#include <rotary.h>                 // rotary handler

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

#define A_output 9
#define B_output 8
#define SW_output 7

Rotary r = Rotary(A_output, B_output, SW_output);

int currentMenu;
int columnsLCD = 16;

char *MenuItems[] = {"Motoare", "Contrast", "LED Test", "Opt. lumina", "Despre", "Resetare"};
char *SubMenuItems[] = {"Servo1", "Servo2", "Iesire"};


int menuItems = 6;
int subMenuItems = 2;


int CursorLine = 0;

int ledPin = 4;
int backButton = 2;

bool isMain;
bool isSub;

int contrastLevel = 10;
int backlightPin = 10;
int brightness = 255;
int fadeLevel = 5;

void (*resetfunc)(void) = 0;

void setup ()
{
  digitalWrite(A_output, HIGH);
  digitalWrite(B_output, HIGH);
  digitalWrite(SW_output, HIGH);
  analogWrite(backlightPin, brightness);
  analogWrite(6, contrastLevel);
  pinMode(backButton, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);

  lcd.clear();
  lcd.begin(16, 2);
  lcd.print("  Bun venit! :)");
  delay(2000);
  print_menu();
  isMain = true;
  isSub = false;
} //end of setup
 
void loop ()
{
  if(isMain == true && isSub == false){
      selection_stuff(MenuItems);
    }else if (isMain == false && isSub == true){
      selection_stuff(SubMenuItems);
    }
} //End loop()

void selection_stuff(int currentList){
  volatile unsigned char result = r.process();
 
  if (result) {
    result == DIR_CCW ? CursorLine = CursorLine - 1 : CursorLine = CursorLine + 1;
 
    if (CursorLine < 0) { 
      CursorLine = 0; // roll over to last item 
    } 
    else if (CursorLine > currentList - 1) {
      CursorLine = currentList - 1;                 // roll over to first item
    }
    printManager();
  } // End if result
 
  if (r.buttonPressedReleased(25)) {
    lcd.clear();
    lcd.setCursor(0, 0);  //(col, row)
    lcd.setCursor(0, 1);  //(col, row)
    selectManager();
  } //endif buttonPressedReleased
}

void printManager(){
  if(isMain == true && isSub == false){
      print_menu();
    }else if (isMain == false && isSub == true){
      print_submenu();
    }
}

void selectManager(){
  if(isMain == true && isSub == false){
      selection();
    }else if (isMain == false && isSub == true){
      submenu_selection();
    }
}
 
void print_menu()
{
  lcd.clear();
  lcd.setCursor(0, 0);     //(col, row)
  lcd.print("   Main Menu  ");
  lcd.setCursor(0, 1);    //2nd row
  lcd.print("<"); lcd.setCursor(columnsLCD - 1, 1); lcd.print(">");
  lcd.setCursor(1, 1);
  lcd.print(MenuItems[CursorLine]);
}

void print_submenu()
{
  lcd.clear();
  lcd.setCursor(0, 0);     //(col, row)
  lcd.print("   2nd Menu  ");
  lcd.setCursor(0, 1);    //2nd row
  lcd.print("<"); lcd.setCursor(columnsLCD - 1, 1); lcd.print(">");
  lcd.setCursor(1, 1);
  lcd.print(SubMenuItems[CursorLine]);
}
 
void selection()
{
  switch (CursorLine) {
    case 0:
      isMain = false;
      isSub = true;
      break;
    case 1:
      break;
    case 2:
      //set a flag or do something....
      lcd.setCursor(0, 0);
      lcd.print("Testare LED!      ");
      lcd.setCursor(0, 1);
      lcd.print("                     ");
      digitalWrite(ledPin, HIGH);
      delay(1000);
      digitalWrite(ledPin, LOW);
      print_menu();
      break;
    case 3:
      lcd.print("Lumina de spate    ");
      digitalWrite(backlightPin, LOW);
      break;
    case 4:
      lcd.setCursor(0, 0);
      lcd.print("Built at    (C) ");
      lcd.setCursor(0, 1);
      lcd.print("FalconVille 2021");
      delay(3000);
      print_menu();
      //set a flag or do something....
      break;
    case 5:
      //set a flag or do something....
      lcd.setCursor(0, 0);
      lcd.print("Resetare...       ");
      lcd.setCursor(0, 1);
      lcd.print("                    ");
      delay(2000);
      resetfunc();
      break;
  } //end switch

  //delay(2000);
  //CursorLine = 0;     // reset to start position
} //End selection

void submenu_selection() {
  switch (CursorLine) {
    case 0:
      //turn on servo 1
      break;
    case 1:
      //turn on servo 2
      break;
    case 2:
      isMain = true;
      isSub = false;
  }
}

Any solutions for this? As always, the library I used is included in the original post.

Probably not the problem but, you create three submenu items and then declare that there are only two.

I saw the problem there, but it still fills with garbage memory in all of the menus.

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