Hi! I've been trying to make a "simple" menu system for a 128 x 64 OLED with a rotary encoder (with pushbutton) since the ones online didn't really work or didn't fit my needs and were a bit complicated. So I wanted to create my own, way simpler. Or so I thought...
This is what I came up with after working on it for way too long:
#include <Bounce2.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "bitmaps.h"
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define LOGO_HEIGHT 64
#define LOGO_WIDTH 128
#define sw 5
#define outputA 6
#define outputB 7
#define VCC 8
//////////////////////////////////////////
int noOfMenus = 3;
//////////////////////////////////////////
int counter = 0 ;
int aState ;
int aLastState ;
int lastSw ;
int lastCounter ;
int currentSw ;
int oldValue;
int x = 1;
bool drewDisplayMenu = false;
bool drewSettingsMenu = false;
bool drewPlaceholderMenu = false;
bool exittedSettingsMenu = false;
bool wentThruSubSettings = false;
bool firstTime = true;
bool pressedFirstTime = false;
bool releasedFirstTime = true;
bool ignoreEncoder = false;
//bool cleared = false;
Bounce debouncer = Bounce();
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setup() {
pinMode (outputA, INPUT);
pinMode (outputB, INPUT);
pinMode (sw, INPUT_PULLUP);
pinMode (VCC, OUTPUT);
digitalWrite(VCC, HIGH);
debouncer.attach(sw);
debouncer.interval(5); // interval in ms
Serial.begin (9600);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Don't proceed, loop forever
}
aLastState = digitalRead(outputA);
display.display();
display.clearDisplay();
display.display();
}
void loop() {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Button debouncing with Bounce2
debouncer.update();
int value = debouncer.read();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Encoder algorythm
if (ignoreEncoder == false) {
aState = digitalRead(outputA); // Reads the "current" state of the outputA
// If the previous and the current state of the outputA are different, that means a Pulse has occured
if (aState != aLastState) {
// If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
if (digitalRead(outputB) != aState) {
counter ++;
} else {
counter --;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Calculating menu position
int counterer = counter / 2;
if (counterer % noOfMenus == noOfMenus - noOfMenus) {
drewDisplayMenu = false;
drewPlaceholderMenu = false;
drawSettingsMenu();
if (value == HIGH) {
releasedFirstTime = true;
}
if (value == LOW && firstTime == true && releasedFirstTime == true) {
drawSubSettings(counterer);
pressedFirstTime = true;
}
if (value == HIGH && pressedFirstTime == true) {
drawSubSettings(counterer);
firstTime = false;
}
if (value == LOW && firstTime == false) {
drewSettingsMenu = false;
firstTime = true;
pressedFirstTime = false;
releasedFirstTime = false;
ignoreEncoder = false;
}
/* if (value == 0) { //pressed
drawSubSettings();
}
if (wentThruSubSettings == true) {
drewSettingsMenu = false;
}
*/
}
if (counterer % noOfMenus == noOfMenus - noOfMenus + 1 || counterer % noOfMenus == noOfMenus - noOfMenus - 1) {
drewSettingsMenu = false;
drewPlaceholderMenu = false;
drawDataDisplayMenu();
}
if (counterer % noOfMenus == noOfMenus - noOfMenus + 2 || counterer % noOfMenus == noOfMenus - noOfMenus - 2) {
drewSettingsMenu = false;
drewDisplayMenu = false;
drawPlaceholderMenu();
}
if (drewDisplayMenu == true && drewSettingsMenu == true) {
drewDisplayMenu = false;
drewSettingsMenu = false;
}
aLastState = aState; // Updates the previous state of the outputA with the current state
lastCounter = counterer;
lastSw = value;
oldValue = value;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Optional debug
//Serial.println(value);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Drawing functions
void drawSettingsMenu(void) {
if (!drewSettingsMenu) {
display.clearDisplay();
display.drawBitmap((display.width() - LOGO_WIDTH ) / 2, (display.height() - LOGO_HEIGHT) / 2, settingsMenu, LOGO_WIDTH, LOGO_HEIGHT, 1);
display.display();
drewSettingsMenu = true;
}
}
void drawSubSettings(int secondValue) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.println(analogRead(A0));
display.println(secondValue);
display.display();
ignoreEncoder = true;
}
void drawDataDisplayMenu(void) {
if (!drewDisplayMenu) {
display.clearDisplay();
display.drawBitmap((display.width() - LOGO_WIDTH ) / 2, (display.height() - LOGO_HEIGHT) / 2, dataDisplayMenu, LOGO_WIDTH, LOGO_HEIGHT, 1);
display.display();
drewDisplayMenu = true;
}
}
void drawPlaceholderMenu(void) {
if (!drewPlaceholderMenu) {
display.clearDisplay();
display.drawBitmap((display.width() - LOGO_WIDTH ) / 2, (display.height() - LOGO_HEIGHT) / 2, placeholderMenu, LOGO_WIDTH, LOGO_HEIGHT, 1);
display.display();
drewPlaceholderMenu = true;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// End of program
(the bitmap.h didn't fit so it's attached)
And for some unknown reason, it works ;D . But I wanted to make it... maybe more compact?
Its purpose:
variable number of menus (atm only 3)
scroll through them with encoder
click encoder on "settings" menu
get analogRead(A0) and the current encoder count/cycle (also ignore encoder so things don't get messed up)
click again to exit submenu of settings
get back to scrolling through menus
How could I make the code less ugly and more compact?
Thanks.
bitmaps.h (18.4 KB)