Reset function running from a 2 pin button

Hi everyone,

I've been working on a timing gate for a CO2 racer unit with some students at my school. Please excuse the massive amounts of commented out code, I need to clean it up a bit, but for the most part it works as intended. Basically I have an arduino in a box which has some led lights and an LCD screen. The launcher has an LED and a LDR which send a signal to capture the start time when the launcher fires and the cars begin, then the gate itself has 2 LDRs which each look for a drop of at least 50 units signalling the car passing the gate. The Arduino sets the finish time as a variable and displays it to the LCD screen and the LED lights flash based on which track (1 or 2) finished first.

Last but not least, there is a 2 pin button which I have connected to ground and to pin 11 to be used as a reset button. I have declared a variable for the reset state an am trying to run a reset function when the button is pressed. It kind of worked originally, except that the button was very sensitive to touch (and even putting your hand near it, not actually touching it) and when the button was pressed the arduino would rest 3 or 4 times before running the code again.

I surmised that this was due to the ambient electricity in the circuit and that a pull up resistor might solve the problem. After following the InputPullupSerial tutorial I implemented the inbuilt pull up resistor and switch the button states to check for in order to reset (ie checking for resetButton == LOW instead of HIGH) but alas, now the button does nothing at all.

This is a fairly minor thing I know, but it bugs me that the code doesn't work exactly as I want it to. Is there something I'm missing in my code?

I've tried to be pedantic with my code, as I teach software design and I want to be able use the code as an example with my students to explain what is happening with each line of code. The check for resetButton is right at the end of the code and the declaration of the rest function is just before the main loop.

Edit - Removed commented code as it was too long to attach

// Include the LCD library code:
#include <LiquidCrystal.h>

// Initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
LiquidCrystal lcd(1, 2, 3, 4, 5, 6);

// Declare unsigned long variables to track possibly large numbers
unsigned long time1 = 0; // Time for Track 1
unsigned long time2 = 0; // Time for Track 2
unsigned long startTime = 0; // Start Time

// Set variables for analog pins to read data from LDRs
int LDR_PinS = A0; // Launcher LDR
int LDR_Pin1 = A1; // Track 1 LDR
int LDR_Pin2 = A2; // Track 2 LDR

// Variables to hold ambient light
int ambient1 = 0;
int ambient2 = 0;

// Set variables for the start and finish states as well as Start Time
int start = 0; // Value used to tell whether the launcehr has fired or not
int finish = 0; // Boolean value that tells whether or not a car has crossed the line

// Variable to store LDR readings from the Launcher, Track 1 and Track 2
// as well as to store the finish times for both tracks
int LDRReadingS = 0; // Variable to store the LDR reading from the Launcher
int LDRReading1 = 0; // Variable to store the LDR reading from Track 1
int LDRReading2 = 0; // Variable to store the LDR reading from Track 2
int finishTime1 = 0; // Variable to store final finish time for Track 1
int finishTime2 = 0; // Variable to store final finish time for Track 2

// Reset button state
int rButton = 1;

// Variables to store who wins the race for LEDs
int t1Win = 0;
int t2Win = 0;

// Variables to store whether the track has ended
int t1Finish = 0;
int t2Finish = 0;

// LDR Testing
int LDRT = 0; // 0 = Skip testing LDR values

void setup() {

  // Set up the LCD's number of columns and rows
  lcd.begin(16, 2);
  lcd.clear();

  // Setup IO for digital inputs and outputs
  pinMode(12, OUTPUT); // Gate LEDs
  pinMode(11, INPUT_PULLUP); // Reset button
  pinMode(7, OUTPUT); // Track1 LED1
  pinMode(8, OUTPUT); // Track1 LED2
  pinMode(9, OUTPUT); // Track2 LED1
  pinMode(10, OUTPUT); // Track2 LED2

  // Turn on Gate LEDs
  digitalWrite(12, HIGH);

  // LED Startup sequence...
  digitalWrite(7, HIGH);
  delay(250);
  digitalWrite(8, HIGH);
  delay(250);
  digitalWrite(9, HIGH);
  delay(250);
  digitalWrite(10, HIGH);
  delay(250);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  delay(250);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
  delay(250);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);

  // Print "Track 1: ..." to TOP line of LCD
  lcd.setCursor(0, 0);
  lcd.print("Track 1:"); 

  // Print "Track 2: ..." to BOTTOM line of LCD
  lcd.setCursor(0, 1);
  lcd.print("Track 2:"); 

// Take ambient light levels
  ambient1 = analogRead(LDR_Pin1);
  ambient2 = analogRead(LDR_Pin2);

}

void(* resetFunc) (void) = 0; //Declare reset function

void loop() {
  // Capture the LDR reading from the launcher and both tracks
  LDRReadingS = analogRead(LDR_PinS);
  LDRReading1 = analogRead(LDR_Pin1);
  LDRReading2 = analogRead(LDR_Pin2);

  // Launcher Logic - If the value for LDR rises above 150
  // AND the races hasn't started yet, then capture
  // the start time and set the Start boolean to 1
  // The race has begun!   
  if (LDRReadingS >= 150 && start == 0) {
    startTime = (millis()/1000.000);
    start = 1;
    lcd.setCursor(9, 0);
    lcd.print("...");
    lcd.setCursor(9, 1);
    lcd.print("...");
  }
    
  // LDR Testing - If LDRT is set to 1, test LDR values
  if (LDRT == 1) {

  // Print LDR values to LCD
    lcd.setCursor(0, 0);
    lcd.print("LDR1:"); 
    lcd.setCursor(6, 0);
    lcd.print(LDRReading1);
    lcd.setCursor(10, 0);
    lcd.print("Start:");
    lcd.setCursor(0, 1);
    lcd.print("LDR2:"); 
    lcd.setCursor(6, 1);
    lcd.print(LDRReading2);
    lcd.setCursor(11, 1);
    lcd.print(LDRReadingS);
  }

// Track 1 finish code - IF ambient1 drops 50 points below the initial value AND the race has started
// AND Track 1 has not crossed the line, record the finish time in finishTime1 and display it to the LCD
  if (LDRReading1 <= (ambient1-50) && start == 1 && t1Finish == 0) {
    float finishTime1 = ((millis()/1000.000) - startTime);
    t1Finish = 1;
    lcd.setCursor(9, 0);
    lcd.print(finishTime1, 3);

    // If Track 2 hasn't finished yet then Track 1 has won the race
    if (t2Finish == 0){
      t1Win = 1;
    }
  }

// Track 2 finish code - IF ambient2 drops 50 points below the initial value AND the race has started
// AND Track 2 has not crossed the line, record the finish time in finishTime2 and display it to the LCD
  if (LDRReading2 <= (ambient2-50) && start == 1 && t2Finish == 0) {
    float finishTime2 = ((millis()/1000.000) - startTime);
    t2Finish = 1;
    lcd.setCursor(9, 1);
    lcd.print(finishTime2, 3);
  
    // If Track 1 hasn't finished yet then Track 2 has won the race
    if (t1Finish == 0){
      t2Win = 1; 
    }
  }

  if (t1Win == 1){
    // Turn OFF Track 2 LEDs
    digitalWrite(9, LOW); 
    digitalWrite(10, LOW);

    // Track 2 LED Win Sequence
    digitalWrite(7, HIGH);
    digitalWrite(8, LOW);
    delay(50);
    digitalWrite(7, LOW);
    digitalWrite(8, HIGH);
    delay(50);
    }

    if (t2Win == 1){

    // Turn OFF Track 1 LEDs
    digitalWrite(7, LOW); 
    digitalWrite(8, LOW);

    // Track 2 LED Win Sequence
    digitalWrite(9, HIGH);
    digitalWrite(10, LOW);
    delay(50);
    digitalWrite(9, LOW);
    digitalWrite(10, HIGH);
    delay(50);
    }

// Reset button
rButton = digitalRead(11); // Read INPUT from pin11 to the button state
if (rButton == LOW) {
   resetFunc();  //call reset
  }

}

I assume the button is a momentary button since it results in a reset...

Any mechanical switch will bounce when it is pressed and when it released. You may want to explore debouncing the input in software. Search for debounce and you will see a lot of discussion on it.

Also, Instead of just looking for LOW you are really interested in a HIGH to LOW transition otherwise if the input stays LOW for a significant amount of time you could have multiple resets. In your case, when a reset happens, the button state should be initialized using a digitalRead and then if it is still LOW it will not trigger a reset until it is released and pressed again.

Ah right so I could just check for the button release. I'll look into the debounce, thanks!

Good idea. Only reset on a LOW to HIGH transition. Try that first. Since you are resetting that might solve it (it may be done bouncing by the time the reset sequence is finished).