Here’s a version of the UI with all the lcd “stuff” in it. The version I run (w/o lcd “stuff”) seems to work OK. It retrieve data loaded into EEPROM with the utility program. It displays that data in the lcd and on the serial monitor, allowing the user to alter the parameters. You invoke the UI mode by pressing the select button (pin6) for 1 sec. You exit the UI mode by scrolling to the “exit” menu and choosing one of the 3 exit strategies. You can exit w/o saving or using any change you made. You can exit and use the CoF parameters you modified (w/o resaving them to EEPROM) or exit and use them after saving them to EEPROM. When at the CoF menu, you can scroll among all the CoFs stored in EEPROM (by name) and then choose a new one to load (press select button) and modify and resave (if you wish).
#include <OLEDFourBit.h>
#include <stdio.h>
#include <string.h>
#include <EEPROM.h>
#include <PString.h>
// initialize the library with the numbers of the interface pins
OLEDFourBit lcd(12, 11, 5, 4, 9, 8);
// set pin numbers
const byte SelectPin = 6; // the select button pin for this test
const byte LEDPin = 13; // the number of the LED output pin
const byte Vert = A0; // the analog input for up or down button
const byte Horz = A1; // the analog input for left or right button
// initialize the constants
const unsigned long DB_delay = 750; // set a debounce wait time of 300 msecs
const unsigned long MaxTime = 60001; // the max time the timer can run for = 60 secs
const byte MaxHits = 24; // Maximum number if hits allowed
const int LoThrshld = 255; // Low threshold for L/D button push
const int HiThrshld = 767; // High threshold for R/U button push
char* MenuList[] ={" Select CoF: "," Select # shooters: "," Select Delay: ",
" Select # of hits: "," Select stop time: "," Save options: "};
char* Savelist[] = {" Exit ","Exit and Use ","Exit and Save"};
// initialize global variables
int CoF = 0; // initialize the CoF used to be the 1st
char CoFname[11]; // set aside space for 10 char name
char buf[21]; // buffer for LCD line 3
byte NumShooters = 1; // initialize the number of shooters to 1
byte RanDly = 0; // set random to disabled
byte StopHits = MaxHits; // Number if hits allowed before stopping
unsigned long StopTime = MaxTime; // Time that the timer will stop at
byte UI_mode = 0; // set the user interface to off
byte UI_init = 0; // set the user interface to not initialized
byte magicNumber = 0x00; // set magic number to 0
byte EEblocksize = 0; // set size of blocks used to hold CoF params to zero
const unsigned long maskHigh = 0xF000; // mask for storing time
const unsigned long maskMidU = 0x0F00; // mask for storing time
const unsigned long maskMidL = 0x00F0; // mask for storing time
const unsigned long maskLow = 0x000F; // mask for storing time
int tmpCoF = CoF; // temp version of timer control
char tmpCoFname[11]; // set aside space for 10 char name
byte tmpRanDly = RanDly; // temp version of timer control
byte tmpNumShooters = NumShooters; // temp version of timer control
byte tmpStopHits = StopHits; // temp version of timer control
unsigned long tmpStopTime = StopTime; // temp version of timer control
unsigned long LastTime = 0; // last time LCD was updated
int FourWay[] = {0, 0, 0, 0};
int indxMenu = 0; // preset to land on CoF menu
int indxSave = 1; // preset to exit and use
int numCoF = 1; // init # of CoFs
char Line3[21];
void setup()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" User Interface ");
lcd.setCursor(0, 1);
lcd.print(" Initializing ");
delay(2000);
// initialize output pins
pinMode(LEDPin, OUTPUT);
digitalWrite(LEDPin, LOW);
// initialize the input pins with internal pullups
pinMode(SelectPin, INPUT);
digitalWrite(SelectPin, HIGH);
// opens serial port, sets data rate to 9600 bps
Serial.begin(9600);
// determine how many CoFs are stored in EEPROM
MapProm();
// for this test code, retrieve the last one used and init the CoF params to that
get_CoF(0);
// copy tmp values to real values
strcpy(CoFname, tmpCoFname);
NumShooters = tmpNumShooters;
RanDly = tmpRanDly;
StopHits = tmpStopHits;
StopTime = tmpStopTime;
lcd.setCursor(0, 1);
lcd.print(" Ready ");
// Send this data to the serial monitor for debug purposes only
Serial.println("~ Initial values are ~");
Serial.print("UI_mode is : ");
Serial.println(UI_mode);
Serial.print("CoF is : ");
Serial.println(CoFname);
Serial.print("# Shooters is : ");
Serial.println(NumShooters);
Serial.print("Random/Fixed delay is : ");
Serial.println(RanDly);
Serial.print("Stop hits # is : ");
Serial.println(StopHits);
Serial.print("Stop time is : ");
Serial.println(StopTime/1000.0);
delay(2000);
}
void loop()
{
// read the Select button and see if its been pushed for 1 sec
if(digitalRead(SelectPin) == LOW)
{
delay(1000);
if(digitalRead(SelectPin) == LOW)
{
UI_mode = 1; // button pushed to enter UI mode
Serial.print("UI_mode is : ");
Serial.println(UI_mode);
delay(DB_delay); // wait to release press and debounce
}
}
// now see if the UI is enabled
if(UI_mode)
{
// UI enabled, read the buttons and set FourWay(LRUD)
GetButtons();
if(UI_init == 0)
{
// first pass since enabled so initialize the indices etc etc
UI_init = 1;
indxMenu = 0; // land on CoF menu
indxSave = 1; // be on exit n use
tmpCoF = CoF; // copy control to UI temp
tmpRanDly = RanDly; // copy control to UI temp
tmpNumShooters = NumShooters; // copy control to UI temp
tmpStopHits = StopHits; // copy control to UI temp
tmpStopTime = StopTime; // copy control to UI temp
// update the LCD to display the UI
lcd.clear();
lcd.setCursor(0,0); // go to line 1
lcd.print(MenuList[indxMenu]); // Show the Menu
lcd.setCursor(0,2); // go to line 3
lcd.print(tmpCoFname); // show what Menu item
Serial.println(" ");
Serial.println(MenuList[indxMenu]);
Serial.println(tmpCoFname);
}
// set index to determine which menu item is displayed
if(FourWay[1]) // right button pressed
{
indxMenu++;
}
if(FourWay[0]) // left button pressed
{
indxMenu--;
}
if(indxMenu<0) // wrap around
{
indxMenu=5; // presently 6 menu items 0-5
}
if(indxMenu>5) // wrap around
{
indxMenu=0;
}
switch (indxMenu) // display menu item set via index
{
case 0: // CoF menu
if(FourWay[2])
{
tmpCoF++;
}
if(FourWay[3])
{
tmpCoF--;
}
if(tmpCoF < 0)
{
tmpCoF = numCoF - 1;
}
if(tmpCoF >= numCoF)
{
tmpCoF = 0;
}
// read name of CoF selected from EEPROM
get_CoFname(tmpCoF);
if(digitalRead(SelectPin) == LOW) // select buttun pushed to load CoF
{
get_CoF(tmpCoF);
lcd.setCursor(0,1); // go to line 2
lcd.print("Loading from EEPROM"); // indicate button push nd loading
delay(2000);
lcd.setCursor(0,1); // go to line 2
lcd.print(" "); // erase the line now
Serial.print("Loading ");
Serial.print(CoFname);
Serial.println(" from EEPROM");
delay(DB_delay);
}
strcpy(Line3, tmpCoFname);
break;
case 1: // number of shooters menu
if(FourWay[2])
{
tmpNumShooters++;
}
if(FourWay[3])
{
tmpNumShooters++;
}
if(tmpNumShooters>2)
{
tmpNumShooters=1;
}
PString(buf, sizeof(buf), tmpNumShooters); // convert to char
strcpy(Line3, buf);
break;
case 2: // countdown delay menu
if(FourWay[2])
{
tmpRanDly++;
}
if(FourWay[3])
{
tmpRanDly++;
}
if(tmpRanDly>1)
{
tmpRanDly=0;
}
PString(buf, sizeof(buf), tmpRanDly); // convert to char
strcpy(Line3, buf);
break;
case 3: // Stop hits menu
if(FourWay[2])
{
tmpStopHits++;
}
if(FourWay[3])
{
tmpStopHits--;
}
if(tmpStopHits < 1)
{
tmpStopHits = MaxHits;
}
if(tmpStopHits > MaxHits)
{
tmpStopHits = 1;
}
PString(buf, sizeof(buf), tmpStopHits); // convert to char
strcpy(Line3, buf);
break;
case 4: // Stop time menu
if(FourWay[2])
{
tmpStopTime += 1000; // add 1000 msec to stoptime if up is pushed
}
if(FourWay[3])
{
tmpStopTime -= 1000; // subtract 1000 msec to stoptime if down is pushed
}
if(tmpStopTime < 1000) // min stop time is 1 sec
{
tmpStopTime = MaxTime; // wrap around to max stop time
}
if(tmpStopTime > MaxTime)
{
tmpStopTime = 1001; // wrap around to min stop time, 1 sec
}
PString(buf, sizeof(buf), tmpStopTime/1000.0); // convert to char
strcpy(Line3, buf);
break;
case 5: // Save options menu
if(FourWay[2])
{
indxSave++;
}
if(FourWay[3])
{
indxSave--;
}
if(indxSave < 0)
{
indxSave = 2;
}
if(indxSave > 2)
{
indxSave = 0;
}
strcpy(Line3, Savelist[indxSave]);
break;
}
// update LCD if something has possibly changed
if(FourWay[0] | FourWay[1] | FourWay[2] | FourWay[3]) // if any button pushed
{
lcd.clear();
lcd.setCursor(0,0); // go to line 1
lcd.print(MenuList[indxMenu]); // Show the Menu
lcd.setCursor(0,2); // go to line 3
lcd.print(Line3); // show what Menu item
Serial.println(" ");
Serial.println(MenuList[indxMenu]);
Serial.println(Line3);
}
// now check if select has been pushed again to exit UI
if(digitalRead(SelectPin) == LOW)
{
// reset UI controls
UI_mode = 0;
UI_init = 0;
// copy new settings to timer controls if selected
if(indxSave) // exit and use
{
CoF = tmpCoF;
strcpy(CoFname, tmpCoFname);
NumShooters = tmpNumShooters;
RanDly = tmpRanDly;
StopHits = tmpStopHits;
StopTime = tmpStopTime;
}
if(indxSave == 2) // exit and save
{
save_CoF(CoF);
}
// print to monitor exitting UI
Serial.println(" ");
Serial.println("~ Exitting UI ~");
Serial.print("UI mode is : ");
Serial.println(UI_mode);
Serial.print("Exit option was : ");
Serial.println(Savelist[indxSave]);
Serial.print("CoF is : ");
Serial.println(CoFname);
Serial.print("# Shooters is : ");
Serial.println(NumShooters);
Serial.print("Random/Fixed delay is : ");
Serial.println(RanDly);
Serial.print("Stop hits # is : ");
Serial.println(StopHits);
Serial.print("Stop time is : ");
Serial.println(StopTime/1000.0);
}
}
else
{
// UI is not enabled
if(millis() - LastTime > 10000)
{
LastTime = millis();
// show results of UI interaction on LCD
lcd.clear();
lcd.setCursor(0,0);
lcd.print(CoFname);
lcd.setCursor(0,1);
lcd.print("Stop hits = ");
lcd.print(StopHits);
lcd.setCursor(0,2);
lcd.print("Stop time is : ");
lcd.print(StopTime/1000L);
lcd.setCursor(0,3);
lcd.print("1 or 2 : ");
lcd.print(NumShooters);
lcd.print(" Delay: ");
lcd.print(RanDly);
Serial.print("UI mode is : ");
Serial.println(UI_mode);
}
}
}
// end of loop
void GetButtons()
{
FourWay[0] = 0;
FourWay[1] = 0;
FourWay[2] = 0;
FourWay[3] = 0;
digitalWrite(LEDPin, LOW);
if(analogRead(Horz) < LoThrshld)
{
FourWay[0] = 1;
Serial.println("Left button pushed");
}
if(analogRead(Horz) > HiThrshld)
{
FourWay[1] = 1;
Serial.println("Right button pushed");
}
if(analogRead(Vert) > HiThrshld)
{
FourWay[2] = 1;
Serial.println("Up button pushed");
}
if(analogRead(Vert) < LoThrshld)
{
FourWay[3] = 1;
Serial.println("Down button pushed");
}
if(FourWay[0] | FourWay[1] | FourWay[2] | FourWay[3]) // if button pushed debounce it by waiting
{
delay(DB_delay);
digitalWrite(LEDPin, HIGH); // turn on LED
}
}
void MapProm()
{
// Map out EEPROM for block size and number of CoFs
// Read the first EEPROM location and verify it's one of the magic numbers
if(EEPROM.read(0) == 0xAA)
{
// Read each subsequent byte of EEPROM to find next that has a magic number in it
byte i = 0;
do
{
i++;
} while (EEPROM.read(i) != 0xAA);
EEblocksize = i;
// Using EEblocksize find how many CoFs are stored
i = 0;
do
{
i++;
} while (EEPROM.read(i * EEblocksize) == 0xAA);
numCoF = i;
}
else
{
Serial.print("Error, can't find magic number");
}
}
// function to recall a CoF from EEPROM
void get_CoF(byte indx)
{
int base = indx * EEblocksize;
magicNumber = EEPROM.read(base);
if(magicNumber == 0xAA)
{
for (int i = 0; i < sizeof(CoFname); i++)
{
tmpCoFname[i] = EEPROM.read(base + 1 + i);
}
tmpNumShooters = EEPROM.read(base + sizeof(CoFname) + 2);
tmpRanDly = EEPROM.read(base + sizeof(CoFname) + 3);
tmpStopHits = EEPROM.read(base + sizeof(CoFname) + 4);
unsigned long temp = EEPROM.read(base + sizeof(CoFname) + 5) << 12;
temp |= EEPROM.read(base + sizeof(CoFname) + 6) << 8;
temp |= EEPROM.read(base + sizeof(CoFname) + 7) << 4;
tmpStopTime = temp | EEPROM.read(base + sizeof(CoFname) + 8);
}
else
{
Serial.print("Error, can't get magic number from EEPROM");
}
}
// function to recall a CoF name only from EEPROM
void get_CoFname(byte indx)
{
int base = indx * EEblocksize;
magicNumber = EEPROM.read(base);
if(magicNumber == 0xAA)
{
for (int i = 0; i < sizeof(CoFname); i++)
{
tmpCoFname[i] = EEPROM.read(base + 1 + i);
}
}
else
{
Serial.print("Error, can't get magic number from EEPROM");
}
}
// function to save a CoF to EEPROM
void save_CoF(byte indx)
{
int base = indx * EEblocksize;
EEPROM.write(base + sizeof(CoFname) + 2, tmpNumShooters);
EEPROM.write(base + sizeof(CoFname) + 3, tmpRanDly);
EEPROM.write(base + sizeof(CoFname) + 4, tmpStopHits);
byte temp = byte((tmpStopTime & maskHigh) >> 12);
EEPROM.write(base + sizeof(CoFname) + 5, temp);
temp = byte((tmpStopTime & maskMidU) >> 8);
EEPROM.write(base + sizeof(CoFname) + 6, temp);
temp = byte((tmpStopTime & maskMidL) >> 4);
EEPROM.write(base + sizeof(CoFname) + 7, temp);
temp = byte(tmpStopTime & maskLow);
EEPROM.write(base + sizeof(CoFname) + 8, temp);
}
So load-up the EEPROM with the utility program and then give this a try. You may need to change the low and high thresholds for the slidey pot (connected to A0 and A1 pins) to get good simulated button presses. ADC readings below the low threshold = left or down button press, ADC above the high threshold = up or right button press.
EDIT : I fixed an error in the above code, so copy it again if you copied it before seeing this. Also I forgot to add you’ll need to d/l and install the PString library for it to run. That library “installed” w/o problem for me and can be found (zipped up) here …
http://arduiniana.org/libraries/pstring/