Problem OLED SSD1306 Menu with Rotatif Encoder

Hello Guys !

I have found a super Menu for my apllication ( see bellow youtube link), and i have changed the second "sub-menu" to setup the "pwm value" on 3rd page, like on the first main menu.

that's ok but when i select this 3rd "sub-menu page" using the scroll of encoder, this sub-menu page switch to next page.

Could you help me pls to select this page by the click button of encoder and after setup the value, exit ! ( like main page)

Thank you in advance :innocent:

Arduino OLED Menu Part III - YouTube)


// INCLUSION

#include <U8g2lib.h>  // LCD
// for timer
#include <TimerOne.h>
// for rotary encoder
#include <Rotary.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

// ========================================================
// MENU DEBUG SUR PORT COM
// ========================================================

//#define DEBUG
//#define DEBUG_BAUD 9600

// ========================================================
// DEFAULTS
// ========================================================

#define VERSION_TITLE "OLED MENU PAGES"
#define VERSION_HW "Corridor 2 Rev. B"
#define VERSION_SUBTITLE "by @schlueri 2017"
#define VERSION "0.32B"

// Status LED

#define STATUS_LED_PIN 9
bool statusLedOn = false;

// Timer
#define TIMER 1000

// Display and menu stuff
int displayCurrentPage = 0;
bool setNeedsDisplay = false;

// Main menu fixed to 3 items, left, center, right...

#define MENU_SELECTED_TIMEOUT 4000
#define MENU_POS_Y 62
#define MENU_POS_Y_HIDDEN 76
#define MENU_ANIMATION_PIXEL_STEP 2

String menuItems[3] = { "MAIN", "AMPERES", "SETUP" };
int menuActive = 1;             // left active
int menuSelected = menuActive;  // selected
bool menuPageMode = false;      // true => rotary encoder

//control page and not menu

// Menu animation
bool menuAnimationRunning = false;
int menuPosY = MENU_POS_Y;

// Rotary encoder with switch
#define ROTARY_SWITCH 15  // A1
#define ROTARY_PIN1 4
#define ROTARY_PIN2 2
#define ROTARY_ACCEL_OFFSET1 20
#define ROTARY_ACCEL_OFFSET2 50
#define ROTARY_ACCEL_OFFSET3 70
unsigned long rotaryLastMove;
bool rotaryButtonPressed = false;

// Action button
#define BUTTON1_PIN 16  // A2

// Test slider A LA PAGE D'ACCEUIL a 20 sur 128
int sliderPosX = 60;  // Valeur 60

// Logic
long int heartbeat = 0;
#define HEARTBEAT_TRIGGER 1000
#define HEARTBEAT_TRIGGER_TIME 50

// ========================================================
// PAGES  AFFICHAGE HAUT EN JAUNE
// ========================================================

#define SETUP_MENU_ITEMS 9
String setupMenuItems[SETUP_MENU_ITEMS] = { "EXIT", "LDR LEVEL", "LDR THRESHOLD", "PIR SENSOR", "LED COLOR", "LED ANIMATION", "LED OUT TEST", "VERSION & INFO", "HHO++" };


int setupMenuSelected = 3;  // SELECTION DU MENU A L4ARRIVE 0


// ========================================================
// Initialisation de l'ecrans et de l'encodeur
// ========================================================

// Display
//
//U8G2_SH1106_128X64_VCOMH0_1_4W_HW_SPI u8g2(U8G2_R0, 10, 8);


//U8G2_SSD1306_128X64_NONAME_1_4W_HW_SPI u8g2(U8G2_R0, 10, 8);

//U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g(U8G2_R0, U8X8_PIN_NONE);

U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R0, /* clock=*/SCL, /* data=*/SDA, /* reset=*/U8X8_PIN_NONE);  // OK en I2C

// Rotary Encoder
Rotary rotary = Rotary(ROTARY_PIN1, ROTARY_PIN2);

// ========================================================
// SETUP
// ========================================================

void setup() {














  // put your setup code here, to run once:





  // Status LED
  pinMode(STATUS_LED_PIN, OUTPUT);
  digitalWrite(STATUS_LED_PIN, HIGH);

#ifdef DEBUG
  Serial.begin(DEBUG_BAUD);
  Serial.println("DEBUG MODE");
  Serial.print("Version ");
  Serial.print(VERSION);
  Serial.print("\n\n");
#endif

  // Menu Button
  pinMode(ROTARY_SWITCH, INPUT);
  digitalWrite(ROTARY_SWITCH, INPUT_PULLUP);

#ifdef BUTTON1_PIN
  pinMode(BUTTON1_PIN, INPUT);
  digitalWrite(BUTTON1_PIN, INPUT_PULLUP);
#endif

  // OLED Display
  u8g2.begin();

  setNeedsDisplay = true;

  Timer1.initialize(TIMER);
  Timer1.attachInterrupt(timerEvent);

  //delay(1000);
}

// ========================================================
// LOOP
// ========================================================

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














  digitalWrite(STATUS_LED_PIN, statusLedOn);

  if (menuAnimationRunning) {
    if (menuPageMode && menuPosY < MENU_POS_Y_HIDDEN) {
      // do animation
      menuPosY = menuPosY + MENU_ANIMATION_PIXEL_STEP;
      setNeedsDisplay = true;
    }
    if (!menuPageMode && menuPosY > MENU_POS_Y) {
      // do animation
      menuPosY = menuPosY - MENU_ANIMATION_PIXEL_STEP;
      setNeedsDisplay = true;
    }
  }
  if (menuAnimationRunning && (menuPosY == MENU_POS_Y || menuPosY == MENU_POS_Y_HIDDEN)) {
    // looks like animation is done
    menuAnimationRunning = false;
  }

  if (setNeedsDisplay) {
    noInterrupts();
    displayRenderCurrentPage();
    setNeedsDisplay = false;
    interrupts();
  }
}

// ========================================================
// TIMER
// ========================================================

void timerEvent() {
  // Heartbeat
  if (heartbeat > HEARTBEAT_TRIGGER) {
    statusLedOn = true;
  }
  if (heartbeat > HEARTBEAT_TRIGGER + HEARTBEAT_TRIGGER_TIME) {
    statusLedOn = false;
    heartbeat = 0;
  }
  heartbeat++;

  // Menu logic
  unsigned long timeOffset = millis() - rotaryLastMove;
  if (timeOffset > MENU_SELECTED_TIMEOUT) {
    // deselect menu
    menuSelected = menuActive;
    rotaryLastMove = millis();
    setNeedsDisplay = true;
  }

  // Rotary Encoder SELECTION DES 3 PREMIERS MENUS


  unsigned char result = rotary.process();
  if (result) {

    if (!menuPageMode) {
      if (result == DIR_CW) {
        // right
        if (menuSelected < 3) {
          menuSelected++;
        }
      } else {
        // left
        if (menuSelected > 1) {
          menuSelected--;
        }
      }
      setNeedsDisplay = true;
    } else {

      // Acceleration
      byte acceleration = 1;
      unsigned long timeOffset = millis() - rotaryLastMove;

      //Serial.println(timeOffset);

      if (displayCurrentPage == 1 || displayCurrentPage == 2 || setupMenuSelected == 3)  // TOUT LES MENUS AVEC SELECITON PAR ENCODER

      {
        if (timeOffset < ROTARY_ACCEL_OFFSET1) {
          acceleration = 16;
        } else if (timeOffset < ROTARY_ACCEL_OFFSET2) {
          acceleration = 4;
        } else if (timeOffset < ROTARY_ACCEL_OFFSET3) {
          acceleration = 2;
        }

        // Development test => control slider CONTROLE DE LA BARRE EN GRAPHE
        if (result == DIR_CW) {
          // right
          if (sliderPosX < 128) {
            sliderPosX = sliderPosX + acceleration;
          }
        } else {
          // left
          if (sliderPosX > 0) {
            sliderPosX = sliderPosX - acceleration;
          }
        }
        setNeedsDisplay = true;
      }

      if (displayCurrentPage == 2) {
        if (result == DIR_CW) {
          // right
          setupMenuSelected++;
        } else {
          // left
          setupMenuSelected--;
        }
        if (setupMenuSelected > SETUP_MENU_ITEMS - 1) {
          setupMenuSelected = SETUP_MENU_ITEMS - 1;
        }
        if (setupMenuSelected < 1) {
          setupMenuSelected = 0;
        }
        setNeedsDisplay = true;
      }
    }

    rotaryLastMove = millis();
  }

  // Rotary button
  if (buttonEvent()) {
    rotaryLastMove = millis();
    if (menuActive == menuSelected) { // ESS PERMISSION ACCES MENU

    // if (menuActive == menuSelected || setupMenuSelected ) { // ESS PERMISSION ACCES MENU

      if (!menuPageMode) {

        // give controls to page (button press on selected page)
        menuPageMode = true;
        menuAnimationRunning = true;

        //sliderPosX = 64;

        setNeedsDisplay = true;

#ifdef DEBUG
        Serial.println("PAGE MODE ON");
#endif
      } else {
        menuPageMode = false;
        menuAnimationRunning = true;
        setNeedsDisplay = true;
        //sliderPosX = 64;

        setupMenuSelected = 0;

#ifdef DEBUG
        Serial.println("PAGE MODE OFF");
#endif
      }
    }
    //MENU PAGE PRINCIPAL

    if (!menuPageMode) {
      menuActive = menuSelected;
      if (menuActive == 1) {
        displayCurrentPage = 0;  //  Affiche menu 0 pricipal
      }
      if (menuActive == 2) {
        displayCurrentPage = 1;  //  Affiche menu 1 pricipal
      }
      if (menuActive == 3) {
        displayCurrentPage = 2;  //  Affiche menu 2 pricipal
      }
      setNeedsDisplay = true;
    }
  }

  // Action button => reset page mode during development
#ifdef BUTTON1_PIN
  if (digitalRead(BUTTON1_PIN) == 0 && menuPageMode) {
    menuPageMode = false;
    menuAnimationRunning = true;
    setNeedsDisplay = true;
//sliderPosX = 64;
#ifdef DEBUG
    Serial.println("PAGE MODE OFF");
#endif
  }
#endif
}

// ========================================================
// MENU BUTTON
// ========================================================

bool buttonEvent() {
  bool result = false;
  bool menuButton = false;
  if (digitalRead(ROTARY_SWITCH) == 1) {
    menuButton = true;
  }
  if (menuButton && !rotaryButtonPressed) {
    rotaryButtonPressed = true;
  } else if (!menuButton && rotaryButtonPressed) {
    rotaryButtonPressed = false;
    result = true;
    // FIXME: debounce for try, check if it's really needed
    //delay(4);
  }
  return result;
}

// ========================================================
// DISPLAY - Screen Drawing
// ========================================================

void displayRenderCurrentPage() {
  // OLED Display update
  u8g2.firstPage();




  do {
    // MENU PRINCIPALE  SETUP MENU 0
    if (displayCurrentPage == 0) {
      u8g2.setFont(u8g2_font_8x13B_tr);
      u8g2.drawStr(0, 12, "Main Page");  // BOUTON PAGE PRINCIPALE DE SELECTION
    }
    // MENU PRINCIPALE  SETUP MENU 1
    if (displayCurrentPage == 1) {
      u8g2.setFont(u8g2_font_8x13B_tr);
      u8g2.drawStr(0, 12, "Network Page");  // BOUTON PAGE PRINCIPALE DE SELECTION
    }


    // MENU PRINCIPALE  SETUP MENU 2


    if (displayCurrentPage == 2) {
      if (!menuPageMode) {  // FONCTION POUR ACCEDER AU SUB MENU
        u8g2.setFont(u8g2_font_8x13B_tr);
        u8g2.drawStr(0, 10, "Setup Page");
        u8g2.setFont(u8g2_font_5x7_tr);
        u8g2.drawStr(0, 28, "PRESS BUTTON FOR SUBMENU");  // BOUTON PAGE PRINCIPALE DE SELECTION
      } else {
        drawPageMenu();  // ALORS DESSINER LE MENU JAUNE


        
        
        // TOUT LES MENUS MENU  JAUNE EXIT ( 0) **************


        if (setupMenuSelected == 0) {  // MENU EXIT JAUNE
          u8g2.setFont(u8g2_font_5x7_tr);
          u8g2.drawStr(0, 28, "DEMO HHO MODE");
          u8g2.drawStr(0, 38, "PRESS BUTTON TO EXIT");
        }


        if (setupMenuSelected == 1) {  // LDR LEVEL J
          u8g2.setFont(u8g2_font_5x7_tr);
          u8g2.drawStr(0, 28, "PAGE2");
          u8g2.drawStr(0, 38, "TO EXIT PAGE2");
          u8g2.drawStr(0, 38, "PRESS  P2 BUTTON TO EXIT");
        }

        if (setupMenuSelected == 2) {  // TRHESHOLD J
          u8g2.setFont(u8g2_font_5x7_tr);
          u8g2.drawStr(0, 28, "PAGE3");
          u8g2.drawStr(0, 38, "TO EXIT PAGE3");
        }

        // MENU 3 BARRE EN GRAPHE

        if (setupMenuSelected == 3) {  // PIR SENSOR MAIS PWM
         


          u8g2.setFont(u8g2_font_5x7_tr);
          if (menuPageMode) {
            u8g2.drawStr(0, 28, "VALEUR PWM");  // AFFICHAGE LIGNE
            u8g2.setCursor(0, 46);
            u8g2.print("VALEUR ");
            u8g2.print(sliderPosX);  // VALEUR DE LA POSITION DU CODEUR
            u8g2.drawStr(0, 28, "ROTARY CONTROL ON MENU");




          } else {
          }
          drawSlider(31);  // POSITION EN HAUTEUR DU LCD DU BARRE EN GRAPHE


          // u8g2.setFont(u8g2_font_5x7_tr);
          //u8g2.setCursor(0, 28);
          //u8g2.print(VERSION_TITLE);
          //u8g2.print(" ");
          //u8g2.print(VERSION);

          // u8g2.setCursor(0, 38);
          // u8g2.print(VERSION_SUBTITLE);

          // u8g2.setCursor(0, 56);
          //u8g2.print("HW: ");
          //u8g2.print(VERSION_HW);
        }
      }
    }



    // PAGE PRICIPALE VALEUR PWM EN BAR GRAPHE


    if (displayCurrentPage == 0 || displayCurrentPage == 1 || setupMenuSelected == 3)  // reporte la barre dans tout les menus ou sous menus

    {  // AFFICHE LE BAR EN GRAPHE SI ON CLICK SUR LE BT MENU 0 ET 1


      u8g2.setFont(u8g2_font_5x7_tr);
      if (menuPageMode) {
        u8g2.drawStr(0, 28, "VALEUR PWM");  // AFFICHAGE LIGNE
        u8g2.setCursor(0, 46);
        u8g2.print("VALEUR ");

        u8g2.print(sliderPosX);  // VALEUR DE LA POSITION DU CODEUR
      } else {
        u8g2.drawStr(0, 28, "ROTARY CONTROL ON MENU");
      }
      drawSlider(31);  // POSITION EN HAUTEUR DU LCD DU BARRE EN GRAPHE
    }

    drawMenuBar();  //DESSINE LE MENU BARRE EN BAS

  } while (u8g2.nextPage());
 

}

// CREATION MENU JAUNE EN HAUT

void drawPageMenu() {
  u8g2.setFont(u8g2_font_6x12_tr);
  if (displayCurrentPage == 2) {
    String text = setupMenuItems[setupMenuSelected];
    // center text
    int textWidth = u8g2.getStrWidth(text.c_str());
    int textX = (128 - textWidth) / 2;  //
    int textXPadding = 4;
    u8g2.drawRBox(textX - textXPadding, 0, textWidth + textXPadding + textXPadding, 11, 2);
    u8g2.setDrawColor(0);
    u8g2.setCursor(textX, 11 - 2);
    u8g2.print(text);
    u8g2.setDrawColor(1);

    bool drawLeftTriangle = false;
    bool drawRightTriangle = false;

    if (setupMenuSelected < SETUP_MENU_ITEMS - 1) {
      drawRightTriangle = true;
    }
    if (setupMenuSelected > 0) {
      drawLeftTriangle = true;
    }

    if (drawLeftTriangle) {
      // Triangle left
      u8g2.drawTriangle(4, 1, 4, 9, 0, 5);
    }
    if (drawRightTriangle) {
      // Triangle right
      u8g2.drawTriangle(128 - 5, 1, 128 - 5, 9, 127, 5);
    }
    u8g2.drawHLine(0, 14, 128);
  }
}
//  DRAWSLIDER et LIMITE


void drawSlider(int yPos) {
  u8g2.drawFrame(0, yPos, 128, 8);  // TAILLE BANDEAU
  if (sliderPosX < 1) {
    sliderPosX = 0;
  }
  if (sliderPosX > 128) {  // LIMITE DE LAFFICHAGE
    sliderPosX = 128;
  }
  u8g2.drawVLine(sliderPosX, yPos, 8);  // TAILLE CURSSEUR SLIDERPOSX
}

void drawMenuBar() {
  int textX = 0;
  int textY = menuPosY;
  int textWidth = 0;
  int textXPadding = 4;

  u8g2.setFont(u8g2_font_6x12_tr);
  u8g2.setDrawColor(1);

  u8g2.drawHLine(0, textY - 11 - 2, 128);





  if (textY < MENU_POS_Y_HIDDEN) {
    // center menu
    String text = menuItems[1];
    textWidth = u8g2.getStrWidth(text.c_str());
    textX = (128 - textWidth) / 2;

    if (menuActive == 2) {
      u8g2.drawRBox(textX - textXPadding, textY + 2 - 11, textWidth + textXPadding + textXPadding, 11, 2);
      u8g2.setDrawColor(0);
    }
    if (menuActive != menuSelected && menuSelected == 2) {
      u8g2.drawRFrame(textX - textXPadding, textY + 2 - 11, textWidth + textXPadding + textXPadding, 11, 2);
      u8g2.setDrawColor(1);
    }

    u8g2.setCursor(textX, textY);
    u8g2.print(text);
    u8g2.setDrawColor(1);

    // left menu
    text = menuItems[0];
    textX = textXPadding;
    textWidth = u8g2.getStrWidth(text.c_str());
    if (menuActive == 1) {
      u8g2.drawRBox(textX - textXPadding, textY + 2 - 11, textWidth + textXPadding + textXPadding, 11, 2);
      u8g2.setDrawColor(0);
    }
    if (menuActive != menuSelected && menuSelected == 1) {
      u8g2.drawRFrame(textX - textXPadding, textY + 2 - 11, textWidth + textXPadding + textXPadding, 11, 2);
      u8g2.setDrawColor(1);
    }
    u8g2.setCursor(textX, textY);
    u8g2.print(text);
    u8g2.setDrawColor(1);

    // right menu
    text = menuItems[2];
    textWidth = u8g2.getStrWidth(text.c_str());
    textX = 128 - textWidth - textXPadding;
    if (menuActive == 3) {  // 3   ESS
      u8g2.drawRBox(textX - textXPadding, textY + 2 - 11, textWidth + textXPadding + textXPadding, 11, 2);
      u8g2.setDrawColor(0);
    }
    if (menuActive != menuSelected && menuSelected == 3) {  // ESS
      u8g2.drawRFrame(textX - textXPadding, textY + 2 - 11, textWidth + textXPadding + textXPadding, 11, 2);
      u8g2.setDrawColor(1);
    }
    u8g2.setCursor(textX, textY);
    u8g2.print(text);
    u8g2.setDrawColor(1);
  }
}

As a minimum you should point your potential helpers to those lines of code where you made this change.

best regards Stefan

Hi Stefan,

Sorry sorry, it's my first post,

My problem is here :

// MENU 3 BARRE EN GRAPHE

       if (setupMenuSelected == 3) {  // PIR SENSOR MAIS PWM
        


         u8g2.setFont(u8g2_font_5x7_tr);
         if (menuPageMode) {
           u8g2.drawStr(0, 28, "VALEUR PWM");  // AFFICHAGE LIGNE
           u8g2.setCursor(0, 46);
           u8g2.print("VALEUR ");
           u8g2.print(sliderPosX);  // VALEUR DE LA POSITION DU CODEUR
           u8g2.drawStr(0, 28, "ROTARY CONTROL ON MENU");




         } else {
         }
         drawSlider(31);  // POSITION EN HAUTEUR DU LCD DU 
  // Rotary Encoder SELECTION DES 3 PREMIERS MENUS
  unsigned char result = rotary.process();
  if (result) {

    if (!menuPageMode) {
      if (result == DIR_CW) {
        // right
        if (menuSelected < 3) { // change to < 4
          menuSelected++;
// did you add item 3?
String menuItems[3] = { "MAIN", "AMPERES", "SETUP" }; 

or do you need to define an 4th item?

Stefan,

i would like to select the "setupMenuSelected == 3" ( PIR sensor ) on picture as you show like "MAIN" "AMPERES...

after you are right i would like to add more menu after main menu "MAIN" , AMPERES , ...

I do not understand what you want to say with that.
You have to use more words
or
write down an example of what you want

If you want further help you have to answer all my questions.
How the code must be modified depends on your answers.

did you yourelf add the third item here?

String menuItems[3] = { "MAIN", "AMPERES", "SETUP" }; 

are there any sub-menus or just 3, 4 eventual more menus?
But no submenus?

Stefan,

I have made a video for you : Microsoft OneDrive - Access files anywhere. Create docs with free Office Online.

could you tell me if it's more understandable pls ?

writing crippled words like "pls" for please is annoying.
You demontrate a lazy attitude with writing crippled words.
Me personal I find it not cool

a lot of information is still lacking.
So how many postings do you need to understand that you have to deliver

much more detail-information

than just a few lines??

post the original unchanged code that you used as a base
mark

each and every line

that you have modified in the actual code

Stefan,

You can see, i start every post by your name, you not.
personally i find it not cool too !

i'm not Lazy, but French beginner with translation problems and low knowledge ( normal ).

i supposed with video it was more understandble ! but not !!

when i'm at this point in programme, (it's at 0:50s on the jointed video)

how can enter in "setupMenuSelected == 3" to change one value and exit

(the program by the owner is not finished)

if (setupMenuSelected == 3) {  // PIR SENSOR MAIS PWM
            u8g2.setFont(u8g2_font_5x7_tr);
          if (menuPageMode) {
            u8g2.drawStr(0, 28, "VALEUR PWM");  // AFFICHAGE LIGNE
            u8g2.setCursor(0, 46);
            u8g2.print("VALEUR ");
            u8g2.print(sliderPosX);  // VALEUR DE LA POSITION DU CODEUR
            u8g2.drawStr(0, 28, "ROTARY CONTROL ON MENU");
          } else {
          }
          drawSlider(31);  // POSITION EN HAUTEUR DU LCD DU BARRE EN GRAPHE

Hi Nikaudino,

The logic of the code is pretty complex.
there is the main-menu and there are submenus

Whoever wrote this code did write the code in a way that is not fully self-explaining
and there are not enough comments that would explain all the details

what does that mean? Are you the owner of the program?
Or
is somebody else the owner of the program?

maybe you find it easier to go on in the french speaking sub-forum?

Another way to improve the communication is that you write down everything in french
and let do google-translate the translation.
This works pretty well

If even the different from you owner of the program has not yet finished the code
To me an unfinished code seems to be a bad base to use.

it would help a lot to see the original code that does not have your added modifications.

for answering this the whole code must be analysed
There is

interaction

between this part

of the code and the other parts
answer me the questions:
where is variable setupMenuSelected set to value 3?
what value does variable menuPageMode have ?

where in the code is the value of variable menuPageMode set to

  • true?
  • false?

where is pressing the encoder-button detected?
what changes of variables results out of the button-presses?

You can't answer all these questions. Of course.
And for me to answer the questions I want to see the original code
I want to save some hours of analysing what changes you made to the code

And this is the reason why I want you to post the original code.

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