Adding Start, Stop, Resume, and Reset Button

I am working on a stopwatch project and I have a working stopwatch but i want to add a Start/Stop button (Press it and it starts, press it again and it pauses it, and press it again it resumes it.) on D8 and a Reset button (Back to 0) on D9.

Here is the code i have so far:

// Made by Matthew Hinkleman aka gohawks413

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int mil=00;
int sec=00;
int min=00;
int hr=00;

void setup() {
lcd.begin(16,2);
lcd.setCursor(3,1);
lcd.print("Stopwatch");
delay(1000);
lcd.setCursor(2,0);
lcd.print("STARTS IN 5");
delay(1000);
lcd.clear();
lcd.setCursor(2,0);
lcd.print("STARTS IN 4");
delay(1000);
lcd.clear();
lcd.setCursor(2,0);
lcd.print("STARTS IN 3");
delay(1000);
lcd.clear();
lcd.setCursor(2,0);
lcd.print("STARTS IN 2");
delay(1000);
lcd.clear();
lcd.setCursor(2,0);
lcd.print("STARTS IN 1");
delay(1000);
lcd.clear();
lcd.setCursor(0,0);
}

void loop() {

lcd.setCursor(3,2);
lcd.print("Stopwatch");
lcd.setCursor(3,0);
lcd.print(hr);
lcd.setCursor(5,0);
lcd.print(":");
lcd.print(min);
lcd.setCursor(8,0);
lcd.print(":");
lcd.print(sec);
lcd.print(".");
lcd.print(mil);
mil=mil+1;
delay(100);

if(mil == 10){
  mil=0;
  sec=sec+1;
}
if(sec == 60){
  sec=00;
  min=min+1; 
}else;
if(min == 60){
  min=0;
  hr=hr+1;
}else;

lcd.clear();
}

Here is the wiring i have:

Here is a tested demo that uses the state change detection with a button switch to cycle through a series of choices.

// by C Goulding aka groundFungus

const byte  buttonPin = 12;    // the pin to which the pushbutton is attached
const byte ledPin = 13;       // the pin to which the LED is attached

byte mode = 0;

void setup()
{
   // initialize the button pin as a input with internal pullup enabled
   pinMode(buttonPin, INPUT_PULLUP);
   // initialize the LED as an output:
   pinMode(ledPin, OUTPUT);
   // initialize serial communication:
   Serial.begin(115200);
   Serial.println("Select mode with push button");
}

void loop()
{
   static bool lastButtonState = HIGH;
   static unsigned long timer = 0;
   unsigned long interval = 50;  // check switch 20 times per second
   if (millis() - timer >= interval)
   {
      timer = millis();
      // read the pushbutton input pin:
      bool buttonState = digitalRead(buttonPin);
      // compare the new buttonState to its previous state
      if (buttonState != lastButtonState)
      {
         if (buttonState == LOW)
         {
            // if the current state is LOW then the button
            // went from off to on:
            
            mode++;
            if(mode > 2)
            {
              mode = 0;
            }
         }
      }
      // save the current state as the last state,
      //for next time through the loop
      lastButtonState = buttonState;
   }

   if (mode == 0)
   {
      function1();
   }
   else if(mode == 1)
   {
      function2();
   }
   else if(mode == 2)
   {
      function3();
   }
}



void function1()
{
   // run code for function 1
   static unsigned long timer = 0;
   unsigned long interval = 1000;
   if (millis() - timer >= interval)
   {
      timer = millis();
      Serial.println("Running function 1");
   }
}

void function2()
{
   // run code for function 2
   static unsigned long timer = 0;
   unsigned long interval = 1000;
   if (millis() - timer >= interval)
   {
      timer = millis();
      Serial.println("Running function 2");
   }
}

void function3()
{
   // run code for function 2
   static unsigned long timer = 0;
   unsigned long interval = 1000;
   if (millis() - timer >= interval)
   {
      timer = millis();
      Serial.println("Running function 3");
   }
}
1 Like

How would i implement that into my code?

You don't use it directly. You read it, play around with it, until you understand the principles. Then you apply those principles in your own code.

But if I were you, I would not add any buttons to your code yet. Do more testing first. Then you will realise that your stopwatch does not keep good time. I suspect you will find that even after 1 or 2 minutes, it will be slow by one or more seconds.

Many beginners have come to the forum with code similar to yours and asked why it does not keep good time. So spend some time using the forum search to find how they solved the problem.

I put it against the google stopwatch and by 9 min, google was ahead by about 50 sec. How can i fix this?

See post #4

EDIT: Forget using the forum search. I just tried and could find no examples like your code, even though I remember many of them over the years. Like finding a needle in a haystack!

The problem is that you can't use delay() like that to keep your stopwatch accurate. That would only work if all your other code took zero time to run. Unfortunately that's not true.

Arduino has a pretty good stopwatch built-in. It's the millis() function.

Try this against Google stopwatch

// Made by Matthew Hinkleman aka gohawks413

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int mil=00;
int sec=00;
int min=00;
int hr=00;

unsigned long nextMil;

void setup() {
lcd.begin(16,2);
lcd.setCursor(3,1);
lcd.print("Stopwatch");
delay(1000);
lcd.setCursor(2,0);
lcd.print("STARTS IN 5");
delay(1000);
lcd.clear();
lcd.setCursor(2,0);
lcd.print("STARTS IN 4");
delay(1000);
lcd.clear();
lcd.setCursor(2,0);
lcd.print("STARTS IN 3");
delay(1000);
lcd.clear();
lcd.setCursor(2,0);
lcd.print("STARTS IN 2");
delay(1000);
lcd.clear();
lcd.setCursor(2,0);
lcd.print("STARTS IN 1");
delay(1000);
lcd.clear();
lcd.setCursor(0,0);
nextMil = millis();
}

void loop() {

lcd.setCursor(3,2);
lcd.print("Stopwatch");
lcd.setCursor(3,0);
lcd.print(hr);
lcd.setCursor(5,0);
lcd.print(":");
lcd.print(min);
lcd.setCursor(8,0);
lcd.print(":");
lcd.print(sec);
lcd.print(".");
lcd.print(mil);
mil=mil+1;
nextMil += 100;
delay(nextMil - millis());

if(mil == 10){
  mil=0;
  sec=sec+1;
}
if(sec == 60){
  sec=00;
  min=min+1; 
}else;
if(min == 60){
  min=0;
  hr=hr+1;
}else;

lcd.clear();
}

The above, if it works correctly, is a very "quick and dirty" fix. There are much better ways to write your code.

So that means your stopwatch is running approximately 10% slow. Your loop() code contains a delay(100), but all the code in loop() combined is taking around 110ms.

You could try reducing your delay to delay(90). You will find that is a big improvement, but my suggested code above is even better because it automatically adjusts the delay() each time to synchronise with millis().

I did and there was no difference at 2 min

1 Like

It was still ahead by a few seconds when i tried that so i think i am going to use the code that you posted

1 Like

Ok, time to think about your buttons.

Start with the reset button, because that's really easy. If the button is pressed, your code just needs to set mil, sec, min & hr back to zero. No need for state change detection or debouncing with this button.

1 Like

So i have the reset button on D9. How would i have it detect input?

see post #2.

1 Like

How would i make it go back to the void setup() when the reset button is pushed

The best way to connect a button is to connect it between the Arduino pin and ground. Set the pin mode to INPUT_PULLUP so that the pin does not float when the button is not pressed.

Your code can then read the pin with digitalRead(). If the result is LOW, that means the button is pressed.

Another alternative is to use the Arduino's reset button as your stopwatch reset button. If you want to use an external button, you can connect it between the RST pin and ground.

Why go back to setup()? Do you want to repeat the whole "Thunderbirds are go" sequence?

If you use the Arduino reset button (or an external button connected to the RST pin) then setup() will get run.

If you want to repeat just the countdown and don't want to reset the Arduino, you could move that countdown code to a new function and call it from both setup() and when your reset button is pressed.

Ok. Is this correct?

How do I create a function?

The way you have connected both buttons is good.

What is not good is that black wire on right side of the breadboard. That is connected directly from 5V to ground and will cause a short circuit which could damage the arduino. I think you made a mistake there!

EDIT: actually it won't cause a short circuit. But both buttons will connect to 5V instead of ground, so they will never read LOW.

Arduino functions.