Counting and Timing a shock sensor

Actually you are not looking at anything terribly difficult. You can easily extract what you need, especially because you are setting up a rigid structure for what you want to store. You can jump to the points you need, grab the info and dump to screen. I don’t think you really need to read in all values after reset, just read at need.

As for accessing separate characters you probably just want a recursive function. It will call itself with the first character in the array then call itself again by adding one to the index value until you hit the null value. I can write up an example but you can probably fine what you need online.

I think if you give the ability to save a certain number of user defined CoF setups this would be handy. Allowing them to name them isn’t too bad either.

Dan

EDIT: After talking with a colleague he mentioned just doing a for loop using the sizeof() on the array and accessing each character that way. May be easier to understand than recursion.

Here’s my 1’st try at the EEPROM utility program. It should write the CoF data to EEPROM and then read it back. Printouts of both the original CoF data and any data read back are sent to the serial monitor for you to check that it all worked correctly. Later on, once this is working, we’ll make that self-checking. But if this works, portions of it can be melded into the UI code and that would be nice to see !

#include <OLEDFourBit.h>

// initialize the library with the numbers of the interface pins
OLEDFourBit lcd(12, 11, 5, 4, 9, 8);


// declare some constants
const byte wblocksize = 20;
const unsigned long maskHigh = 0xF000;
const unsigned long maskMidU = 0x0F00;
const unsigned long maskMidL = 0x00F0;
const unsigned long maskLow = 0x000F;

//declare some variables
byte magicNumber = 0xAA;
char CoFname[11];
unsigned long StopTime = 0;
byte NumShooters = 0;
byte RanDly = 0;
byte StopHits = 0;
byte EEblocksize = 0;
byte numCoF = 8;

//here's all the CoF parameters put into various arrays
char* CoFlist[] = {"Last Used ","Standard 1","QuickDraw2","    21    "," Custom 1 ",
" Custom 2 "," Custom 3 ","  A vs B  "}
byte aNumShooters[] = {1, 1, 2, 1, 1, 2, 1, 2}
byte aRanDly[] = {1, 1, 1, 1, 1, 1, 1, 1}
byte aStopHits[] = {6, 24, 1, 20, 20, 20, 12, 20}
unsigned long aStopTime[] = {10001, 20001, 10001, 1501, 20001, 20001, 30001, 24001}


void setup()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("  EEPROM  Utility   ");
  lcd.setCursor(0, 1);
  lcd.print("   Program v0.1     ");
  delay(3000);

  // opens serial port, sets data rate to 9600 bps
  Serial.begin(9600);
  
  lcd.setCursor(0, 1);
  lcd.print(" -writing to EEPROM ");
  delay(1000);
  
  //Write all the CoF parameters to EEPROM
  for (byte i = 0; i < numCoF; i++)
  {
    CoFname[] = CoFlist[i];
    NumShooters = aNumShooters[i];
    RanDly = aRanDly[i];
    StopHits = aStopHits[i];
    StopTime = aStopTime[i];
    Serial.print("CoF Name #");
    Serial.print(i+1);
    Serial.print(" is : ");
    Serial.println(CoFname);
    Serial.println("Write values are :");
    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/1000L);
    save_CoF(i);
  }

  lcd.setCursor(0, 1);
  lcd.print("-reading block size ");
  delay(1000);
  
  // now check what was written to EEPROM
  
  // 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) == 0x55 || 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) != 0x55 && EEPROM.read(i) != 0xAA);
    EEblocksize = i;
    // Using EEblocksize find how many CoFs are stored
    i = 0;
    do
    {
      i++;
    } while (EEPROM.read(i * EEblocksize) == 0x55 || EEPROM.read(i * EEblocksize) == 0xAA);
    numCoF = i;
  }
  else
  {
    Serial.print("Error, can't find magic number");
  }
  
    lcd.setCursor(0, 1);
    lcd.print(" -getting CoF data  ");
    delay(1000);

    //Now retrieve and print each CoF from EEPROM
  for (int i = 0; i < numCof; i++)
  {
    get_CoF(i);
    // Send this data to the serial monitor
    Serial.println("Values read from EEPROM are :");
    Serial.print("CoF Name #");
    Serial.print(i+1);
    Serial.print(" 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/1000L);
  }
  
void loop
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("      All Done      ");
  lcd.setCursor(0, 1);
  lcd.print(" -verify printouts  ");
  delay(5000);
}


// function to recall a CoF from EEPROM
void get_CoF(byte indx)
{
  int base = indx * EEblocksize;
  magicNumber = EEPROM.read(base);
  if (magicNumber == 0xAA || magicNumber == 0x55)
  {
    for (int i = 0; i < sizeof(CoFname); i++)
    {
      CoFname[i] = EEPROM.read(base + 1 + i);
    }
    NumShooters = EEPROM.read(base + sizeof(CoFname) + 2);
    RanDly = EEPROM.read(base + sizeof(CoFname) + 3);
    StopHits = EEPROM.read(base + sizeof(CoFname) + 4);
    unsigned long temp = EEPROM.read(base + sizeof(CoFname) + 5) << 24;
    temp &= EEPROM.read(base + sizeof(CoFname) + 6) << 16;
    temp &= EEPROM.read(base + sizeof(CoFname) + 7) << 8;
    StopTime = temp & EEPROM.read(base + sizeof(CoFname) + 8);
  }
  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 * wblocksize;
  EEPROM.write(base, magicNumber);
  for (int i = 0; i < sizeof(CoFname); i++)
  {
    EEPROM.write(base + 1 + i, CoFname[i]);
  }
  EEPROM.write(base + sizeof(CoFname) + 2, NumShooters);
  EEPROM.write(base + sizeof(CoFname) + 3, RanDly);
  EEPROM.write(base + sizeof(CoFname) + 4, StopHits);
  byte temp = byte((StopTime & maskHigh) >> 24);
  EEPROM.write(base + sizeof(CoFname) + 5, temp);
  temp = byte((StopTime & maskMidU) >> 16);
  EEPROM.write(base + sizeof(CoFname) + 6, temp);
  temp = byte((wStopTime & maskMidL) >> 8);
  EEPROM.write(base + sizeof(CoFname) + 7, temp);
  temp = byte(StopTime & maskLow);
  EEPROM.write(base + sizeof(wCoFname) + 8, temp);
}

ERROR

I’m afraid the Forum attachment bug has reduced your picture to a red X.

EDIT : Still no pic, just a red X. Can you try removing and re-attaching the pic ? Or is it just at my end ?? Other attachments seem to display just fine and I know the forum has had issues in the past.

All I see for the .PNG attachment above is:

… which I’ve seen in the past when the Forum hosed up storing of the attachment.

Here is another attempt at the errors.

I did some reading but I’m in WAY over my head.

I’m going to try to take advantage of some programming courses that my work should pay for.

I did do some “research” this weekend in the form of my first 3 gun match.

It was very spur of the moment but I had a blast.

http://www.youtube.com/watch?v=GYxGq5ZK … ure=relmfu

The dummy I hit to start the round was a a joke between a few of the guys running it.

I knew the place outlined above was going to be a problem, just didn’t know what to do about it. If I’ve absorbed dk’s advice, the following should fix that problem and, with the include for EEPROM, the other issue to. I think the other complaints are a result of these 2 errors.

#include <OLEDFourBit.h>
#include <EEPROM.h>

// initialize the library with the numbers of the interface pins
OLEDFourBit lcd(12, 11, 5, 4, 9, 8);


// declare some constants
const byte wblocksize = 20;
const unsigned long maskHigh = 0xF000;
const unsigned long maskMidU = 0x0F00;
const unsigned long maskMidL = 0x00F0;
const unsigned long maskLow = 0x000F;

//declare some variables
byte magicNumber = 0xAA;
char CoFname[11];
unsigned long StopTime = 0;
byte NumShooters = 0;
byte RanDly = 0;
byte StopHits = 0;
byte EEblocksize = 0;
byte numCoF = 8;

//here's all the CoF parameters put into various arrays
char* CoFlist[] = {"Last Used ","Standard 1","QuickDraw2","    21    "," Custom 1 ",
" Custom 2 "," Custom 3 ","  A vs B  "}
byte aNumShooters[] = {1, 1, 2, 1, 1, 2, 1, 2}
byte aRanDly[] = {1, 1, 1, 1, 1, 1, 1, 1}
byte aStopHits[] = {6, 24, 1, 20, 20, 20, 12, 20}
unsigned long aStopTime[] = {10001, 20001, 10001, 1501, 20001, 20001, 30001, 24001}


void setup()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("  EEPROM  Utility   ");
  lcd.setCursor(0, 1);
  lcd.print("   Program v0.1     ");
  delay(3000);

  // opens serial port, sets data rate to 9600 bps
  Serial.begin(9600);
  
  lcd.setCursor(0, 1);
  lcd.print(" -writing to EEPROM ");
  delay(1000);
  
  //Write all the CoF parameters to EEPROM
  for (byte i = 0; i < numCoF; i++)
  {
    for (byte ii = 0; ii < 11; ii++);
    {
      CoFname[ii] = CoFlist[i][ii];
    }
    NumShooters = aNumShooters[i];
    RanDly = aRanDly[i];
    StopHits = aStopHits[i];
    StopTime = aStopTime[i];
    Serial.print("CoF Name #");
    Serial.print(i+1);
    Serial.print(" is : ");
    Serial.println(CoFname);
    Serial.println("Write values are :");
    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/1000L);
    save_CoF(i);
  }

  lcd.setCursor(0, 1);
  lcd.print("-reading block size ");
  delay(1000);
  
  // now check what was written to EEPROM
  
  // 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) == 0x55 || 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) != 0x55 && EEPROM.read(i) != 0xAA);
    EEblocksize = i;
    // Using EEblocksize find how many CoFs are stored
    i = 0;
    do
    {
      i++;
    } while (EEPROM.read(i * EEblocksize) == 0x55 || EEPROM.read(i * EEblocksize) == 0xAA);
    numCoF = i;
  }
  else
  {
    Serial.print("Error, can't find magic number");
  }
  
    lcd.setCursor(0, 1);
    lcd.print(" -getting CoF data  ");
    delay(1000);

    //Now retrieve and print each CoF from EEPROM
  for (int i = 0; i < numCof; i++)
  {
    get_CoF(i);
    // Send this data to the serial monitor
    Serial.println("Values read from EEPROM are :");
    Serial.print("CoF Name #");
    Serial.print(i+1);
    Serial.print(" 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/1000L);
  }
  
void loop
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("      All Done      ");
  lcd.setCursor(0, 1);
  lcd.print(" -verify printouts  ");
  delay(5000);
}


// function to recall a CoF from EEPROM
void get_CoF(byte indx)
{
  int base = indx * EEblocksize;
  magicNumber = EEPROM.read(base);
  if (magicNumber == 0xAA || magicNumber == 0x55)
  {
    for (int i = 0; i < sizeof(CoFname); i++)
    {
      CoFname[i] = EEPROM.read(base + 1 + i);
    }
    NumShooters = EEPROM.read(base + sizeof(CoFname) + 2);
    RanDly = EEPROM.read(base + sizeof(CoFname) + 3);
    StopHits = EEPROM.read(base + sizeof(CoFname) + 4);
    unsigned long temp = EEPROM.read(base + sizeof(CoFname) + 5) << 24;
    temp &= EEPROM.read(base + sizeof(CoFname) + 6) << 16;
    temp &= EEPROM.read(base + sizeof(CoFname) + 7) << 8;
    StopTime = temp & EEPROM.read(base + sizeof(CoFname) + 8);
  }
  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 * wblocksize;
  EEPROM.write(base, magicNumber);
  for (int i = 0; i < sizeof(CoFname); i++)
  {
    EEPROM.write(base + 1 + i, CoFname[i]);
  }
  EEPROM.write(base + sizeof(CoFname) + 2, NumShooters);
  EEPROM.write(base + sizeof(CoFname) + 3, RanDly);
  EEPROM.write(base + sizeof(CoFname) + 4, StopHits);
  byte temp = byte((StopTime & maskHigh) >> 24);
  EEPROM.write(base + sizeof(CoFname) + 5, temp);
  temp = byte((StopTime & maskMidU) >> 16);
  EEPROM.write(base + sizeof(CoFname) + 6, temp);
  temp = byte((wStopTime & maskMidL) >> 8);
  EEPROM.write(base + sizeof(CoFname) + 7, temp);
  temp = byte(StopTime & maskLow);
  EEPROM.write(base + sizeof(wCoFname) + 8, temp);
}

sspbass:
I did do some “research” this weekend in the form of my first 3 gun match.

It was very spur of the moment but I had a blast.

The dummy I hit to start the round was a a joke between a few of the guys running it.

Quite the “research project” ! :mrgreen: Good work on that star. I’ve never shot one of those before, they look to be a bear.

Things are getting crazy around here and only picking up!

Here’s the latest round of compile errors.

Did you ever get that fancy new laptop of yours in?

sspbass:
Things are getting crazy around here and only picking up!

Here’s the latest round of compile errors.

Did you ever get that fancy new laptop of yours in?

Hmmm, I thought that would work. Let me do it via brute force then.

I actually got the new lappy tonight. Typing on it right now. I’m going to make sure everything is working for 24+ hours and then install Arduino 1.01 on it and be able to compile all this stuff prior to posting. In fact I’ll see what I can get setup to mimic the project at my end … since I’ll need a goodly portion of it anyway.

Hmmm, I’m not sure what to think. The error seems to be with I or j (in the below) not being in scope, that is not being valid any more. And that troubles me because loops within loops are supposed to work … ???

  for (byte i = 0; i < numCoF; i++)
  {
    for (byte j = 0; j < 11; j++);
    {
      CoFname[j] = CoFlist[i][j];
    }
  //more code follows that uses index i w/o complaint
  }

The following stupid brute force code compiles (with some warnings). See if if compiles for you and runs and actually writes to and reads from EEPROM successfully.

#include <OLEDFourBit.h>
#include <EEPROM.h>

// initialize the library with the numbers of the interface pins
OLEDFourBit lcd(12, 11, 5, 4, 9, 8);


// declare some constants
const byte wblocksize = 20;
const unsigned long maskHigh = 0xF000;
const unsigned long maskMidU = 0x0F00;
const unsigned long maskMidL = 0x00F0;
const unsigned long maskLow = 0x000F;

//declare some variables
byte magicNumber = 0xAA;
char CoFname[11];
unsigned long StopTime = 0;
byte NumShooters = 0;
byte RanDly = 0;
byte StopHits = 0;
byte EEblocksize = 0;
byte numCoF = 8;

//here's all the CoF parameters put into various arrays
char* CoFlist[] = {"Last Used ","Standard 1","QuickDraw2","    21    "," Custom 1 ",
" Custom 2 "," Custom 3 ","  A vs B  "};
byte aNumShooters[] = {1, 1, 2, 1, 1, 2, 1, 2};
byte aRanDly[] = {1, 1, 1, 1, 1, 1, 1, 1};
byte aStopHits[] = {6, 24, 1, 20, 20, 20, 12, 20};
unsigned long aStopTime[] = {10001, 20001, 10001, 1501, 20001, 20001, 30001, 24001};


void setup()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("  EEPROM  Utility   ");
  lcd.setCursor(0, 1);
  lcd.print("   Program v0.1     ");
  delay(3000);

  // opens serial port, sets data rate to 9600 bps
  Serial.begin(9600);
  
  lcd.setCursor(0, 1);
  lcd.print(" -writing to EEPROM ");
  delay(1000);
  
  //Write all the CoF parameters to EEPROM
  for (byte i = 0; i < numCoF; i++)
  {
    CoFname[0] = CoFlist[i][0];
    CoFname[1] = CoFlist[i][1];
    CoFname[2] = CoFlist[i][2];
    CoFname[3] = CoFlist[i][3];
    CoFname[4] = CoFlist[i][4];
    CoFname[5] = CoFlist[i][5];
    CoFname[6] = CoFlist[i][6];
    CoFname[7] = CoFlist[i][7];
    CoFname[8] = CoFlist[i][8];
    CoFname[9] = CoFlist[i][9];
    CoFname[10] = CoFlist[i][10];
    
    NumShooters = aNumShooters[i];
    RanDly = aRanDly[i];
    StopHits = aStopHits[i];
    StopTime = aStopTime[i];
    Serial.print("CoF Name #");
    Serial.print(i+1);
    Serial.print(" is : ");
    Serial.println(CoFname);
    Serial.println("Write values are :");
    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/1000L);
    save_CoF(i);
  }

  lcd.setCursor(0, 1);
  lcd.print("-reading block size ");
  delay(1000);
  
  // now check what was written to EEPROM
  
  // 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) == 0x55 || 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) != 0x55 && EEPROM.read(i) != 0xAA);
    EEblocksize = i;
    // Using EEblocksize find how many CoFs are stored
    i = 0;
    do
    {
      i++;
    } while (EEPROM.read(i * EEblocksize) == 0x55 || EEPROM.read(i * EEblocksize) == 0xAA);
    numCoF = i;
  }
  else
  {
    Serial.print("Error, can't find magic number");
  }
  
    lcd.setCursor(0, 1);
    lcd.print(" -getting CoF data  ");
    delay(1000);

    //Now retrieve and print each CoF from EEPROM
  for (int i = 0; i < numCoF; i++)
  {
    get_CoF(i);
    // Send this data to the serial monitor
    Serial.println("Values read from EEPROM are :");
    Serial.print("CoF Name #");
    Serial.print(i+1);
    Serial.print(" 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/1000L);
  }
}
void loop()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("      All Done      ");
  lcd.setCursor(0, 1);
  lcd.print(" -verify printouts  ");
  delay(5000);
}


// function to recall a CoF from EEPROM
void get_CoF(byte indx)
{
  int base = indx * EEblocksize;
  magicNumber = EEPROM.read(base);
  if (magicNumber == 0xAA || magicNumber == 0x55)
  {
    for (int i = 0; i < sizeof(CoFname); i++)
    {
      CoFname[i] = EEPROM.read(base + 1 + i);
    }
    NumShooters = EEPROM.read(base + sizeof(CoFname) + 2);
    RanDly = EEPROM.read(base + sizeof(CoFname) + 3);
    StopHits = EEPROM.read(base + sizeof(CoFname) + 4);
    unsigned long temp = EEPROM.read(base + sizeof(CoFname) + 5) << 24;
    temp &= EEPROM.read(base + sizeof(CoFname) + 6) << 16;
    temp &= EEPROM.read(base + sizeof(CoFname) + 7) << 8;
    StopTime = temp & EEPROM.read(base + sizeof(CoFname) + 8);
  }
  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 * wblocksize;
  EEPROM.write(base, magicNumber);
  for (int i = 0; i < sizeof(CoFname); i++)
  {
    EEPROM.write(base + 1 + i, CoFname[i]);
  }
  EEPROM.write(base + sizeof(CoFname) + 2, NumShooters);
  EEPROM.write(base + sizeof(CoFname) + 3, RanDly);
  EEPROM.write(base + sizeof(CoFname) + 4, StopHits);
  byte temp = byte((StopTime & maskHigh) >> 24);
  EEPROM.write(base + sizeof(CoFname) + 5, temp);
  temp = byte((StopTime & maskMidU) >> 16);
  EEPROM.write(base + sizeof(CoFname) + 6, temp);
  temp = byte((StopTime & maskMidL) >> 8);
  EEPROM.write(base + sizeof(CoFname) + 7, temp);
  temp = byte(StopTime & maskLow);
  EEPROM.write(base + sizeof(CoFname) + 8, temp);
}

I keep on getting that message to upgrade from 1.0 to 1.1 but I was worried about the bottom falling out so I haven’t done it.

Once you install it and try code on it I’ll do the same.

sspbass:
I keep on getting that message to upgrade from 1.0 to 1.1 but I was worried about the bottom falling out so I haven’t done it. Once you install it and try code on it I’ll do the same.

Actually that last bit was compliled using 1.01 or 1.1, whichever is the latest. I’ve still got to put all the folders ‘n’ files in the right place and copy the OLED library** but I did want to fix that error and have some assurance it would run. Perhaps dk can chime in as to why my inner loop was so despised by the compiler. I wouldn’t have thunk it nessecary to make the index a global variable and yet that would seem to be the case.

** as a result of this I had to comment out all the LCD stuff to get it to compile. Then I undid my commenting out to post here. So given my horrendous typing and proofreading ablities, if there’s a problem, it’ll no doubt have something to do with the LCD stuff. Which is not to say I have have 100% confidence that it’ll actually write to and read from EEPROM just as desired … but that it’s worth a shot. The good thing is that even w/o the LCD and slidey joystick thingee, I should be able to find some time this WE to get this part (utility program) actually working and perhaps make some progress on the UI too. Switches I’ve got lying about and I think I have an old analog joystick from the old old old PC that could be wired into the Arduino. Just depends on how much I want this to cut into my drinking time. :mrgreen:

Haha, don’t work too hard. It is the weekend after all!

I got the (EEPROM utility) code to upload and it does write to EEPROM. Some of the info that’s read back from EEPROM is good, other stuff is … not so good. Not sure how much time I’ll have to debug this ATM but I’m looking at it now and perhaps it’ll turn out to be something simple. [/suppressed_laugh]

EDIT : As it turns out they were pretty simple errors and right now I have the utility EEPROM code loading and reading EEPROM with all the CoF names and parameters. So next I’ll see if I can get that working with an altered version of the UI I put up a while ago and then you can see if that works (as I don’t have the LCD but will try to debug as much as possible w/o one).

Thx to dk for “pointing” me in the proper direction. Saved and retrieved an array of char arrays, no problem !

Got a version of the UI that uses EEPROM to compile. I need to change it to print to the serial monitor in lieu of the LCD (which I don’t have) and figure out a good way to test it with my mini test rig. When you get a chance can you post the timer code that you have that’s working. I think i have it but the next thing to do (after the UI works) is to combine it with the UI. The UI presently uses ~8k of program space,leaving 24k for the timer code. My guess is that’s enough.

Heres the latest version I have.

#include <OLEDFourBit.h>

// initialize the library with the numbers of the interface pins
// with the OLED library this also seems to do the init and begin calls
OLEDFourBit lcd(12, 11, 5, 4, 9, 8);

// set pin numbers
const int StartPin = 7;                  // the number of the Start pushbutton pin
const int TargetAPin = 2;                // the number of the A targets input pin
const int TargetBPin = 3;                // the number of the B targets input pin
const int BuzzerPin = 10;                // the number of the buzzer output pin
const int LEDPin = 13;                   // the number of the LED output pin
const int ScrollPin = 6;                 // the number of the scroll button input pin

// initialize the constants
const unsigned long MaxTime = 60001;     // the max time the timer can run for = 60 secs
const unsigned long WaitTime = 1000;     // wait time btw start and timer running = 1 sec plus debounce
const unsigned long DB_delay = 1000;     // set a debounce wait time of 1000 msecs
const unsigned long BuzzTime5 = 500;     // set the on time for the buzzer, 500 msecs
const unsigned long BuzzTime2 = 200;     // set the on time for the buzzer, 200 msecs
const unsigned long BuzzTime10 = 1000;   // set the on time for the buzzer, 1000 msecs
const unsigned int FreqHi = 2000;        // High frequency of buzzer tone
const unsigned int FreqLo = 1000;        // Low frequency of buzzer tone
const byte MaxHits = 24;                 // Maximum number of hits allowed per shooter

// initialize global variables
volatile byte TimerState = 0;            // variable for state of timer, running or not running
volatile byte AupDtFlag = 0;             // variable indication an A hit has occurred
volatile byte BupDtFlag = 0;             // variable indication a B hit has occurred
volatile int secs = 0;                   // whole seconds of time for display
volatile int frac = 0;                   // fractional part of time for display
unsigned long StartTime = 0;             // variable to hold the start time
unsigned long BuzzTime = 500;            // variable to hold the buzzer on time
unsigned int Freq = 2000;                // variable for high or low buzzer tone
volatile byte A_count = 0;               // variable to hold the number of A hits
volatile byte B_count = 0;               // variable to hold the number of B hits
volatile unsigned long A_Times[MaxHits]; // array to hold up to MaxHits hit times for target A
volatile unsigned long B_Times[MaxHits]; // array to hold up to MaxHits hit times for target B
byte DisplayIndex = 0;                   // variable for controlling what's displayed
byte diMax = 99;                         // Display index maximum
byte LastUpdt = 0;                       // Flag to allow last update of LCD after timer stopped
boolean Stop = false;                    // Flag to indicate hit condition to stop timer has been met
byte StopHits = MaxHits;                 // Number if hits allowed before stopping
unsigned long StopTime = MaxTime;        // Time that the timer will stop at 

byte CoF = 0;                            // initialize the mode to be standard
//byte CoF = 1;                          // initialize the mode to be quick draw
//byte CoF = 2;                          // initialize the mode to be 21
//byte NumShooters = 1;                    // initialize the number of shooters to 1
byte NumShooters = 2;                  // initialize the number of shooters to 2
byte RanDly = 0;                         // random delay disabled
//byte RanDly = 1;                       // random delay enabled


void setup()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("    Shot Timer 1    ");
  lcd.setCursor(0, 1);
  lcd.print("    Initializing    ");
  delay(3000);

  // initialize output pins
  pinMode(BuzzerPin, OUTPUT);
  pinMode(LEDPin, OUTPUT);
  digitalWrite(BuzzerPin, LOW);
  digitalWrite(LEDPin, LOW);
   
  // initialize the input pins with internal pullups
  pinMode(StartPin, INPUT);
  pinMode(TargetAPin, INPUT);
  pinMode(TargetBPin, INPUT);
  digitalWrite(StartPin, HIGH);   
  digitalWrite(TargetAPin, HIGH);
  digitalWrite(TargetBPin, HIGH);

  // for now use pin 6 as button input
  pinMode(ScrollPin, INPUT);
  digitalWrite(ScrollPin, HIGH);

  // opens serial port, sets data rate to 9600 bps
  Serial.begin(9600);

  // setup ext pins as interrupts
  //attachInterrupt(0, ISR_A, FALLING);
  //attachInterrupt(1, ISR_B, FALLING);

  lcd.setCursor(0, 1);
  lcd.print("      Ready       ");

  ClearData();
}


void loop()
{
  if (TimerState) // is timer running
  {
    // timer is running
    
    // send data to display if there have been any hits
    if (AupDtFlag == 1 || BupDtFlag == 1)
    {
      UpdateLCD();
    }
    
    // timer is running so now check for any stop conditions
    if (NumShooters == 1)
    {
      if (A_count >= StopHits)
      {
        Stop = true;
      }
    }
    else
    {
      if (A_count >= StopHits && B_count >= StopHits)
      {
        Stop = true;
      }
    }
    if ((digitalRead(StartPin) == LOW) || ((millis() - StartTime) >= StopTime) || Stop)
    {
      // stop the timer
      StopTimer();
      LastUpdt = 1;
      tone(BuzzerPin, FreqLo, BuzzTime10);
      
      // update the LCD running display one last time
      UpdateLCD();
      
      // just for the moment send times to PC for debug
      SendTimes();
      
      // delay enough to debounce stop button
      delay(DB_delay);
      
      // Setup the review-stopped state display based on number shooters and hits
      if(NumShooters == 1)
      {
        diMax = byte(A_count/8) - 1;   // DI goes 0 to number of displays - 1
        if (A_count % 8)                 // diMax indicates last screen of hits
        {
          diMax ++;                      // limit lines per number of hits
        }
        DisplayIndex = diMax;            // display will show list of hit times
      }
      else
      {
        diMax = byte(max(A_count,B_count)/4) - 1; // find how many whole screens
        if (max(A_count,B_count) % 4)
        {
          diMax++ ;              // add another screen if partial exists
        }
        DisplayIndex = diMax;    // display will show list of hit times
      }
    }
  }
  else
  {
  // timer is stopped look for start button or review button pushes

    // check for scroll button pushes, change display state as reqd
    if (digitalRead(ScrollPin) == LOW)
    {
      DisplayIndex++;             // increment DisplayIndex upon push
      if (DisplayIndex > diMax)
      {
        DisplayIndex = 0;         // wrap around of scrolling action
      }
      // update display
      UpdateLCD();
      delay(DB_delay);
    }

    // check to see if start button has been pushed
    if (digitalRead(StartPin) == LOW)
    {
      // start button pushed
      // Do the following debug code only to get system running
      // This will send message to PC to show button was pushed
      Serial.println("Timer is running");
      
      // turn on the LED to show timer is running
      digitalWrite(LEDPin, HIGH);
      
      // show the timer has been started
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("    Shot Timer v1   ");
      lcd.setCursor(0, 1);
      lcd.print("     is running     ");
      lcd.setCursor(0, 2);
      lcd.print("      Shooter:      ");
      lcd.setCursor(0, 3);
      lcd.print("    --STANDBY--     ");
      
      // this will change when config mode is added ?
      switch (CoF)
      {
        case 1:
          //this is for quick draw mode
          StopTime = 10001;
          StopHits = 1;
          break;
        case 2:
          //this is for 21 mode
          StopTime = 1501;
          StopHits = MaxHits;
          break;
        default: 
          // the default = standard timer mode
          StopTime = MaxTime;
          StopHits = MaxHits;
      }
      
      // delay the Wait Time from start button push
      randomSeed(millis());
      // delay is min delay plus random if enabled
      delay(WaitTime);               // 1 sec min delay
      if(RanDly)
      {
        delay(random(2000, 4000));   // total delay btw 3 and 5 secs
      }
      
      // turn on interrupts as needed for 1 or 2 shooters
      attachInterrupt(0, ISR_A, FALLING);
      if (NumShooters > 1)
      {
        attachInterrupt(1, ISR_B, FALLING);
      }
      
      // clear all the prior runs data
      ClearData();      
      
      // save the starting time of this run
      StartTime = millis();
      
      // set state of timer to running
      TimerState = 1;
      
      // now buzz the speaker for 0.5 secs
      tone(BuzzerPin, FreqHi, BuzzTime5);
    }
  }
}


void StopTimer()
{
  // turn off interrupts
  detachInterrupt(0);
  detachInterrupt(1);
  TimerState = 0;
  Stop = false;
  // turn the LED off to show timer is stopped
  digitalWrite(LEDPin, LOW);
}


void ClearData()
{
  A_count = 0; 
  B_count = 0;
  for (byte i = 0; i < MaxHits; i++)
  {
    A_Times[i] = 0;
    B_Times[i] = 0;
  }
}


void SendTimes()
// temp routine to send data to serial monitor
{
  Serial.println("Timer is stopped");
  Serial.println("Here are the times for Shooter A");
  Serial.print("Number of hits : ");
  Serial.print("\t");
  Serial.println(A_count);
  Serial.println("A Hit and split times are : ");
  byte i = 0;
  unsigned long Split = 0;
  for (i = 0; i < A_count; i++)
  {
    Serial.print(i+1);
    Serial.print("\t");
    Serial.print(A_Times[i]);
    Serial.print("\t");
    if (i)
    {
      Split = A_Times[i] - A_Times[i-1];
      Serial.print(Split);
    }
    Serial.println("\t");
  }
  Serial.println("Here are the times for Shooter B");
  Serial.print("Number of hits : ");
  Serial.print("\t");
  Serial.println(B_count);
  Serial.println("B Hit and split times are : ");
  for (i = 0; i < B_count; i++)
  {
    Serial.print(i+1);
    Serial.print("\t");
    Serial.print(B_Times[i]);
    Serial.print("\t");
    if (i)
    {
      Split = B_Times[i] - B_Times[i-1];
      Serial.print(Split);
    }
    Serial.println("\t");
  }
}


void ISR_A()
{
  if(TimerState)
  {
    if(A_count < StopHits)
    {
      if((millis() - StartTime) < StopTime)
      {
        // store the hit time 
        A_Times[A_count] = millis() - StartTime;
        // increment the hit count and array index
        A_count++;
        // set the Hit flag so other stuff will update
        AupDtFlag = 1;
      }
    }
  }
}


void ISR_B()
{
  if(TimerState)
  {
    if(B_count < StopHits)
    {
      if((millis() - StartTime) < StopTime)
      {
        // store the hit time 
        B_Times[B_count] = millis() - StartTime;
        // increment the hit count and array index
        B_count++;
        // set the Hit flag so other stuff will update
        BupDtFlag = 1;
      }
    }
  }
}


void UpdateLCD()
{
AupDtFlag = 0;
BupDtFlag = 0;
// routine to format lines of data to be sent to LCD
// presently assume 4 lines of 20 characters
// formatting based number of shooters and timer state
  if(TimerState || LastUpdt)
  {
    // timer is running or this is last pass through before review
    // display number of hits so far
    LastUpdt = 0;
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(" A: # hits = ");
    if(A_count < 10)
    {
      lcd.print(' ');
    } 
    lcd.print(A_count);
    // now display the time of last hit
    lcd.setCursor(0, 1);
    lcd.print("A Hit time = ");
    if(A_count)
    {
      TimeConvert(A_Times[A_count-1]); // convert hit time to XX.xx format
    }
    lcd.setCursor(0, 2);
    // Chose 1 or 2 shooter portion of display
    if(NumShooters == 1)
    {
      // this is for single A shooter running display
      // display the split time btw last hit and prior hit
      unsigned long Split = 0;
      if (A_count > 1)
      {
        Split = A_Times[A_count-1] - A_Times[A_count-2];
      }
      lcd.print("Split time = ");
      TimeConvert(Split); // convert split time
      lcd.setCursor(0, 3);
      // compute A hit factor
      //float HF = A_count/A_Times[A_count - 1];
      //lcd.print("Hit factor = ");
      //char buf[6];
      //PString(buf, sizeof(buf), HF);  // convert FP to char
      //lcd.print(buf);
    }      
    else
    {
      // this is for 2 shooter running display
      lcd.print(" B: # hits = ");
      if(B_count < 10)
      {
        lcd.print(' ');
      } 
      lcd.print(B_count);
      lcd.setCursor(0, 3);
      lcd.print("B Hit time = ");
      if(B_count)
      {
        TimeConvert(B_Times[B_count-1]); // Now for B times
      }
    }    
  }
  else
  {
  // timer is stopped
    if(NumShooters == 1)
    {
      // this is single shooter review display
      lcd.clear();
      lcd.setCursor(0, 0);
      byte k = 0;                    // k will hold LCD line number
      byte j = DisplayIndex << 3;    // index for first hit time displayed
      byte jj = (A_count % 8);       // jj holds number hits on last display
      if (jj == 0)
      {
        jj = 8;                      // acount for 8 hits on last screeen
      }
      if (DisplayIndex == diMax)     // diMax indicates last screen of hits
      {
        jj = j + min(jj,4);          // display 1 line per hit up to 4 lines
      }
      else
      {
        jj = j + 4;                  // there are enough hits to fill 4 lines
      }
      for (byte i = j; i < jj; i++)
      {
        k = (i % 4);
        lcd.setCursor(0,k);
        lcd.print('A');
        if(i<9)
        {
         lcd.print(' ');             // add a space for single digit numbers
        }
        lcd.print(i+1);              // send hit # to LCD
        lcd.print(": ");
        TimeConvert(A_Times[i]);     // convert hit time to XX.xx format
        if(A_Times[i+4])             // if there's a non-zero time
        {
          lcd.print(' ');            // print a space
          if((i+4)<9)
          {
           lcd.print(' ');           // add a space for single digit numbers
          }          
          lcd.print(i+5);            // send hit # to LCD
          lcd.print(": ");
          TimeConvert(A_Times[i+4]); // convert hit time to XX.xx format
        }
      }
    }      
    else
    {
      // this is 2 shooter review display
      lcd.clear();
      lcd.setCursor(0, 0);
      byte k = 0;                     // k will hold LCD line number
      byte j = DisplayIndex << 2;     // index for first hit time displayed
      byte jj = max(A_count,B_count); // init jj to max hit count
      jj = jj % 4;                    // jj holds number hits on last display
      if (jj == 0)
      {
        jj = 4;                       // acount for 4 hits on last screeen
      }
      if (DisplayIndex == diMax)      // diMax indicates last screen of hits
      {
        jj = j + min(jj,4);           // display 1 line per hit up to 4 lines
      }
      else
      {
        jj = j + 4;                   // there are enough hits to fill 4 lines
      }
      for (byte i = j; i < jj; i++)
      {
        k = (i % 4);
        lcd.setCursor(0,k);
        if(i<9)
        {
          lcd.print(' ');               // for hits 1-9 put in a leading space
        }
        lcd.print(i+1);                 // print hit number
        lcd.print(" A: ");
        TimeConvert(A_Times[i]);        // convert hit time to XX.xx format
        if(B_Times[i]);
        {
          lcd.print(" B: ");
          TimeConvert(B_Times[i]);      // convert hit time to XX.xx format
        }
      }  
    }
  }
}


void TimeConvert(unsigned long input)
{
// takes the msecs as argument and sets the time for that hit as a XX.xxs string

  if (input != 0)         // Make sure there's a value...
  {
    secs = int((input + 5)/1000L);         // round msecs into whole secs
    frac = int(((input + 5) % 1000L)/10L); // find fractional rounded secs

    if (secs < 10)
    {
      lcd.print(' ');               // for sub 10 sec times add leading space
    }
    lcd.print(secs);                // now add whole secs 
    lcd.print('.');                 // now add period

    if (frac < 10)
    {
      lcd.print('0');               // If frac < 10 then pad with a zero
    }
    lcd.print(frac);                // now add fractional secs
  }
  else
  {
    lcd.print("     ");         // If the input variable is zero set time to 6 blank spaces
  }
}

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/

sspbass:
Heres the latest version I have.

OK, now I’ll have to d/l the OLED library so I can compile the “real” versions of this code.

Hmmm, I seem to have lost a post I wrote. In short I installed the OLED (modified) library and, after some tribulations, got the Timer code to compile. Got the above UI w/LCD to compile as well (so it should work for you). Obviously I can’t vouch for how well the LCD will display it’s “stuff” but the serial monitor should give a good idea of what’s happening in the UI when a button is pushed. See if the LCD agrees with it’s output.

I note the UI code is 8k and the Timer code is 10k. The mash-up of the two should take less than the sum of those numbers and so easily fit in the 32k available … with room to grow. Let’s hope we aren’t close to the 2k RAM limit (again).