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
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);
}
}