#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SSD1306_NO_SPLASH
#define encoder0PinA 2
#define encoder0PinB 4
#define encoder0Press 5
#define OLED_ADDR 0x3C
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define BUTTONPRESSEDSTATE 0
#define DEBOUNCEDELAY 20
const int menuTimeout = 10;
const bool menuLargeText = 0;
const int maxmenuItems = 12;
const int itemTrigger = 2;
const int topLine = 18;
const byte lineSpace1 = 9;
const byte lineSpace2 = 17;
const int displayMaxLines = 5;
const int MaxmenuTitleLength = 10;
enum menuModes {
off,
menu,
value,
message,
blocking
};
menuModes menuMode = off;
struct oledMenus {
String menuTitle = "";
int noOfmenuItems = 0;
int selectedMenuItem = 0;
int highlightedMenuItem = 0;
String menuItems[maxmenuItems + 1];
uint32_t lastMenuActivity = 0;
int mValueEntered = 0;
int mValueLow = 0;
int mValueHigh = 0;
int mValueStep = 0;
int mValue = 0;
};
oledMenus oledMenu;
struct rotaryEncoders {
volatile int encoder0Pos = 0;
volatile bool encoderPrevA;
volatile bool encoderPrevB;
uint32_t reLastButtonChange = 0;
bool encoderPrevButton = 0;
int reButtonDebounced = 0;
const bool reButtonPressedState = BUTTONPRESSEDSTATE;
const uint32_t reDebounceDelay = DEBOUNCEDELAY;
bool reButtonPressed = 0;
};
rotaryEncoders rotaryEncoder;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void demoMenu() {
resetMenu();
menuMode = menu;
oledMenu.noOfmenuItems = 2;
oledMenu.menuTitle = "demo_menu";
oledMenu.menuItems[1] = "On or Off";
oledMenu.menuItems[2] = "Enter value";
}
void menuActions() {
if (oledMenu.menuTitle == "demo_menu") {
handleDemoMenuActions();
}
}
void handleDemoMenuActions() {
if (oledMenu.selectedMenuItem == 1) {
resetMenu();
menuMode = value;
oledMenu.menuTitle = "on or off";
oledMenu.mValueLow = 0;
oledMenu.mValueHigh = 1;
oledMenu.mValueStep = 1;
oledMenu.mValueEntered = 0;
}
else if (oledMenu.selectedMenuItem == 2) {
resetMenu();
menuMode = value;
oledMenu.menuTitle = "demo_value";
oledMenu.mValueLow = 1;
oledMenu.mValueHigh = 10000;
oledMenu.mValueStep = 1;
oledMenu.mValueEntered = 0;
}
oledMenu.selectedMenuItem = 0;
}
void menuValues() {
if (oledMenu.menuTitle == "demo_value") {
demoMenu();
}
if (oledMenu.menuTitle == "on or off") {
demoMenu();
}
}
void reUpdateButton() {
bool tReading = digitalRead(encoder0Press);
if (tReading != rotaryEncoder.encoderPrevButton) {
rotaryEncoder.reLastButtonChange = millis();
}
if (millis() - rotaryEncoder.reLastButtonChange > rotaryEncoder.reDebounceDelay) {
if (rotaryEncoder.encoderPrevButton == rotaryEncoder.reButtonPressedState && rotaryEncoder.reButtonDebounced == 0) {
rotaryEncoder.reButtonPressed = 1;
if (menuMode == off) {
demoMenu();
}
rotaryEncoder.reButtonDebounced = 1;
} else {
rotaryEncoder.reButtonDebounced = 0;
}
}
rotaryEncoder.encoderPrevButton = tReading;
}
void menuUpdate() {
if (menuMode == off) return;
if ( (unsigned long)(millis() - oledMenu.lastMenuActivity) > (menuTimeout * 1000) ) {
resetMenu();
return;
}
if (menuMode == menu)
{
serviceMenu();
menuActions();
}
if (menuMode == value)
{
serviceValue();
if (rotaryEncoder.reButtonPressed) {
menuValues();
}
}
if (menuMode == message)
{
if (rotaryEncoder.reButtonPressed == 1) demoMenu();
}
}
void serviceMenu() {
checkForRotaryEncoder();
updateHighlightedMenuItem();
displayMenu();
}
void checkForRotaryEncoder() {
if (rotaryEncoder.encoder0Pos >= itemTrigger) {
rotaryEncoder.encoder0Pos -= itemTrigger;
oledMenu.highlightedMenuItem++;
oledMenu.lastMenuActivity = millis();
}
if (rotaryEncoder.encoder0Pos <= -itemTrigger) {
rotaryEncoder.encoder0Pos += itemTrigger;
oledMenu.highlightedMenuItem--;
oledMenu.lastMenuActivity = millis();
}
if (rotaryEncoder.reButtonPressed == 1) {
oledMenu.selectedMenuItem = oledMenu.highlightedMenuItem;
oledMenu.lastMenuActivity = millis();
}
}
void updateHighlightedMenuItem() {
if (oledMenu.highlightedMenuItem > oledMenu.noOfmenuItems) oledMenu.highlightedMenuItem = oledMenu.noOfmenuItems;
if (oledMenu.highlightedMenuItem < 1) oledMenu.highlightedMenuItem = 1;
}
void displayMenu() {
const int _centreLine = displayMaxLines / 2 + 1;
display.clearDisplay();
display.setTextColor(WHITE);
display.setCursor(0, 0);
if (menuLargeText) {
display.setTextSize(2);
display.println(oledMenu.menuItems[oledMenu.highlightedMenuItem].substring(0, MaxmenuTitleLength));
} else {
display.setTextSize(1);
display.println(oledMenu.menuItems[oledMenu.highlightedMenuItem]);
}
int _startAt = oledMenu.highlightedMenuItem - _centreLine + 1;
if (_startAt < 1) _startAt = 1;
int _endAt = _startAt + displayMaxLines - 1;
if (_endAt > oledMenu.noOfmenuItems) _endAt = oledMenu.noOfmenuItems;
display.setTextSize(1);
for (int _line = _startAt; _line <= _endAt; _line++) {
display.setCursor(0, topLine
+ ((_line - _startAt) * lineSpace1));
if (_line == oledMenu.highlightedMenuItem) {
display.setTextColor(WHITE);
} else {
display.setTextColor(BLACK, WHITE);
}
display.println(oledMenu.menuItems[_line]);
}
display.display();
}
void serviceValue() {
const int _valueSpacingX = 30;
const int _valueSpacingY = 5;
uint32_t tTime;
if (rotaryEncoder.reButtonPressed == 0 && tTime < (menuTimeout * 1000))
{
if (oledMenu.menuTitle == "demo_value") {
if (rotaryEncoder.encoder0Pos <= -itemTrigger) {
rotaryEncoder.encoder0Pos += itemTrigger;
if (oledMenu.mValueEntered == 1) {
oledMenu.mValueEntered = 10;
} else if (oledMenu.mValueEntered == 10) {
oledMenu.mValueEntered = 100;
} else if (oledMenu.mValueEntered == 100) {
oledMenu.mValueEntered = 1000;
} else if (oledMenu.mValueEntered == 1000) {
oledMenu.mValueEntered = 10000;
}
oledMenu.lastMenuActivity = millis();
}
if (rotaryEncoder.encoder0Pos >= itemTrigger) {
rotaryEncoder.encoder0Pos -= itemTrigger;
if (oledMenu.mValueEntered == 10) {
oledMenu.mValueEntered = 1;
} else if (oledMenu.mValueEntered == 100) {
oledMenu.mValueEntered = 10;
} else if (oledMenu.mValueEntered == 1000) {
oledMenu.mValueEntered = 100;
} else if (oledMenu.mValueEntered == 10000) {
oledMenu.mValueEntered = 1000;
}
oledMenu.lastMenuActivity = millis();
}
} else {
if (rotaryEncoder.encoder0Pos >= itemTrigger) {
rotaryEncoder.encoder0Pos -= itemTrigger;
oledMenu.mValueEntered -= oledMenu.mValueStep ;
oledMenu.lastMenuActivity = millis();
}
if (rotaryEncoder.encoder0Pos <= -itemTrigger) {
rotaryEncoder.encoder0Pos += itemTrigger;
oledMenu.mValueEntered += oledMenu.mValueStep ;
oledMenu.lastMenuActivity = millis();
}
}
if (oledMenu.mValueEntered < oledMenu.mValueLow) {
oledMenu.mValueEntered = oledMenu.mValueLow;
oledMenu.lastMenuActivity = millis();
}
if (oledMenu.mValueEntered > oledMenu.mValueHigh) {
oledMenu.mValueEntered = oledMenu.mValueHigh;
oledMenu.lastMenuActivity = millis();
}
display.clearDisplay();
display.setTextColor(WHITE);
display.setCursor(0, 0);
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);
display.setCursor(_valueSpacingX, topLine + _valueSpacingY);
display.setTextSize(3);
display.println(oledMenu.mValueEntered);
display.setCursor(0, display.height() - lineSpace1 - 1 );
display.setTextSize(1);
display.println(String(oledMenu.mValueLow) + " to " + String(oledMenu.mValueHigh));
int Tlinelength = map(oledMenu.mValueEntered, oledMenu.mValueLow, oledMenu.mValueHigh, 0, display.width());
display.drawLine(0, display.height() - 1, Tlinelength, display.height() - 1, WHITE);
display.display();
reUpdateButton();
tTime = (unsigned long)(millis() - oledMenu.lastMenuActivity);
}
}
void resetMenu() {
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();
display.clearDisplay();
display.display();
}
void doEncoder() {
bool pinA = digitalRead(encoder0PinA);
bool pinB = digitalRead(encoder0PinB);
if (rotaryEncoder.encoderPrevA == pinA && rotaryEncoder.encoderPrevB == pinB) {
return;
}
int change = 0;
if (rotaryEncoder.encoderPrevA != pinA) {
change = (rotaryEncoder.encoderPrevA == rotaryEncoder.encoderPrevB) ? 1 : -1;
} else {
change = (rotaryEncoder.encoderPrevA == rotaryEncoder.encoderPrevB) ? -1 : 1;
}
rotaryEncoder.encoder0Pos += change;
rotaryEncoder.encoderPrevA = pinA;
rotaryEncoder.encoderPrevB = pinB;
}
void setup() {
Serial.begin(9600);
pinMode(encoder0Press, INPUT_PULLUP);
pinMode(encoder0PinA, INPUT_PULLUP);
pinMode(encoder0PinB, INPUT_PULLUP);
!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
rotaryEncoder.encoder0Pos = 0;
attachInterrupt(digitalPinToInterrupt(encoder0PinA), doEncoder, CHANGE);
demoMenu();
}
void loop() {
reUpdateButton();
menuUpdate();
Serial.println(oledMenu.menuTitle);
}Loading
ssd1306
ssd1306