/**************************************************************************************************
FileName : Menu_DFR_LCD_OLED_V1.ino
Menu de base
OLED display simple none blocking menu System - i2c version SSD1306 - 30mar22
OLED display simple none blocking menu System - i2c version SSD1306 - 30mar22
This sketch is on Github: https://github.com/alanesq/BasicOLEDMenu
https://wokwi.com/projects/323967017900048980 "sketch Source"
mega_ShieldsLab_RE_OLED
- https://wokwi.com/projects/413735615119147009
OutilsLab_RE_OLED : UNO_OLED_Encoder_Menu - Wokwi ESP32, STM32, Arduino Simulator
https://wokwi.com/projects/411471879427147777
**************************************************************************************************
*/
#include <SPI.h>
#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 SSD1306 display connected using I2C
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// #include "Affiche_OLED.h"
// Misc
const int serialDebug = 1;
const int iLED = 13; // onboard indicator led gpio pin
// #define BUTTONPRESSEDSTATE 0 // rotary encoder gpio pin logic level when the button is pressed (usually 0)
// #define DEBOUNCEDELAY 20 // debounce delay for button inputs
const int menuTimeout = 120; // menu inactivity timeout (seconds)
const bool menuLargeText = 0; // show larger text when possible (if struggling to read the small text)
const int maxmenuItems = 20; // max number of items used in any of the menus (keep as low as possible to save memory)
// const int itemTrigger = 2; // rotary encoder - counts per tick (varies between encoders usually 1 or 2)
const int topLine = 18; // y position of lower area of the display (18 with two colour displays)
const byte lineSpace1 = 9; // line spacing for textsize 1 (small text)
const byte lineSpace2 = 17; // line spacing for textsize 2 (large text)
const int displayMaxLines = 5; // max lines that can be displayed in lower section of display in textsize1 (5 on larger oLeds)
const int MaxmenuTitleLength = 10; // max characters per line when using text size 2 (usually 10)
// -------------------------------------------------------------------------------------------------
// void doEncoder();
// void mainMenu();
// void menuActions();
// void value1();
// void menuValues();
// void reUpdateButton();
void serviceMenu();
// int serviceValue(bool _blocking);
// void createList(String _title, int _noOfElements, String *_list);
void displayMessage(String _title, String _message);
void resetMenu();
// menus
// modes that the menu system can be in
enum menuModes {
off, // display is off
menu, // a menu is active
value, // 'enter a value' none blocking is active
message, // displaying a message
blocking // a blocking procedure is in progress (see enter value)
};
menuModes menuMode = off; // default mode at startup is off
struct oledMenus {
// menu
String menuTitle = ""; // the title of active mode
int noOfmenuItems = 0; // number if menu items in the active menu
int selectedMenuItem = 0; // when a menu item is selected it is flagged here until actioned and cleared
int highlightedMenuItem = 0; // which item is curently highlighted in the menu
// String menuItems[maxmenuItems + 1]; // store for the menu item titles
uint32_t lastMenuActivity = 0; // time the menu last saw any activity (used for timeout)
// 'enter a value'
// int mValueEntered = 0; // store for number entered by value entry menu
// int mValueLow = 0; // lowest allowed value
// int mValueHigh = 0; // highest allowed value
// int mValueStep = 0; // step size when encoder is turned
};
oledMenus oledMenu;
int readKey;
void setup()
{
Serial.begin(115200); while (!Serial); delay(50); // start serial comms
Serial.println("\n\n\nStarting Main menu\n");
// initialize the OLED object
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Don't proceed, loop forever
}
// Uncomment this if you are using SPI
//if(!display.begin(SSD1306_SWITCHCAPVCC)) {
// Serial.println(F("SSD1306 allocation failed"));
// for(;;); // Don't proceed, loop forever
//}
// display greeting message - pressing button will start menu
// display greeting message 1
displayMessage(" STARTED", "\n\nPresse Button SELECT\n\nto START Main_menu");
do {
readKey = analogRead(0);
} while (readKey != 639); // SELECT
display.clearDisplay();
display.display();//
Serial.println("quitte greeting OLED");
// ou display greeting message 2
// // *****************************
// // greeting on oLED
// // *****************************
// greeting_oLED();
} // end setup
// ----------------------------------------------------------------
// -loop
// ----------------------------------------------------------------
// called from main loop
void loop() {
// reUpdateButton(); // update rotary encoder button status (if pressed activate default menu)
menuUpdate(); // update or action the oled menu
// flash onboard led
// static uint32_t ledTimer = millis();
// if ( (unsigned long)(millis() - ledTimer) > 500 ) {
// digitalWrite(iLED, !digitalRead(iLED));
// ledTimer = millis();
// }
} // oledLoop
// ----------------------------------------------------------------
// -update the active menu
// ----------------------------------------------------------------
void menuUpdate() {
Serial.println((menuMode));
if (menuMode == off) return; // if menu system is turned off do nothing more
// if no recent activity then turn oled off
if ( (unsigned long)(millis() - oledMenu.lastMenuActivity) > (menuTimeout * 1000) ) {
resetMenu();
return;
}
switch (menuMode) {
// // if there is an active menu
// Serial.println(menuMode);
case menu:
serviceMenu();
// menuActions();
break;
// // if there is an active none blocking 'enter value'
// case value:
// // serviceValue(0);
// // if (rotaryEncoder.reButtonPressed) { // if the button has been pressed
// // menuValues(); // a value has been entered so action it
// break;
// // if a message is being displayed
// case message:
// // if (rotaryEncoder.reButtonPressed == 1) defaultMenu(); // if button has been pressed return to default menu
// break;
}
}
// ----------------------------------------------------------------
// -service active menu
// ----------------------------------------------------------------
void serviceMenu() {
// // rotary encoder
// if (rotaryEncoder.encoder0Pos >= itemTrigger) {
// rotaryEncoder.encoder0Pos -= itemTrigger;
// oledMenu.highlightedMenuItem++;
// oledMenu.lastMenuActivity = millis(); // log time
// }
// if (rotaryEncoder.encoder0Pos <= -itemTrigger) {
// rotaryEncoder.encoder0Pos += itemTrigger;
// oledMenu.highlightedMenuItem--;
// oledMenu.lastMenuActivity = millis(); // log time
// }
// if (rotaryEncoder.reButtonPressed == 1) {
// oledMenu.selectedMenuItem = oledMenu.highlightedMenuItem; // flag that the item has been selected
// oledMenu.lastMenuActivity = millis(); // log time
// if (serialDebug) Serial.println("menu '" + oledMenu.menuTitle + "' item '" + oledMenu.menuItems[oledMenu.highlightedMenuItem] + "' selected");
// }
// const int _centreLine = displayMaxLines / 2 + 1; // mid list point
// display.clearDisplay();
// display.setTextColor(WHITE);
// // verify valid highlighted item
// if (oledMenu.highlightedMenuItem > oledMenu.noOfmenuItems) oledMenu.highlightedMenuItem = oledMenu.noOfmenuItems;
// if (oledMenu.highlightedMenuItem < 1) oledMenu.highlightedMenuItem = 1;
// title
// display.setCursor(0, 0);
// if (menuLargeText) {
// display.setTextSize(2);
// display.println(oledMenu.menuItems[oledMenu.highlightedMenuItem].substring(0, MaxmenuTitleLength));
// } else {
// if (oledMenu.menuTitle.length() > MaxmenuTitleLength) display.setTextSize(1);
// else display.setTextSize(2);
// display.println(oledMenu.menuTitle);
// }
// display.drawLine(0, topLine-1, display.width(), topLine-1, WHITE); // draw horizontal line under title
// // menu
// display.setTextSize(1);
// display.setCursor(0, topLine);
// for (int i=1; i <= displayMaxLines; i++) {
// int item = oledMenu.highlightedMenuItem - _centreLine + i;
// if (item == oledMenu.highlightedMenuItem) display.setTextColor(BLACK, WHITE);
// else display.setTextColor(WHITE);
// if (item > 0 && item <= oledMenu.noOfmenuItems) display.println(oledMenu.menuItems[item]);
// else display.println(" ");
// }
// how to display some updating info. on the menu screen
display.setCursor(80, 25);
display.println(millis());
display.display();
} // endserviceMenu
// ----------------------------------------------------------------
// -message display
// ----------------------------------------------------------------
// 21 characters per line, use "\n" for next line
// assistant: < line 1 >< line 2 >< line 3 >< line 4 >
void displayMessage(String _title, String _message) {
resetMenu();
menuMode = message;
display.clearDisplay();
display.setTextColor(WHITE);
// title
display.setCursor(0, 0);
if (menuLargeText) {
display.setTextSize(2);
display.println(_title.substring(0, MaxmenuTitleLength));
} else {
if (_title.length() > MaxmenuTitleLength) display.setTextSize(1);
else display.setTextSize(2);
display.println(_title);
}
// message
display.setCursor(0, topLine);
display.setTextSize(1);
display.println(_message);
display.display();
}
// ----------------------------------------------------------------
// -reset menu system
// ----------------------------------------------------------------
void resetMenu() {
Serial.println("reset menu");
// reset all menu variables / flags
menuMode = off;
oledMenu.selectedMenuItem = 0;
// rotaryEncoder.encoder0Pos = 0;
oledMenu.noOfmenuItems = 0;
oledMenu.menuTitle = "";
// oledMenu.highlightedMenuItem = 0;
// oledMenu.mValueEntered = 0;
// rotaryEncoder.reButtonPressed = 0;
oledMenu.lastMenuActivity = millis(); // log time
// clear oled display
display.clearDisplay();
display.display();
}