// Learn about the ESP32 WiFi simulation in
// https://docs.wokwi.com/guides/esp32-wifi
#include <WiFi.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
unsigned long UpdateTime;
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);
// LCD1602 to Arduino Uno connection example
unsigned long ST,ET;
//Menu variables
String MainMenuItemPrompt[10]; //this is what is scrolled through when in menu
String SubMenuItemPrompt[10]; //this is what is diplayed on Line 1 on LCD when menu item selected
int SubMenuPossibleResponses[10]; //this is the number of items in the list of possible responses
String SubMenuResponseAlias[10][10]; //this is the value that is shown on line 2 as possible responses are displayed
int SubMenuResponseValue[10][10]; //this stores the value corresponding to the array index selected as an alias
boolean InMenu = false;
boolean InSubMenu = false;
int MainMenuIndex=0; //stored the current index in main menu
int SubMenuResponseIndex = 0;
int MenuItems = 8; //index 0 = 1
String LCDLine1;
String LCDLine2;
String TeamA = "TeamA";
String TeamB = "TeamB";
int TeamAColor = 1;
int TeamBColor = 2;
//change these pin definitions for your schematic
int LeftUpPin = 14;
int LeftDownPin = 12;
int RightUpPin = 26;
int RightDownPin = 25;
int EnterPin = 13;
//int MenuPin = 6; //Future
//Switch State Variable
int SwitchState = 0;
//0 = Nothing Pressed
//1 = Enter Pressed
//2 = Enter Held
//3 = Left Up Pressed
//4 = Left Up Held
//5 = Left Down Pressed
//6 = Left Down Held
//7 = Right Up Pressed
//8 = Right Up Held
//9 = Right Down Pressed
//10 = Right Down Held
//11 = Menu Pressed (Future)
//12 = Menu Held (Future)
int RightScore, LeftScore;
int Game=1;
int Brightness=1; //valid values are 1 -10
boolean FlipSides=false;
int OldLeftScore;
int OldRightScore;
void LoadMenuItems(){
//modify this routine for your menu
MenuItems = 9; //this should be 1 more than the max array numer as array starts at 0
MainMenuItemPrompt[0]=F("Exit Menu");
MainMenuItemPrompt[1]=F("Switch Sides");
MainMenuItemPrompt[2]=F("Start Next Game");
MainMenuItemPrompt[3]=F("Reset Scores");
MainMenuItemPrompt[4]=F("Set Game #");
MainMenuItemPrompt[5]=F("Reset All");
MainMenuItemPrompt[6]=F("Set TeamA Color");
MainMenuItemPrompt[7]=F("Set TeamB Color");
MainMenuItemPrompt[8]=F("Set Brightness");
SubMenuItemPrompt[0]=F("");
SubMenuItemPrompt[1]=F("");
SubMenuItemPrompt[2]=F("");
SubMenuItemPrompt[3]=F("");
SubMenuItemPrompt[4]=F("Set Game #:");
SubMenuItemPrompt[5]=F("");
SubMenuItemPrompt[6]=F("Team A Color:");
SubMenuItemPrompt[7]=F("Team B Color:");
SubMenuItemPrompt[8]=F("Set Brightness:");
//this stores the number of acceptable responses stored in array, non-zero indicates data input
//the submenu response array stores acceptable answers
SubMenuPossibleResponses[0] = 0;
SubMenuPossibleResponses[1] = 0;
SubMenuPossibleResponses[2] = 0;
SubMenuPossibleResponses[3] = 0;
SubMenuPossibleResponses[4] = 9;
SubMenuPossibleResponses[5] = 0;
SubMenuPossibleResponses[6] = 10;
SubMenuPossibleResponses[7] = 10;
SubMenuPossibleResponses[8] = 10;
//set up submenu response arrays only for menu items that require data input
//data will be input based on the array index
SubMenuResponseAlias[4][0] = "1";
SubMenuResponseAlias[4][1] = "2";
SubMenuResponseAlias[4][2] = "3";
SubMenuResponseAlias[4][3] = "4";
SubMenuResponseAlias[4][4] = "5";
SubMenuResponseAlias[4][5] = "6";
SubMenuResponseAlias[4][6] = "7";
SubMenuResponseAlias[4][7] = "8";
SubMenuResponseAlias[4][8] = "9";
SubMenuResponseAlias[6][0] = "Red";
SubMenuResponseAlias[6][1] = "Green";
SubMenuResponseAlias[6][2] = "Blue";
SubMenuResponseAlias[6][3] = "Magenta";
SubMenuResponseAlias[6][4] = "Purple";
SubMenuResponseAlias[6][5] = "Light Blue";
SubMenuResponseAlias[6][6] = "Yellow";
SubMenuResponseAlias[6][7] = "Lime Green";
SubMenuResponseAlias[6][8] = "Orange";
SubMenuResponseAlias[6][9] = "White";
SubMenuResponseAlias[7][0] = "Red";
SubMenuResponseAlias[7][1] = "Green";
SubMenuResponseAlias[7][2] = "Blue";
SubMenuResponseAlias[7][3] = "Magenta";
SubMenuResponseAlias[7][4] = "Purple";
SubMenuResponseAlias[7][5] = "Light Blue";
SubMenuResponseAlias[7][6] = "Yellow";
SubMenuResponseAlias[7][7] = "Lime Green";
SubMenuResponseAlias[7][8] = "Orange";
SubMenuResponseAlias[7][9] = "White";
SubMenuResponseAlias[8][0] = "Minimum";
SubMenuResponseAlias[8][1] = "20%";
SubMenuResponseAlias[8][2] = "30%";
SubMenuResponseAlias[8][3] = "40%";
SubMenuResponseAlias[8][4] = "50%";
SubMenuResponseAlias[8][5] = "60%";
SubMenuResponseAlias[8][6] = "70%";
SubMenuResponseAlias[8][7] = "80%";
SubMenuResponseAlias[8][8] = "90%";
SubMenuResponseAlias[8][9] = "Maximum";
SubMenuResponseValue[4][0] = 1;
SubMenuResponseValue[4][1] = 2;
SubMenuResponseValue[4][2] = 3;
SubMenuResponseValue[4][3] = 4;
SubMenuResponseValue[4][4] = 5;
SubMenuResponseValue[4][5] = 6;
SubMenuResponseValue[4][6] = 7;
SubMenuResponseValue[4][7] = 8;
SubMenuResponseValue[4][8] = 9;
SubMenuResponseValue[6][0] = 1;
SubMenuResponseValue[6][1] = 2;
SubMenuResponseValue[6][2] = 3;
SubMenuResponseValue[6][3] = 4;
SubMenuResponseValue[6][4] = 5;
SubMenuResponseValue[6][5] = 6;
SubMenuResponseValue[6][6] = 7;
SubMenuResponseValue[6][7] = 8;
SubMenuResponseValue[6][8] = 9;
SubMenuResponseValue[6][9] = 10;
SubMenuResponseValue[7][0] = 1;
SubMenuResponseValue[7][1] = 2;
SubMenuResponseValue[7][2] = 3;
SubMenuResponseValue[7][3] = 4;
SubMenuResponseValue[7][4] = 5;
SubMenuResponseValue[7][5] = 6;
SubMenuResponseValue[7][6] = 7;
SubMenuResponseValue[7][7] = 8;
SubMenuResponseValue[7][8] = 9;
SubMenuResponseValue[7][9] = 10;
SubMenuResponseValue[8][0] = 1;
SubMenuResponseValue[8][1] = 2;
SubMenuResponseValue[8][2] = 3;
SubMenuResponseValue[8][3] = 4;
SubMenuResponseValue[8][4] = 5;
SubMenuResponseValue[8][5] = 6;
SubMenuResponseValue[8][6] = 7;
SubMenuResponseValue[8][7] = 8;
SubMenuResponseValue[8][8] = 9;
}
void setup() {
lcd.init();
lcd.backlight();
//lcd.begin(16, 2);
Serial.begin(115200);
pinMode(LeftUpPin, INPUT_PULLUP);
pinMode(LeftDownPin, INPUT_PULLUP);
pinMode(RightUpPin, INPUT_PULLUP);
pinMode(RightDownPin, INPUT_PULLUP);
pinMode(EnterPin, INPUT_PULLUP);
lcd.print("ScoreFi V2.0");
lcd.setCursor(0,1);
lcd.print("by Darin");
LoadMenuItems();
delay(2000);
UpdateLCD();
}
void loop() {
if (millis()>UpdateTime){
UpdateTime=millis()+50;
CheckSwitches();
if (InMenu == true && SwitchState > 0) { //menu item selected
ProcessMenuClick();
}
else if (InMenu == false && SwitchState > 0) { //
ProcessSwitches();
}
}
}
void UpdateLCD(){
lcd.clear();
if (FlipSides == false){
lcd.print(TeamA);
lcd.print(" [");
lcd.print(Game);
lcd.print("] ");
lcd.print(TeamB);
lcd.setCursor(2,1);
lcd.print(RightScore);
lcd.setCursor(13,1);
lcd.print(LeftScore);
}
else {
lcd.print(TeamB);
lcd.print(" [");
lcd.print(Game);
lcd.print("] ");
lcd.print(TeamA);
lcd.setCursor(2,1);
lcd.print(RightScore);
lcd.setCursor(13,1);
lcd.print(LeftScore);
}
}
void ProcessMenuClick(){
switch (SwitchState) {
case 0: // Exit, no button press
break;
case 1: //Enter Pressed while in menu
Serial.println("Enter Press...In Menu");
switch (MainMenuIndex) {
case 0: //exit menu requested, just get out
InMenu=false;
MainMenuIndex = 0; //reset menu index
UpdateLCD();
break;
case 1: //switch sides request
InMenu=false;
FlipSides = !FlipSides;
OldLeftScore = LeftScore;
OldRightScore = RightScore;
RightScore = OldLeftScore;
LeftScore = OldRightScore;
MainMenuIndex = 0; //reset menu index
UpdateLCD();
break;
case 2: //Start Next game/set request
InMenu=false;
Game++; //increment the game number
if (Game > 9){
Game = 0;
}
LeftScore = 0;
RightScore = 0;
MainMenuIndex = 0; //reset menu index
UpdateLCD();
break;
case 3: //reset scores
InMenu=false;
LeftScore = 0;
RightScore = 0;
MainMenuIndex = 0; //reset menu index
UpdateLCD();
break;
case 4: //Set Game Number
if (InSubMenu == true){ //if we are in a submenu, set the current value in array
Game = SubMenuResponseValue[MainMenuIndex][SubMenuResponseIndex];
Serial.print("Game: ");
Serial.println(Game);
UpdateLCD();
MainMenuIndex = 0; //reset menu index
InSubMenu = false;
}
else {
SubMenuResponseIndex = Game - 1;
lcd.clear();
lcd.print(SubMenuItemPrompt[MainMenuIndex]);
lcd.setCursor(0,1);
lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);
InSubMenu = true;
}
break;
case 5: //Reset All
InMenu=false;
LeftScore = 0;
RightScore = 0;
Game = 1;
FlipSides = false;
MainMenuIndex = 0; //reset menu index
UpdateLCD();
break;
case 6: //Change TeamA Color
if (InSubMenu == true){ //if we are in a submenu, set the current value in array
TeamAColor = SubMenuResponseValue[MainMenuIndex][SubMenuResponseIndex];
Serial.print("Team A Color: ");
Serial.println(TeamAColor);
UpdateLCD();
MainMenuIndex = 0; //reset menu index
InSubMenu = false;
}
else {
SubMenuResponseIndex = TeamAColor - 1;
lcd.clear();
lcd.print(SubMenuItemPrompt[MainMenuIndex]);
lcd.setCursor(0,1);
lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);
InSubMenu = true;
}
break;
case 7: //Change TeamB Color
if (InSubMenu == true){ //if we are in a submenu, set the current value in array
TeamBColor = SubMenuResponseValue[MainMenuIndex][SubMenuResponseIndex];
Serial.print("Team B Color: ");
Serial.println(TeamBColor);
UpdateLCD();
MainMenuIndex = 0; //reset menu index
InSubMenu = false;
}
else {
SubMenuResponseIndex = TeamBColor - 1;
lcd.clear();
lcd.print(SubMenuItemPrompt[MainMenuIndex]);
lcd.setCursor(0,1);
lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);
InSubMenu = true;
}
break;
case 8: //Change Brightness
if (InSubMenu == true){ //if we are in a submenu, set the current value in array
Brightness = SubMenuResponseValue[MainMenuIndex][SubMenuResponseIndex];
Serial.print("Brightness: ");
Serial.println(Brightness);
UpdateLCD();
MainMenuIndex = 0; //reset menu index
InSubMenu = false;
}
else {
SubMenuResponseIndex = Brightness - 1;
lcd.clear();
lcd.print(SubMenuItemPrompt[MainMenuIndex]);
lcd.setCursor(0,1);
lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);
InSubMenu = true;
}
break;
}
break; //for case 1 enter pressed
case 2: //enter held (Exit Menu)
InMenu=false;
UpdateLCD();
MainMenuIndex = 0; //reset menu index
break;
case 3: //Left Up Pressed
if (InSubMenu == true){ //if we are in a submenu, show next value in array
SubMenuResponseIndex++; //increment the index
if (SubMenuResponseIndex > SubMenuPossibleResponses[MainMenuIndex]-1){ //make sure within bounds
SubMenuResponseIndex = SubMenuPossibleResponses[MainMenuIndex]-1; //
}
lcd.clear();
lcd.print(SubMenuItemPrompt[MainMenuIndex]);
lcd.setCursor(0,1);
lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);
InSubMenu = true;
}
else { //we are not in submenu, so step through main menu items
if (MainMenuIndex - 1 >= 0) {
MainMenuIndex--;
}
ShowMenu();
}
break; //for case 3 Left Up pressed
case 5: //Left Down Pressed
if (InSubMenu == true){ //if we are in a submenu, show next value in array
SubMenuResponseIndex--; //increment the index
if (SubMenuResponseIndex < 0){ //make sure within bounds
SubMenuResponseIndex = 0; //
}
lcd.clear();
lcd.print(SubMenuItemPrompt[MainMenuIndex]);
lcd.setCursor(0,1);
lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);
InSubMenu = true;
}
else { //we are not in submenu, so step through main menu items
if (MainMenuIndex + 1 <= MenuItems -1){
MainMenuIndex++;
}
ShowMenu();
}
break; //for case 5 Left Down pressed
case 7: //Right Up Pressed
if (InSubMenu == true){ //if we are in a submenu, show next value in array
SubMenuResponseIndex++; //increment the index
if (SubMenuResponseIndex > SubMenuPossibleResponses[MainMenuIndex]-1){ //make sure within bounds
SubMenuResponseIndex = SubMenuPossibleResponses[MainMenuIndex]-1; //
}
lcd.clear();
lcd.print(SubMenuItemPrompt[MainMenuIndex]);
lcd.setCursor(0,1);
lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);
InSubMenu = true;
}
else { //we are not in submenu, so step through main menu items
if (MainMenuIndex - 1 >= 0) {
MainMenuIndex--;
}
ShowMenu();
}
break; //for case 7 Right Up pressed
case 9: //Right Down Pressed
if (InSubMenu == true){ //if we are in a submenu, show next value in array
SubMenuResponseIndex--; //increment the index
if (SubMenuResponseIndex < 0){ //make sure within bounds
SubMenuResponseIndex = 0; //
}
lcd.clear();
lcd.print(SubMenuItemPrompt[MainMenuIndex]);
lcd.setCursor(0,1);
lcd.print(SubMenuResponseAlias[MainMenuIndex][SubMenuResponseIndex]);
InSubMenu = true;
}
else { //we are not in submenu, so step through main menu items
if (MainMenuIndex + 1 <= MenuItems -1){
MainMenuIndex++;
}
ShowMenu();
}
break; //for case 9 Right Down pressed
}
}
void ShowMenu() {
InMenu = true;
lcd.clear();
LCDLine1 = MainMenuItemPrompt[MainMenuIndex];
LCDLine2="";
if (MainMenuIndex < (MenuItems - 1)) {
LCDLine2 = MainMenuItemPrompt[MainMenuIndex + 1];
}
lcd.print(">");
lcd.print(LCDLine1);
lcd.setCursor(1,1);
lcd.print(LCDLine2);
}
void ProcessSwitches(){
switch (SwitchState) {
case 0: // Exit, no button press
break;
case 1: //Enter Pressed Enter Menu
Serial.println("Enter Press...Enter Menu");
ShowMenu();
InMenu=true;
break;
case 2: //Enter Held
Serial.println("Enter Held");
break;
case 3: //Left Up Pressed
RightScore++;
UpdateLCD();
Serial.println("Left Up Press");
break;
case 4: //Left Up Held
Serial.println("Left Up Held");
break;
case 5: //Left Down Pressed
RightScore--;
UpdateLCD();
Serial.println("Left Down Press");
break;
case 6: //Left Down Held
Serial.println("Left Down Held");
break;
case 7: //Right Up Pressed
LeftScore++;
UpdateLCD();
Serial.println("Right Up Press");
break;
case 8: //Right Up Held
Serial.println("Right Up Held");
break;
case 9: //Right Down Pressed
LeftScore--;
UpdateLCD();
Serial.println("Right Down Press");
break;
case 10: //Right Down Held
Serial.println("Right Down Held");
break;
}
SwitchState = 0; //reset
delay(500); //to eliminate bounce back to press
}
void CheckSwitches(){
//0 = Nothing Pressed
//1 = Enter Pressed
//2 = Enter Held
//3 = Left Up Pressed
//4 = Left Up Held
//5 = Left Down Pressed
//6 = Left Down Held
//7 = Right Up Pressed
//8 = Right Up Held
//9 = Right Down Pressed
//10 = Right Down Held
//11 = Menu Pressed (Future)
//12 = Menu Held (Future)
SwitchState = 0; //reset
//check Enter Switch first
if (digitalRead(EnterPin) == LOW){
ST = millis();
while (digitalRead(EnterPin) == LOW){ //debounce
delay(1);
ET = millis()-ST;
}
//if we got here we have a debounced button press
if (ET > 50 && ET <750){ //short press
SwitchState = 1;
return;
}
else if (ET > 750 ){ //long press
SwitchState = 2;
return;
}
}
//check Left Up
if (digitalRead(LeftUpPin) == LOW){
ST = millis();
while (digitalRead(LeftUpPin) == LOW){ //debounce
delay(1);
ET = millis()-ST;
}
//if we got here we have a debounced button press
if (ET > 50 && ET <750){ //short press
SwitchState = 3;
return;
}
else if (ET > 750 ){ //long press
SwitchState = 4;
return;
}
}
//check Left Down
if (digitalRead(LeftDownPin) == LOW){
ST = millis();
while (digitalRead(LeftDownPin) == LOW){ //debounce
delay(1);
ET = millis()-ST;
}
//if we got here we have a debounced button press
if (ET > 50 && ET <750){ //short press
SwitchState = 5;
return;
}
else if (ET > 750 ){ //long press
SwitchState = 6;
return;
}
}
//check Right Up
if (digitalRead(RightUpPin) == LOW){
ST = millis();
while (digitalRead(RightUpPin) == LOW){ //debounce
delay(1);
ET = millis()-ST;
}
//if we got here we have a debounced button press
if (ET > 50 && ET <750){ //short press
SwitchState = 7;
return;
}
else if (ET > 750 ){ //long press
SwitchState = 8;
delay(500); //to eliminate bounce back to press
return;
}
}
//check Right Down
if (digitalRead(RightDownPin) == LOW){
ST = millis();
while (digitalRead(RightDownPin) == LOW){ //debounce
delay(1);
ET = millis()-ST;
}
//if we got here we have a debounced button press
if (ET > 50 && ET <750){ //short press
SwitchState = 9;
return;
}
else if (ET > 750 ){ //long press
SwitchState = 10;
return;
}
}
} //end of check switches