Counting and Timing a shock sensor

Wow that was quick ! And you got the 20x4 snuck in as well. Give me a sec to fix the 2 things I saw wrong.

OK fixed the 2 things I saw weren’t what I thought they should be. The leftover “g” and the wrong display when running (new).

void setup()
{
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  lcd.clear();
  lcd.print("  Shot Timer 1  ");
  lcd.setCursor(0, 1);
  lcd.print("  Initializing  ");
  delay(5000);

  // 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(UpPin, INPUT);
  pinMode(DownPin, INPUT);
  pinMode(TargetAPin, INPUT);
  pinMode(TargetBPin, INPUT);
  digitalWrite(StartPin, HIGH);   
  digitalWrite(UpPin, HIGH);
  digitalWrite(DownPin, HIGH);
  digitalWrite(TargetAPin, HIGH);
  digitalWrite(TargetBPin, 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     ");
}
void FormatData()
{
// routine to format lines of data to be sent to LCD
// presently assume 2 lines of 16 characters
// switch formatting done based on display state
  switch (DisplayState)
  {
    case 1:{
      //this is for single A shooter mode
      // display number of hits so far
      String tmp = "A: # hits = ";
      Line1 = tmp + A_count;
      // now display the time of last hit in secs out to hundreths of secs
      String tmp2 = String(int(((A_Times[A_count-1])+5)/10)); // round msecs into csecs
      int k = tmp2.length();  // k will be index to last char in padded string
      int km1 = k-1;          // km1 will be index to next to last char
      int km2 = k-2;          // km2 will be position of period
      tmp2 = tmp2 + '0';  // pad the end of the truncated string with a zero
      //now move chars to make space to add a period
      tmp2.setCharAt(k, tmp2.charAt(km1));   // move next-2-last to last position in string
      tmp2.setCharAt(km1, tmp2.charAt(km2)); // move char to next-2-last position
      // now insert period
      tmp2.setCharAt(km2, '.');
      // tmp2 now holds rounded time in secs XX.xx format
      Line2 = "Hit time = " + tmp2 ;
      break;}
    case 2:{
      // this is for A vs B mode
      // put that display code here
      break;
    default: 
      // do the default =0 for now
      // 2 string objects for lines 1 and 2
      Line1 = "  Shot Timer v1 ";
      Line2 = "   is running   ";

From this point forward should it be 20x4 code ?

Might as well, that will give us more room to display the data we want.

sspbass:
Might as well, that will give us more room to display the data we want.

OK, just wanted to be sure you were planning to use the 20x4. I understood the one you have in place now is borrowed.

So I think you’ve got a good working baseline. Most of the woring bits are there to be modified into the functions you’ve mentioned a few posts ago. What’s next ? Getting the B channel and A/B display working ? Getting the A “review mode” displays working … which in turn means getting another set of switches working ? Trying to get some user preferences (# hits to win or time to stop or ??) working ?

I think the easiest thing is to get a review of the data going, though that means you’ll need at least 2 more switches and some resistors and I’ll have to think of a simple circuit that makes different analog voltages to be sampled when the timer is stopped and one or the other the switches is pushed.

FWIW : I’ve been pleasantly surprised by how easy this has gone so far ! I don’t know if it’s more pleased or more surprised. :mrgreen:

Mee_n_Mac:

sspbass:
Might as well, that will give us more room to display the data we want.

OK, just wanted to be sure you were planning to use the 20x4. I understood the one you have in place now is borrowed.

So I think you’ve got a good working baseline. Most of the woring bits are there to be modified into the functions you’ve mentioned a few posts ago. What’s next ? Getting the B channel and A/B display working ? Getting the A “review mode” displays working … which in turn means getting another set of switches working ? Trying to get some user preferences (# hits to win or time to stop or ??) working ?

I think the easiest thing is to get a review of the data going, though that means you’ll need at least 2 more switches and some resistors and I’ll have to think of a simple circuit that makes different analog voltages to be sampled when the timer is stopped and one or the other the switches is pushed.

FWIW : I’ve been pleasantly surprised by how easy this has gone so far ! I don’t know if it’s more pleased or more surprised. :mrgreen:

If we stopped sending info to the computer via serial communication would we be able to use pins 0 & 1 for regular push buttons?

What about using a shift register to control the LCD to free up some I/O for regular push buttons?

I guess it all depends on what is easier to do.

sspbass:
If we stopped sending info to the computer via serial communication would we be able to use pins 0 & 1 for regular push buttons?

What about using a shift register to control the LCD to free up some I/O for regular push buttons?

I guess it all depends on what is easier to do.

Getting rid of the serial I/O might work but I don’t know what happens when the sketch wants to download. The Rx in pin is used for that. You could use a different interface to the LCD but what you have now is working so I’m tempted to leave that be. The analog input isn’t that hard. It might look like this … and I’ve made it harder than it needs to be (2 extra resistors, wow!) so that 2 more switches could be added in the future if desired.

So the below plus an analog read and some logic (a window comparator) to declare a switch states is all that’s needed. The switches would be normally open (NO) momentaries, like I think you’re using now for the start/stop.

The pushbuttons are wired to pwm pin 6.

I only used 2 5k1 resistors and 2 pushbuttons.

sspbass:
The pushbuttons are wired to pwm pin 6.

I only used 2 5k1 resistors and 2 pushbuttons.

I assume the “top” and “bottom” Rs are missing. So S1 shorts to Vcc and S2 to gnd ? (Don’t push simultaneouly !!)

Try this and see if the switch states show on the LCD. You’ll need to push and hold them ATM to see them for more than a moment. It’ll also see if I can display on Line 3 of the LCD.

#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal 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 ButtonInPin = A6;   // the pin used for the analog buttons


// initialize the constants
const unsigned long MaxTime = 30000;     // the max time the timer can run for = 30 secs
const unsigned long WaitTime = 2000;     // wait time btw start and timer running = 2 secs 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 = 20;                 // Maximum number if hits allowed
const byte RUN = 1;                      // make code easy to understand

// 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
byte DisplayState = 0;          // variable for controlling what's displayed
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 long A_Times[MaxHits];// array to hold up to 10 hit times for target A
volatile long B_Times[MaxHits];// array to hold up to 10 hit times for target B
long A_splits [MaxHits];
long B_splits [MaxHits];
long AB_splits [MaxHits];
float A_Hit_Factor = 0;
float B_Hit_Factor = 0;
byte S1 = 0;                    // Switch 1 init to zero
byte S2 = 0;                    // Switch 2 init to zero

// setup and intialize two strings for the display each 16 chars long
String Line1 = "  Shot Timer v1 ";
String Line2 = "   is running   ";


void setup()
{
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  lcd.clear();
  lcd.print("  Shot Timer 1  ");
  lcd.setCursor(0, 1);
  lcd.print("  Initializing  ");
  delay(5000);

  // 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(UpPin, INPUT);
  pinMode(DownPin, INPUT);
  pinMode(TargetAPin, INPUT);
  pinMode(TargetBPin, INPUT);
  digitalWrite(StartPin, HIGH);   
  digitalWrite(UpPin, HIGH);
  digitalWrite(DownPin, HIGH);
  digitalWrite(TargetAPin, HIGH);
  digitalWrite(TargetBPin, 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     ");
}


void loop()
{
  if (TimerState == RUN)
  {
    // check to see if this is first pass since start push
    // this is goofy and will change when modes are coded
    if (DisplayState == 0)
    {
      DisplayState = 1; // display will be set depending on mode selected
    }
    // send data to display if there have been any hits
    if (AupDtFlag == 1 || BupDtFlag == 1)
    {
      CalcTimes();
      FormatData();
      LCDdisplay();
    }
    
    // timer is running so check for any stop conditions
    if ((digitalRead(StartPin) == LOW) || ((millis() - StartTime) > MaxTime) || A_count >= MaxHits || B_count >= MaxHits)
    {
      StopTimer();
      tone(BuzzerPin, FreqLo, BuzzTime10);
      // update display just in case last msec hit came in
      if (AupDtFlag == 1 || BupDtFlag == 1)
      {
        CalcTimes();
        FormatData();
        LCDdisplay();
      }
      
      // just for the moment send times to PC for debug
      SendTimes();
      
      // delay enough to debounce stop button
      delay(DB_delay);
    }
  }
  else
  {
  // timer is stopped look for start button or review button pushes
    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);
      
      // clear all the prior runs data, reset the display
      ClearData();
      DisplayState = 0;
      FormatData();
      LCDdisplay();
      
      // delay the Wait Time from start button push
      // this delay is for debounce purposes and should stay
      delay(DB_delay);
      // this delay will change to random later on    
      delay(WaitTime);
       
      // enable the interrupts just in case
      interrupts();
      
      // save the starting time of this run
      StartTime = millis();
      
      // set state of timer to running
      TimerState = RUN;
      
      // now buzz the speaker for 0.5 secs
      tone(BuzzerPin, FreqHi, BuzzTime5);
    }
    // check for up down button pushes change display state as reqd
    S1 = 0; // SW1 is reset
    S2 = 0; // SW2 is reset
    if (analogRead(ButtonInPin) > 767)
    {
      S1 = 1; // SW1 is pushed
    }
    if (analogRead(ButtonInPin) < 341)
    {
      S2 = 1; // SW2 is pushed
    }
    lcd.setCursor(0, 2);
    lcd.print("S1 = " + S1 + " S2 = " + S2);
  }
}

Got this error

OK, I thought print and therefore lcd.print could do the concatenation. Guess not.

Just to see that the pin can be read, print them out to the PC.

replace …

lcd.setCursor(0, 2);

lcd.print("S1 = " + S1 + " S2 = " + S2);

with …

Serial.print(S1);

Serial.print(“\t”);

Serial.println(S2);

And see if the button pushes show up on the PC

If the above works (and perhaps even if it doesn’t) give this a try. It should (ha !) scroll up or down between displays when the timer is stopped, showing 1 to 20 hit times. There’s so much changed I have little faith in it working at first and I know there’s some display ugliness that I don’t know how to correct ATM if it does work, but either way it’ll be another learning experience. I’ve switched over to a 4 line display too. Hopefully the display that used to work when timing still works, even if the review mode displays don’t.

#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal 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 ButtonInPin = A6;   // the pin used for the analog buttons


// initialize the constants
const unsigned long MaxTime = 30000;     // the max time the timer can run for = 30 secs
const unsigned long WaitTime = 2000;     // wait time btw start and timer running = 2 secs 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 = 20;                 // Maximum number if hits allowed
const byte RUN = 1;                      // make code easy to understand

// 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
byte DisplayState = 0;          // variable for controlling what's displayed
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 long A_Times[MaxHits];// array to hold up to MaxHits hit times for target A
volatile long B_Times[MaxHits];// array to hold up to MaxHits hit times for target B
long A_splits[MaxHits];
long B_splits[MaxHits];
long AB_splits[MaxHits];
String A_vert[MaxHits];
float A_Hit_Factor = 0;
float B_Hit_Factor = 0;
byte S1 = 0;                    // Switch 1 init to zero
byte S2 = 0;                    // Switch 2 init to zero

// setup and intialize strings for the display each 20 chars long
String Line1 = "    Shot Timer v1   ";
String Line2 = "      is alive      ";
String Line3 = "                    ";
String Line4 = "                    ";

void setup()
{
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  lcd.clear();
  lcd.print("    Shot Timer 1    ");
  lcd.setCursor(0, 1);
  lcd.print("    Initializing    ");
  delay(5000);

  // 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(UpPin, INPUT);
  pinMode(DownPin, INPUT);
  pinMode(TargetAPin, INPUT);
  pinMode(TargetBPin, INPUT);
  digitalWrite(StartPin, HIGH);   
  digitalWrite(UpPin, HIGH);
  digitalWrite(DownPin, HIGH);
  digitalWrite(TargetAPin, HIGH);
  digitalWrite(TargetBPin, 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       ");
}


void loop()
{
  if (TimerState == RUN)
  {
    // check to see if this is first pass since start push
    // this is goofy and will change when modes are coded
    if (DisplayState == 0)
    {
      DisplayState = 1; // display will be set depending on mode selected
    }
    // send data to display if there have been any hits
    if (AupDtFlag == 1 || BupDtFlag == 1)
    {
      CalcTimes();
      FormatData();
      LCDdisplay();
    }
    
    // timer is running so check for any stop conditions
    if ((digitalRead(StartPin) == LOW) || ((millis() - StartTime) > MaxTime) || A_count >= MaxHits || B_count >= MaxHits)
    {
      StopTimer();
      tone(BuzzerPin, FreqLo, BuzzTime10);
      // update display just in case last msec hit came in
      if (AupDtFlag == 1 || BupDtFlag == 1)
      {
        CalcTimes();
        FormatData();
        LCDdisplay();
      }
      
      // just for the moment send times to PC for debug
      SendTimes();
      
      // delay enough to debounce stop button
      delay(DB_delay);
    }
  }
  else
  {
  // timer is stopped look for start button or review button pushes
    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);
      
      // clear all the prior runs data, reset the display
      ClearData();
      DisplayState = 0;
      FormatData();
      LCDdisplay();
      
      // delay the Wait Time from start button push
      // this delay is for debounce purposes and should stay
      delay(DB_delay);
      // this delay will change to random later on    
      delay(WaitTime);
       
      // enable the interrupts just in case
      interrupts();
      
      // save the starting time of this run
      StartTime = millis();
      
      // set state of timer to running
      TimerState = RUN;
      
      // now buzz the speaker for 0.5 secs
      tone(BuzzerPin, FreqHi, BuzzTime5);
    }
    // check for up down button pushes change display state as reqd
    S1 = 0; // SW1 is reset
    S2 = 0; // SW2 is reset
    if (analogRead(ButtonInPin) > 767)
    {
      S1 = 1; // SW1 is pushed
      int ds = int(A_count/8) + 1;
      if (A_count % 8)
      {
        ds++;
      }
      DisplayState++;
      DisplayState = min(ds,DisplayState);
      FormatData();
      LCDdisplay();
      delay(DB_delay);
    }
    if (analogRead(ButtonInPin) < 341)
    {
      S2 = 1; // SW2 is pushed
      DisplayState--;
      DisplayState = max(2,DisplayState);
      FormatData();
      LCDdisplay();
      delay(DB_delay);
    }    
  }
}


void StopTimer()
{
  //noInterrupts();
  TimerState = !RUN;
  // turn the LED off to show timer is stopped
  digitalWrite(LEDPin, LOW);
}


void ClearData()
{
  A_count = 0; 
  B_count = 0;
  for (int i=0; i < MaxHits ; i++)
  {
    A_Times[i] = 0;
    B_Times[i] = 0;
    A_splits[i] = 0;
    B_splits[i] = 0;
    AB_splits[i] = 0;
    A_vert[i] = "     ";
  }
  A_Hit_Factor = 0;
  B_Hit_Factor = 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 : ");
  int i = 0;
  int k = 0;
  for (i=0; i < A_count ; i++)
  {
    k = i + 1;
    //Serial.print(A_count[k]);
    Serial.print("\t");
    Serial.print(A_Times[i]);
    Serial.print("\t");
    Serial.println(A_splits[i]);
  }
  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++)
  {
    k = i + 1;
    //Serial.print(B_count[k]);
    Serial.print("\t");
    Serial.print(B_Times[i]);
    Serial.print("\t");
    Serial.println(B_splits[i]);
  }
}


void ISR_A()
{
  if(TimerState == RUN)
  {
    // 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 == RUN)
  {
    // 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 CalcTimes()
{
// routine to calculate all data and declare winner
// not all calcs having meaning for uses of timer
  // calculate A splits and cumlative hit factor
  if (A_count > 1)
  {
    for (int i=1; i < A_count ; i++)
    {
      A_splits[i] = A_Times[i] - A_Times[i-1];
    }
  }
  else
  {
    A_splits[0] = A_Times[0];
  }  
  A_Hit_Factor = A_Times[A_count - 1]/A_count;
  // calculate B splits and cumlative hit factor
  if (B_count > 1)
  {
    for (int i=1; i < B_count ; i++)
    {
      B_splits[i] = B_Times[i] - B_Times[i-1];
    }
  }
  else
  {
    B_splits[0] = B_Times[0];
  }  
  B_Hit_Factor = B_Times[B_count - 1]/B_count;
  // Calculate A - B times just in case
  int Min_count = min(A_count, B_count);
  for (int i=0; i < Min_count ; i++)
    {
      AB_splits[i] = A_Times[i] - B_Times[i];
    }
// add more here for A vs B modes

}

void FormatData()
{
// routine to format lines of data to be sent to LCD
// presently assume 2 lines of 16 characters
// switch formatting done based on display state
  switch (DisplayState)
  {
    case 1:{
      //this is for single A shooter mode
      // display number of hits so far
      String tmp = "A: # hits = ";
      Line1 = tmp + A_count;
      // now display the time of last hit in secs out to hundreths of secs
      String tmp2 = String(int(((A_Times[A_count-1])+5)/10)); // round msecs into csecs
      int k = tmp2.length();  // k will be index to last char in padded string
      int km1 = k-1;          // km1 will be index to next to last char
      int km2 = k-2;          // km2 will be position of period
      tmp2 = tmp2 + '0';  // pad the end of the truncated string with a zero
      //now move chars to make space to add a period
      tmp2.setCharAt(k, tmp2.charAt(km1));   // move next-2-last to last position in string
      tmp2.setCharAt(km1, tmp2.charAt(km2)); // move char to next-2-last position
      // now insert period
      tmp2.setCharAt(km2, '.');
      // tmp2 now holds rounded time in secs XX.xx format
      Line2 = "Hit time = " + tmp2 ;
      Line3 = "                    ";
      Line4 = "                    ";
      break;}
    case 2:{
      // this is A review mode
      for (int i=0; i < 8 ; i++)
      {
        A_vert[i] = TimeConvert(A_Times[i]); // convert hit times to XX.xx format first
      }
      Line1 = "A 1:" + A_vert[0] + "s  5:" + A_vert[4] + "s";
      Line2 = "A 2:" + A_vert[1] + "s  6:" + A_vert[5] + "s";
      Line3 = "A 3:" + A_vert[2] + "s  7:" + A_vert[6] + "s";
      Line4 = "A 4:" + A_vert[3] + "s  8:" + A_vert[7] + "s";
      break;}
    case 3:{
      // this is A review mode
      for (int i=8; i < 16 ; i++)
      {
        A_vert[i] = TimeConvert(A_Times[i]); // convert hit times to XX.xx format first
      }
      Line1 = "A 9:" + A_vert[8] + "s 13:" + A_vert[12] + "s";
      Line2 = "A 10:" + A_vert[9] + "s14:" + A_vert[13] + "s";
      Line3 = "A 11:" + A_vert[10] + "s15:" + A_vert[14] + "s";
      Line4 = "A 12:" + A_vert[11] + "s16:" + A_vert[15] + "s";
      break;}
    case 4:{
      // this is A review mode
      for (int i=16; i < 20 ; i++)
      {
        A_vert[i] = TimeConvert(A_Times[i]); // convert hit times to XX.xx format first
      }
      Line1 = "A 17:" + A_vert[16] + "s19:" + A_vert[18] + "s";
      Line2 = "A 18:" + A_vert[17] + "s20:" + A_vert[19] + "s";
      Line3 = "                    ";
      Line4 = "                    ";
      break;}
    default: 
      // do the default =0 for now
      // 2 string objects for lines 1 and 2
      Line1 = "    Shot Timer v1   ";
      Line2 = "     is running     ";
      Line3 = "    Countdown in    ";
      Line4 = "      progress      ";
  }
}

String TimeConvert(long time)
{
// takes the time as argument and returns the time for that hit as a XX.xx string
  String tmp2 = String(int((time + 5)/10)); // round msecs into csecs
  int k = tmp2.length();  // k will be index to last char in padded string
  int km1 = k-1;          // km1 will be index to next to last char
  int km2 = k-2;          // km2 will be position of period
  tmp2 = tmp2 + '0';  // pad the end of the truncated string with a zero
  //now move chars to make space to add a period
  tmp2.setCharAt(k, tmp2.charAt(km1));   // move next-2-last to last position in string
  tmp2.setCharAt(km1, tmp2.charAt(km2)); // move char to next-2-last position
  // now insert period
  tmp2.setCharAt(km2, '.');
  // tmp2 now holds rounded time in secs XX.xx format
  return tmp2;
}


void LCDdisplay()
{
  // reset display update flags
  AupDtFlag = 0;
  BupDtFlag = 0;
  // sends 4 lines to LCD using library functions
  lcd.clear();
  lcd.print(Line1);
  lcd.setCursor(0, 1);
  lcd.print(Line2);
  lcd.setCursor(0, 2);
  lcd.print(Line3);
  lcd.setCursor(0, 3);
  lcd.print(Line4);
}

I think i see at least 1 problem in the code in the above post. I don’t think I can declare an array of String objects as I did. I also know that even if it works, when we expand the scrolling/displays to include B hits and up the count from 20 each to 50 each, the method used to fill the displays will become a big fat memory hog. So I got rid of that way and did something a bit less elegant but more memory friendly while eliminating the questionable declaration. So give the above a try just for giggles but if it doesn’t compile, don’t spend any time figuring it out (do post the error message though). Do try the following even if the above does work, as I think it’s closer to the way-to-go.

#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal 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 ButtonInPin = A6;   // the pin used for the analog buttons


// initialize the constants
const unsigned long MaxTime = 30000;     // the max time the timer can run for = 30 secs
const unsigned long WaitTime = 2000;     // wait time btw start and timer running = 2 secs 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 = 20;                 // Maximum number if hits allowed
const byte RUN = 1;                      // make code easy to understand

// 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
byte DisplayState = 0;          // variable for controlling what's displayed
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 long A_Times[MaxHits];// array to hold up to MaxHits hit times for target A
volatile long B_Times[MaxHits];// array to hold up to MaxHits hit times for target B
long A_splits[MaxHits];
long B_splits[MaxHits];
long AB_splits[MaxHits];
float A_Hit_Factor = 0;
float B_Hit_Factor = 0;
byte S1 = 0;                    // Switch 1 init to zero
byte S2 = 0;                    // Switch 2 init to zero

// setup and intialize strings for the display each 20 chars long
String Line1 = "    Shot Timer v1   ";
String Line2 = "      is alive      ";
String Line3 = "                    ";
String Line4 = "                    ";

void setup()
{
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  lcd.clear();
  lcd.print("    Shot Timer 1    ");
  lcd.setCursor(0, 1);
  lcd.print("    Initializing    ");
  delay(5000);

  // 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(UpPin, INPUT);
  pinMode(DownPin, INPUT);
  pinMode(TargetAPin, INPUT);
  pinMode(TargetBPin, INPUT);
  digitalWrite(StartPin, HIGH);   
  digitalWrite(UpPin, HIGH);
  digitalWrite(DownPin, HIGH);
  digitalWrite(TargetAPin, HIGH);
  digitalWrite(TargetBPin, 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       ");
}


void loop()
{
  if (TimerState == RUN)
  {
    // check to see if this is first pass since start push
    // this is goofy and will change when modes are coded
    if (DisplayState == 0)
    {
      DisplayState = 1; // display will be set depending on mode selected
    }
    // send data to display if there have been any hits
    if (AupDtFlag == 1 || BupDtFlag == 1)
    {
      CalcTimes();
      FormatData();
      LCDdisplay();
    }
    
    // timer is running so check for any stop conditions
    if ((digitalRead(StartPin) == LOW) || ((millis() - StartTime) > MaxTime) || A_count >= MaxHits || B_count >= MaxHits)
    {
      StopTimer();
      tone(BuzzerPin, FreqLo, BuzzTime10);
      // update display just in case last msec hit came in
      if (AupDtFlag == 1 || BupDtFlag == 1)
      {
        CalcTimes();
        FormatData();
        LCDdisplay();
      }
      
      // just for the moment send times to PC for debug
      SendTimes();
      
      // delay enough to debounce stop button
      delay(DB_delay);
    }
  }
  else
  {
  // timer is stopped look for start button or review button pushes
    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);
      
      // clear all the prior runs data, reset the display
      ClearData();
      DisplayState = 0;
      FormatData();
      LCDdisplay();
      
      // delay the Wait Time from start button push
      // this delay is for debounce purposes and should stay
      delay(DB_delay);
      // this delay will change to random later on    
      delay(WaitTime);
       
      // enable the interrupts just in case
      interrupts();
      
      // save the starting time of this run
      StartTime = millis();
      
      // set state of timer to running
      TimerState = RUN;
      
      // now buzz the speaker for 0.5 secs
      tone(BuzzerPin, FreqHi, BuzzTime5);
    }
    // check for up down button pushes change display state as reqd
    S1 = 0; // SW1 is reset
    S2 = 0; // SW2 is reset
    if (analogRead(ButtonInPin) > 767)
    {
      S1 = 1; // SW1 is pushed
      int ds = int(A_count/8) + 1;
      if (A_count % 8)
      {
        ds++;
      }
      DisplayState++;
      DisplayState = min(ds,DisplayState);
      FormatData();
      LCDdisplay();
      delay(DB_delay);
    }
    if (analogRead(ButtonInPin) < 341)
    {
      S2 = 1; // SW2 is pushed
      DisplayState--;
      DisplayState = max(2,DisplayState);
      FormatData();
      LCDdisplay();
      delay(DB_delay);
    }    
  }
}


void StopTimer()
{
  //noInterrupts();
  TimerState = !RUN;
  // turn the LED off to show timer is stopped
  digitalWrite(LEDPin, LOW);
}


void ClearData()
{
  A_count = 0; 
  B_count = 0;
  for (int i=0; i < MaxHits ; i++)
  {
    A_Times[i] = 0;
    B_Times[i] = 0;
    A_splits[i] = 0;
    B_splits[i] = 0;
    AB_splits[i] = 0;
  }
  A_Hit_Factor = 0;
  B_Hit_Factor = 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 : ");
  int i = 0;
  int k = 0;
  for (i=0; i < A_count ; i++)
  {
    k = i + 1;
    //Serial.print(A_count[k]);
    Serial.print("\t");
    Serial.print(A_Times[i]);
    Serial.print("\t");
    Serial.println(A_splits[i]);
  }
  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++)
  {
    k = i + 1;
    //Serial.print(B_count[k]);
    Serial.print("\t");
    Serial.print(B_Times[i]);
    Serial.print("\t");
    Serial.println(B_splits[i]);
  }
}


void ISR_A()
{
  if(TimerState == RUN)
  {
    // 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 == RUN)
  {
    // 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 CalcTimes()
{
// routine to calculate all data and declare winner
// not all calcs having meaning for uses of timer
  // calculate A splits and cumlative hit factor
  if (A_count > 1)
  {
    for (int i=1; i < A_count ; i++)
    {
      A_splits[i] = A_Times[i] - A_Times[i-1];
    }
  }
  else
  {
    A_splits[0] = A_Times[0];
  }  
  A_Hit_Factor = A_Times[A_count - 1]/A_count;
  // calculate B splits and cumlative hit factor
  if (B_count > 1)
  {
    for (int i=1; i < B_count ; i++)
    {
      B_splits[i] = B_Times[i] - B_Times[i-1];
    }
  }
  else
  {
    B_splits[0] = B_Times[0];
  }  
  B_Hit_Factor = B_Times[B_count - 1]/B_count;
  // Calculate A - B times just in case
  int Min_count = min(A_count, B_count);
  for (int i=0; i < Min_count ; i++)
    {
      AB_splits[i] = A_Times[i] - B_Times[i];
    }
// add more here for A vs B modes

}

void FormatData()
{
// routine to format lines of data to be sent to LCD
// presently assume 4 lines of 20 characters
// switch formatting done based on display state
  switch (DisplayState)
  {
    case 1:{
      //this is for single A shooter mode
      // display number of hits so far
      String tmp = "A: # hits = ";
      Line1 = tmp + A_count;
      // now display the time of last hit in secs out to hundreths of secs
      String tmp2 = TimeConvert(A_Times[A_count-1]); // convert hit time to XX.xx format
      Line2 = "Hit time = " + tmp2 + "secs";
      Line3 = "                    ";
      Line4 = "                    ";
      break;}
    case 2:{
      // this is A review mode hits 1-8
      String tmp = TimeConvert(A_Times[0]); // convert hit time to XX.xx format
      String tmp2 = TimeConvert(A_Times[4]); // convert hit time to XX.xx format
      Line1 = "A 1:" + tmp + "s  5:" + tmp2 + "s";
      String tmp = TimeConvert(A_Times[1]); // convert hit time to XX.xx format
      String tmp2 = TimeConvert(A_Times[5]); // convert hit time to XX.xx format
      Line2 = "A 2:" + tmp + "s  6:" + tmp2 + "s";
      String tmp = TimeConvert(A_Times[2]); // convert hit time to XX.xx format
      String tmp2 = TimeConvert(A_Times[6]); // convert hit time to XX.xx format
      Line3 = "A 3:" + tmp + "s  7:" + tmp2 + "s";
      String tmp = TimeConvert(A_Times[3]); // convert hit time to XX.xx format
      String tmp2 = TimeConvert(A_Times[7]); // convert hit time to XX.xx format
      Line4 = "A 4:" + tmp + "s  8:" + tmp2 + "s";
      break;}
    case 3:{
      // this is A review mode hits 9-16
      String tmp = TimeConvert(A_Times[8]); // convert hit time to XX.xx format
      String tmp2 = TimeConvert(A_Times[12]); // convert hit time to XX.xx format
      Line1 = "A 9:" + tmp + "s 13:" + tmp2 + "s";
      String tmp = TimeConvert(A_Times[9]); // convert hit time to XX.xx format
      String tmp2 = TimeConvert(A_Times[13]); // convert hit time to XX.xx format
      Line2 = "A 10:" + tmp + "s14:" + tmp2 + "s";
      String tmp = TimeConvert(A_Times[10]); // convert hit time to XX.xx format
      String tmp2 = TimeConvert(A_Times[14]); // convert hit time to XX.xx format
      Line3 = "A 11:" + tmp + "s15:" + tmp2 + "s";
      String tmp = TimeConvert(A_Times[11]); // convert hit time to XX.xx format
      String tmp2 = TimeConvert(A_Times[15]); // convert hit time to XX.xx format
      Line4 = "A 12:" + tmp + "s16:" + tmp2 + "s";
      break;}
    case 4:{
      // this is A review mode hits 17-20
      String tmp = TimeConvert(A_Times[16]); // convert hit time to XX.xx format
      String tmp2 = TimeConvert(A_Times[18]); // convert hit time to XX.xx format
      Line1 = "A 17:" + tmp + "s19:" + tmp2 + "s";
      String tmp = TimeConvert(A_Times[17]); // convert hit time to XX.xx format
      String tmp2 = TimeConvert(A_Times[19]); // convert hit time to XX.xx format
      Line2 = "A 18:" + tmp + "s20:" + tmp2 + "s";
      Line3 = "                    ";
      Line4 = "                    ";
      break;}
    default: 
      // do the default = 0
      // 4 string objects
      Line1 = "    Shot Timer v1   ";
      Line2 = "     is running     ";
      Line3 = " Countdown to start ";
      Line4 = "    in progress     ";
  }
}

String TimeConvert(long time)
{
// takes the time as argument and returns the time for that hit as a XX.xx string
  String tmp3 = String(int((time + 5)/10)); // round msecs into csecs
  int k = tmp3.length();  // k will be index to last char in padded string
  int km1 = k-1;          // km1 will be index to next to last char
  int km2 = k-2;          // km2 will be position of period
  tmp3 = tmp3 + '0';  // pad the end of the truncated string with a zero
  //now move chars to make space to add a period
  tmp3.setCharAt(k, tmp3.charAt(km1));   // move next-2-last to last position in string
  tmp3.setCharAt(km1, tmp3.charAt(km2)); // move char to next-2-last position
  // now insert period
  tmp3.setCharAt(km2, '.');
  // tmp3 now holds rounded time in secs XX.xx format
  return tmp3;
}


void LCDdisplay()
{
  // reset display update flags
  AupDtFlag = 0;
  BupDtFlag = 0;
  // sends 4 lines to LCD using library functions
  lcd.clear();
  lcd.print(Line1);
  lcd.setCursor(0, 1);
  lcd.print(Line2);
  lcd.setCursor(0, 2);
  lcd.print(Line3);
  lcd.setCursor(0, 3);
  lcd.print(Line4);
}

Here is the latest code at work.

http://www.youtube.com/watch?v=A1aNjPbB … e=youtu.be

The start button needs to be held in order for the sketch to catch that it is low with the new method.

And doesn’t the analog buttons need to use two different resistors in order for the voltage to be different when one is shorted?

sspbass:
Here is the latest code at work.

http://www.youtube.com/watch?v=A1aNjPbB … e=youtu.be

The start button needs to be held in order for the sketch to catch that it is low with the new method.

And doesn’t the analog buttons need to use two different resistors in order for the voltage to be different when one is shorted?

Looks like a number of things are AFU. One thing that’s curious is that the display shows a mismash of the default display which is supposed to be :

Line1 = " Shot Timer v1 ";

Line2 = " is running ";

Line3 = " Countdown to start ";

Line4 = " in progress ";

I’m not sure how that get’s FU’ed. That should be easy to find and fix.

Obviously the function that calcs the XX.xx String format from the stored hit time is wrong but I sorta expected that.

Not sure what to say about the start button. That should have worked as before. That you have to hold it is a big clue that should make the problem easy to figure out.

How did you wire the other buttons and resistor ? We should put a debug, write to the PC, the analog read on pin A6 to see if it’s even seeing the voltage divider, let alone the button action. If you have a volt meter you could measure the voltage at that pin for the 3 cases : no button pushed and then either buttong pushed. The intent was that w/o any button pushed you should see Vcc/2 at the pin or about 2.5V or an analog reading of 511-512. Then pushing a button shorted out one resistor, raising or lowering the voltage. I’m not sure what you implemented with the 2 resistors. Can you post someting of a schematic or wiring diagram ?

Here’s the code that should get each line of the 4 to display. It seems like it should work but from what I can see the “change line” command isn’t working. The result is that the 3’rd line overwrites the 2’nd and then the 4’th overwrites that again.

void LCDdisplay()
{
  // reset display update flags
  AupDtFlag = 0;
  BupDtFlag = 0;
  // sends 4 lines to LCD using library functions
  lcd.clear();
  lcd.print(Line1);
  lcd.setCursor(0, 1);
  lcd.print(Line2);
  lcd.setCursor(0, 2);
  lcd.print(Line3);
  lcd.setCursor(0, 3);
  lcd.print(Line4);
}

So the thing to figure out is how to command a line change with the 20x4 display. Or maye the wiring needs to change from the 16x2 ?? I’m not sure where to start. DK seems to be familiar with these displays, perhaps he can chime in while I’m looking at the start button oddness.

Can you describe what you have to do and what doesn’t work re: the start button ? Obviously the timer does get started and I hear the start buzzer. Can I assume the LED comes on as it’s supposed to ? That the time delay works like it used to ? The problem is that you have to hold the button for a loooong time to have it be recognized as having been pushed ? Once that happens does the LCD and serial monitor show a switch from their pre-start conditions ? That is did you see the LCD show the “initializing” and then “ready” displays upon bootup ? That those displays remained until the looooong push ?

Does pushing it again make the timer stop ?

Here’s a “debug” version of the last main loop(). I’ve commented out the new analog read for the new buttons. See if this makes the start/stop button work as it should. All other problems remain un-fixed.

void loop()
{
  if (TimerState == RUN)
  {
    // check to see if this is first pass since start push
    // this is goofy and will change when modes are coded
    if (DisplayState == 0)
    {
      DisplayState = 1; // display will be set depending on mode selected
    }
    // send data to display if there have been any hits
    if (AupDtFlag == 1 || BupDtFlag == 1)
    {
      CalcTimes();
      FormatData();
      LCDdisplay();
    }
    
    // timer is running so check for any stop conditions
    if ((digitalRead(StartPin) == LOW) || ((millis() - StartTime) > MaxTime) || A_count >= MaxHits || B_count >= MaxHits)
    {
      StopTimer();
      tone(BuzzerPin, FreqLo, BuzzTime10);
      // update display just in case last msec hit came in
      if (AupDtFlag == 1 || BupDtFlag == 1)
      {
        CalcTimes();
        FormatData();
        LCDdisplay();
      }
      
      // just for the moment send times to PC for debug
      SendTimes();
      
      // delay enough to debounce stop button
      delay(DB_delay);
    }
  }
  else
  {
  // timer is stopped look for start button or review button pushes
    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);
      
      // clear all the prior runs data, reset the display
      ClearData();
      DisplayState = 0;
      FormatData();
      LCDdisplay();
      
      // delay the Wait Time from start button push
      // this delay is for debounce purposes and should stay
      delay(DB_delay);
      // this delay will change to random later on    
      delay(WaitTime);
       
      // enable the interrupts just in case
      interrupts();
      
      // save the starting time of this run
      StartTime = millis();
      
      // set state of timer to running
      TimerState = RUN;
      
      // now buzz the speaker for 0.5 secs
      tone(BuzzerPin, FreqHi, BuzzTime5);
    }
    // check for up down button pushes change display state as reqd
    //S1 = 0; // SW1 is reset
    //S2 = 0; // SW2 is reset
    //if (analogRead(ButtonInPin) > 767)
    //{
      //S1 = 1; // SW1 is pushed
      //int ds = int(A_count/8) + 1;
      //if (A_count % 8)
      //{
        //ds++;
      //}
      //DisplayState++;
      //DisplayState = min(ds,DisplayState);
      //FormatData();
      //LCDdisplay();
      //delay(DB_delay);
    //}
    //if (analogRead(ButtonInPin) < 341)
    //{
      //S2 = 1; // SW2 is pushed
      //DisplayState--;
      //DisplayState = max(2,DisplayState);
      //FormatData();
      //LCDdisplay();
      //delay(DB_delay);
    //}    
  }
}

There’s obviously something wrong with the following function (something probably obvious to a real Arduino person) or how it’s being called/used.

String TimeConvert(long time)
{
// takes the time as argument and returns the time for that hit as a XX.xx string
  String tmp3 = String(int((time + 5)/10)); // round msecs into csecs
  int k = tmp3.length();  // k will be index to last char in padded string
  int km1 = k-1;          // km1 will be index to next to last char
  int km2 = k-2;          // km2 will be position of period
  tmp3 = tmp3 + '0';  // pad the end of the truncated string with a zero
  //now move chars to make space to add a period
  tmp3.setCharAt(k, tmp3.charAt(km1));   // move next-2-last to last position in string
  tmp3.setCharAt(km1, tmp3.charAt(km2)); // move char to next-2-last position
  // now insert period
  tmp3.setCharAt(km2, '.');
  // tmp3 now holds rounded time in secs XX.xx format
  return tmp3;
}

And here’s 2 snippets of it’s usage.

String tmp2 = TimeConvert(A_Times[A_count-1]); // convert hit time to XX.xx format
String tmp = TimeConvert(A_Times[0]); // convert hit time to XX.xx format

I note from the LCD that the 1’st usage seems not to work at all (or the other data sent to the display is AFU) and the second usage does seem to return a string but it’s the same string every time, even with the input argument (supposedly) changed.

sspbass:
The pushbuttons are wired to pwm pin 6.

I only used 2 5k1 resistors and 2 pushbuttons.

Damn ! I should have caught this sooner. What pin, exactly, is the above ? It’s not the same digital pin 6 that’s being used for the LCD is it ? I just realized the Uno doesn’t appear to have an analog input pin 6. They go A0 - A5. So what’s wired to what for the LCD and the new analog push buttons ?

http://arduino.cc/en/uploads/Main/Ardui … _450px.jpg