I wrote a code to make a menu for 128x64 lcd and it works. For navigation i am using an encoder, it starts on the default menu, with one encoder press it switches to the main menu, then i can scroll through the options and select the choice with the click again can scroll and with one more click i can set the value of a certain variable. It works, except the encoder scrolling is not perfectly smooth, but i will fix that later. For now the code is very unorganized so i want to shorten it and make it easiest as possible to add new menus, submenus and variables. i was thinking of making a function for encoder with an argument, so it would be shorter instead of just copying the same encoder code and changing the +- counter variable, i already tried to make that function(the commented one under the encoder), but the problem is with the attachInterrupt function because it does not take function with arguments for valid so not sure how to get around that. Also thinking of making a single function for switching between the menus/submenus with the pushbutton and also making some shortened function for the arrow position. But not 100% sure how to implement that so asking here if anyone can give some tips to make it better.
#include "Arduino.h"
#include <U8g2lib.h>
#include <SPI.h>
#define LcdPrintTextFull(X, Y, Font, Text1, Variable, Text2) \
do \
{ \
u8g2.setCursor(X, Y); \
u8g2.setFont(Font); \
u8g2.print(Text1); \
u8g2.print(Variable); \
u8g2.print(Text2); \
} while (false)
#define LcdPrintText(X, Y, Font, Variable, Text) \
do \
{ \
u8g2.setCursor(X, Y); \
u8g2.setFont(Font); \
u8g2.print(Variable); \
u8g2.print(Text); \
} while (false)
#define CD 8
#define RST A2
#define CS 10
#define A 3
#define B 2
#define SW 7
enum EMenuPage
{
RETURN = 0,
HEATERS = 1,
MOTORS = 2,
FAN = 3,
PROFILES = 4,
CONFIGURATION = 5,
INFORMATION = 6,
};
enum SubmenuPage
{
RETURN_SUB = 0,
HEATERS_SUB = 1,
SCREW_MOTOR_SUB = 2,
PULLER_MOTOR_SUB = 3,
FAN_SUB = 4,
};
enum buttonStates // add plastic profiles
{
DEFAULT_SCREEN = 0,
MAIN_MENU = 1,
SUB_MENU = 2,
};
bool menuState = false,
menuHeater = false,
heatblockSet = false,
heatblockSetLastState = false;
#define DebounceDelay 200
int setHeatblockTemp = 0, setPipeTemp = 0;
unsigned int SW_Button_State = 0,
SW_Button_State1 = 0,
SW_Count = 0,
LastDebounceTimeSW = 0,
SW_Button_Last_State = LOW,
SW_Button_Last_State1 = LOW;
volatile int currentStateCLK;
int menuCounter = 0, subMenuCounter = 0, previousStateCLK;
unsigned long previousMillis1 = 0, currentMillis1 = 0,
previousMillis2 = 0, currentMillis2 = 0,
previousMillis3 = 0, currentMillis3 = 0;
const int interval10 = 10, interval100 = 100, interval1000 = 1000;
U8G2_ST7565_ERC12864_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/CS, /* dc=*/CD, /* reset=*/RST);
void readPushbutton() // function argument
{
if ((millis() - LastDebounceTimeSW) > DebounceDelay)
{
SW_Button_State = digitalRead(SW);
if (SW_Button_State != SW_Button_Last_State)
{
if (SW_Button_State == HIGH && SW_Count == DEFAULT_SCREEN)
{
SW_Count = MAIN_MENU;
menuCounter = 0;
}
SW_Button_Last_State = SW_Button_State;
}
}
}
void Encoder()
{
if (SW_Count == MAIN_MENU && heatblockSet == false)
{
currentStateCLK = digitalRead(A);
if (currentStateCLK != previousStateCLK && currentStateCLK == 1)
{
if (digitalRead(B) != currentStateCLK)
{
menuCounter--;
}
else
{
menuCounter++;
}
}
previousStateCLK = currentStateCLK;
}
if (SW_Count == SUB_MENU && heatblockSet == false)
{
currentStateCLK = digitalRead(A);
if (currentStateCLK != previousStateCLK && currentStateCLK == 1)
{
if (digitalRead(B) != currentStateCLK)
{
subMenuCounter--;
}
else
{
subMenuCounter++;
}
}
previousStateCLK = currentStateCLK;
}
if (heatblockSet == true)
{
currentStateCLK = digitalRead(A);
if (currentStateCLK != previousStateCLK && currentStateCLK == 1)
{
if (digitalRead(B) != currentStateCLK)
{
setHeatblockTemp--;
}
else
{
setHeatblockTemp++;
}
}
previousStateCLK = currentStateCLK;
}
}
/*void Encoder(int counter)
{
currentStateCLK = digitalRead(A);
if (currentStateCLK != previousStateCLK && currentStateCLK == 1)
{
if (digitalRead(B) != currentStateCLK)
{
counter--;
}
else
{
counter++;
}
}
previousStateCLK = currentStateCLK;
}*/
void printLCD()
{
if (SW_Count == MAIN_MENU)
{
LcdPrintText(5, 9, u8g2_font_helvR08_tf, "RETURN", "");
LcdPrintText(5, 18, u8g2_font_helvR08_tf, "HEATERS", "");
LcdPrintText(5, 27, u8g2_font_helvR08_tf, "MOTORS", "");
LcdPrintText(5, 36, u8g2_font_helvR08_tf, "FANS", "");
LcdPrintText(5, 45, u8g2_font_helvR08_tf, "PROFILES", "");
LcdPrintText(5, 54, u8g2_font_helvR08_tf, "CONFIGURATION", "");
LcdPrintText(5, 63, u8g2_font_helvR08_tf, "INFORMATION", "");
}
else if (SW_Count == DEFAULT_SCREEN)
{
LcdPrintText(5, 30, u8g2_font_helvR08_tf, "DEFAULT_SCREEN", "");
}
}
void menuArrow()
{
if (SW_Count == MAIN_MENU)
{
switch (menuCounter)
{
case 1:
LcdPrintText(0, 9, u8g2_font_helvR08_tf, ">", "");
break;
case 2:
LcdPrintText(0, 18, u8g2_font_helvR08_tf, ">", "");
break;
case 3:
LcdPrintText(0, 27, u8g2_font_helvR08_tf, ">", "");
break;
case 4:
LcdPrintText(0, 36, u8g2_font_helvR08_tf, ">", "");
break;
case 5:
LcdPrintText(0, 45, u8g2_font_helvR08_tf, ">", "");
break;
case 6:
LcdPrintText(0, 54, u8g2_font_helvR08_tf, ">", "");
break;
case 7:
LcdPrintText(0, 63, u8g2_font_helvR08_tf, ">", "");
break;
}
}
if (SW_Count == SUB_MENU && menuHeater == true)
{
switch (subMenuCounter)
{
case 1:
LcdPrintText(0, 10, u8g2_font_helvR08_tf, ">", "");
break;
case 2:
LcdPrintText(0, 20, u8g2_font_helvR08_tf, ">", "");
break;
case 3:
LcdPrintText(0, 30, u8g2_font_helvR08_tf, ">", "");
break;
}
}
}
void subMenu()
{
if (menuHeater == true)
{
LcdPrintText(5, 10, u8g2_font_helvR08_tf, "RETURN", "");
LcdPrintText(5, 20, u8g2_font_helvR08_tf, "HEATBLOCK=", setHeatblockTemp);
LcdPrintText(5, 30, u8g2_font_helvR08_tf, "PIPE1=", "");
}
SW_Button_State1 = digitalRead(SW);
if (SW_Button_State1 != SW_Button_Last_State1 && SW_Count == SUB_MENU && subMenuCounter == 2)
{
if (SW_Button_State1 == HIGH)
{
if (heatblockSet == false)
{
heatblockSet = true;
// Encoder(setHeatblockTemp);
}
else if (heatblockSet == true)
{
heatblockSet = false;
}
}
SW_Button_Last_State1 = SW_Button_State1;
}
}
void menuSelect()
{
if (SW_Count == MAIN_MENU && SW_Button_State == HIGH && menuCounter == 1)
{
SW_Count = DEFAULT_SCREEN;
}
if (SW_Count == MAIN_MENU && SW_Button_State == HIGH && menuCounter == 2)
{
menuHeater = true;
SW_Count = SUB_MENU;
subMenuCounter = 0;
// Encoder(subMenuCounter);
}
if (SW_Count == SUB_MENU && SW_Button_State == HIGH && subMenuCounter == 1)
{
menuHeater = false;
SW_Count = MAIN_MENU;
menuCounter = 0;
// Encoder(menuCounter);
}
}
void setup()
{
pinMode(A, INPUT);
pinMode(B, INPUT);
pinMode(SW, INPUT);
attachInterrupt(digitalPinToInterrupt(A), Encoder, RISING);
attachInterrupt(digitalPinToInterrupt(B), Encoder, RISING);
Serial.begin(4800);
u8g2.begin();
u8g2.setContrast(25);
previousStateCLK = digitalRead(A);
}
void loop()
{
// Encoder();
currentMillis1 = millis();
if (currentMillis1 - previousMillis1 >= interval10)
{
previousMillis1 = currentMillis1;
readPushbutton();
}
currentMillis2 = millis();
if (currentMillis2 - previousMillis2 >= interval100)
{
previousMillis2 = currentMillis2;
u8g2.firstPage();
do
{
printLCD();
menuArrow();
menuSelect();
subMenu();
} while (u8g2.nextPage());
}
currentMillis3 = millis();
if (currentMillis3 - previousMillis3 >= interval1000)
{
previousMillis3 = currentMillis3;
/*Serial.print("SW_Count==");
Serial.println(SW_Count);
Serial.print("menucounter==");
Serial.println(menuCounter);
Serial.print("submenucounter==");
Serial.println(subMenuCounter);*/
Serial.println(heatblockSet);
}
}