Problem with correct operation of pushbuttons

Hi All
I am having to ask here because the original author of the project is not responding to troubleshooting questions.
I have a Stopwatch sketch that works almost perfectly except that the start/stop button restarts from 00:00:00 instead of carrying on from when it was stopped.
Here is the code I have:

// include the library code:
#include <LiquidCrystal.h>
#include <Bounce2.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 6, rw = 5, en = 4, d4 = 8, d5 = 9, d6 = 10, d7 = 11;
//LiquidCrystal(rs, rw, enable, d4, d5, d6, d7)
LiquidCrystal lcd(rs, rw, en, d4, d5, d6, d7);
const byte ledPin = 13;
const byte startButton = 7;
// Instantiate a Bounce object
Bounce startDebouncer1 = Bounce();
const byte resetButton = 3;
// Instantiate another Bounce object
Bounce resetDebouncer2 = Bounce();
void setup() {
pinMode(startButton, INPUT_PULLUP);
// After setting up the button, setup the Bounce instance :
startDebouncer1.attach(startButton);
startDebouncer1.interval(5); // interval in ms
pinMode(resetButton, INPUT_PULLUP);
// After setting up the button, setup the Bounce instance :
resetDebouncer2.attach(resetButton);
resetDebouncer2.interval(5); // interval in ms
pinMode(ledPin, OUTPUT);
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
lcd.setCursor(0, 0);
// Print a message to the LCD.
lcd.print("*** StopWatch **");
lcd.setCursor(0, 1);
lcd.print("*** Project ***");
delay(1500);
lcd.setCursor(0, 0);
// Print a message to the LCD.
lcd.print("***Door Mick**");
lcd.setCursor(0, 1);
lcd.print("*Dankjewel Bart*");
// clear screen for the next loop
delay(1500);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("S - Start/Stop");
lcd.setCursor(0, 1);
lcd.print("R - Reset");
}
bool startState = LOW;
bool resetState = LOW;
unsigned long startMillis;
unsigned long currentMillis;
unsigned long elapsedMillis;
void loop() {
// Update the Bounce instances :
startDebouncer1.update();
if ( startDebouncer1.fell() ) { // Call code if button transitions from HIGH to LOW
startState = !startState; // Toggle start button state
startMillis = millis();
}
if (startState)
{
currentMillis = millis();
elapsedMillis = (currentMillis - startMillis);
lcd.setCursor(0, 0);
lcd.print("SW (hh:mm:ss:ms)");
lcd.setCursor(0, 1);
lcd.print(" ");
unsigned long durMS = (elapsedMillis%1000); //Milliseconds
unsigned long durSS = (elapsedMillis/1000)%60; //Seconds
unsigned long durMM = (elapsedMillis/(60000))%60; //Minutes
unsigned long durHH = (elapsedMillis/(3600000)); //Hours
durHH = durHH % 24;
String durMilliSec = timeMillis(durHH, durMM, durSS,durMS);
lcd.setCursor(0, 1);
lcd.print(durMilliSec);
delay(150);
}
resetDebouncer2.update();
if (resetDebouncer2.fell())
{
resetState = HIGH;
}
if (resetState)
{
// clear screen for the next loop:
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("S - Start/Stop");
lcd.setCursor(0, 1);
lcd.print("R - Reset");
delay(100);
resetState = LOW;
}
}
String timeMillis(unsigned long Hourtime,unsigned long Mintime,unsigned long Sectime,unsigned long MStime)
{
String dataTemp = "";
if (Hourtime < 10)
{
dataTemp = dataTemp + "0" + String(Hourtime)+ "h:";
}
else{
dataTemp = dataTemp + String(Hourtime)+ "h:";
}
if (Mintime < 10)
{
dataTemp = dataTemp + "0" + String(Mintime)+ "m:";
}
else{
dataTemp = dataTemp + String(Mintime)+ "m:";
}
if (Sectime < 10)
{
dataTemp = dataTemp + "0" + String(Sectime)+ "s:";
}
else{
dataTemp = dataTemp + String(Sectime)+ "s:";
}
dataTemp = dataTemp + String(MStime);
return dataTemp;
}

Being a bit of a long term newbie, this is just beyond me at the moment but I hope to learn something with this.

consider

// stopwatch controlled by 2 buttons

#if 0       // my hardware
# include "LiquidCrystal.h"
const byte PinStart = A1;
const byte PinStop  = A2;

#else
# include <LiquidCrystal.h> // Import LCD
const byte PinStart = 7;
const byte PinStop  = 3;

#endif

const int rs = 6, rw = 5, en = 4, d4 = 8, d5 = 9, d6 = 10, d7 = 11;
LiquidCrystal lcd(rs, rw, en, d4, d5, d6, d7);

byte buttonPins   [] = { PinStart, PinStop };
byte buttonStates [] = { HIGH, HIGH };

#define N_BUTS  sizeof (buttonPins)

unsigned long msecLst = 0;
unsigned long msec;
unsigned long msec0;
unsigned long msec1;

int           run     = 0;

char s0 [40];
char s1 [40] = "";


// -----------------------------------------------------------------------------
void setup () {
    Serial.begin (9600); // Initialise Serial at 9600.

    for (unsigned n = 0; n < N_BUTS; n++)
        pinMode (buttonPins [n], INPUT_PULLUP);

    lcd.begin (16, 2); // Initalise LCD Display.
    reset ();
}

// -----------------------------------------------------------------------------
int
chkButtons (void)
{
    for (unsigned n = 0; n < N_BUTS; n++)  {
        byte but = digitalRead (buttonPins [n]);
        if (buttonStates [n] != but)  {
            buttonStates [n] = but;
            delay (20);         // debounce
            if (LOW == but)
                return buttonPins [n];
        }
    }

    return 0;
}

// ---------------------------------------------------------
char *
getTime (
    char          *s,
    unsigned long  msec,
    unsigned long  msec0)
{
    int  secs = (msec - msec0) / 1000; 

    sprintf (s, "%2d:%02d:%02d.%03ld",
        secs / 3600, (secs / 60) % 60, secs % 60, (msec - msec0) % 1000);
    return s;
}

// ---------------------------------------------------------
void
lcdDisp (
    const char *s0,
    const char *s1 )
{
    lcd.clear ();

    lcd.setCursor (0, 0);
    lcd.print (s0);

    if (s1 && *s1)  {
        lcd.setCursor (0, 1);
        lcd.print (s1);
    }
}

// ---------------------------------------------------------
void
reset (void)
{
    run = 0;
    getTime (s0, 0, 0);
    lcdDisp (s0, 0);
}

// ---------------------------------------------------------
void loop () {
    msec = millis ();

    switch (chkButtons ())  {
    case PinStart:
        if (! run)  {
            run     = 1;
            msec0   = msec;
            msec1   = 0;
        }
        else  {
            msec1   = msec;
        }
        break;

    case PinStop:
        if (1 == run)
            run = 2;
        else if (2 == run)
            reset ();
        break;

    default:
        break;
    }

    if (1 != run)
        return;

    if (msec1)  {
        getTime (s1, msec1, msec0);
    }
    getTime (s0, msec, msec0);
    lcdDisp (s0, s1);
}

It sounds like you want a lap timer, not a stop watch.

No, a stopwatch is exactly what I need.
This is the senario:
The work that I do is charged by the hour and I may have several jobs going at the same time.
What I need is a stopwatch for each job that I can start and stop while I am actually working on that job and then when the job is complete, I can see exactly how much time I have spent on that job in total.
Therefore, one single button to start and stop and one button (optional) to reset to zero. In reality, when the job is finished, I would just switch that clock off after noting down the total time.
I'm not a coder and as I get older, I'm finding it more difficult to learn how to. I'm an electrical engineer working with hardware. I can design all the hardware and I can put together a project hardware wise. I just need the help of you people to comlete simple projects like this.

Do you really care about milliseconds? I assume that was part of the stopwatch code you started with. Come to that, do seconds mean anything for job costing?

To be honest, only hours and minutes matter to me and I was going to fix that bit of code when I'd got the button bit to work

Try this:

// include the library code:
#include <LiquidCrystal.h>
#include <Bounce2.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 6, rw = 5, en = 4, d4 = 8, d5 = 9, d6 = 10, d7 = 11;
//LiquidCrystal(rs, rw, enable, d4, d5, d6, d7)
LiquidCrystal lcd(rs, rw, en, d4, d5, d6, d7);
const byte ledPin = 13;
const byte startButton = 7;
// Instantiate a Bounce object
Bounce startDebouncer1 = Bounce();
const byte resetButton = 3;
// Instantiate another Bounce object
Bounce resetDebouncer2 = Bounce();

void setup()
{
  pinMode(startButton, INPUT_PULLUP);
  // After setting up the button, setup the Bounce instance :
  startDebouncer1.attach(startButton);
  startDebouncer1.interval(5); // interval in ms
  pinMode(resetButton, INPUT_PULLUP);
  // After setting up the button, setup the Bounce instance :
  resetDebouncer2.attach(resetButton);
  resetDebouncer2.interval(5); // interval in ms
  pinMode(ledPin, OUTPUT);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  // Print a message to the LCD.
  lcd.print("*** StopWatch **");
  lcd.setCursor(0, 1);
  lcd.print("*** Project ***");
  delay(1500);
  lcd.setCursor(0, 0);
  // Print a message to the LCD.
  lcd.print("***Door Mick**");
  lcd.setCursor(0, 1);
  lcd.print("*Dankjewel Bart*");
  // clear screen for the next loop
  delay(1500);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("S - Start/Stop");
  lcd.setCursor(0, 1);
  lcd.print("R - Reset");
}
bool startState = LOW;
bool resetState = LOW;
unsigned long startMillis;
unsigned long currentMillis;
unsigned long elapsedMillis;
unsigned long TotalMillis = 0;

void loop()
{
  // Update the Bounce instances :
  startDebouncer1.update();
  if ( startDebouncer1.fell() )   // Call code if button transitions from HIGH to LOW
  {
    startState = !startState; // Toggle start button state
    if (startState)
    {
      TotalMillis += elapsedMillis;
    }
    startMillis = millis();
  }
  if (startState)
  {
    currentMillis = millis();
    elapsedMillis = (currentMillis - startMillis);
    lcd.setCursor(0, 0);
    lcd.print("SW (hh:mm:ss:ms)");
    lcd.setCursor(0, 1);
    lcd.print(" ");
    unsigned long durMS = ((elapsedMillis + TotalMillis) % 1000); //Milliseconds
    unsigned long durSS = ((elapsedMillis + TotalMillis) / 1000) % 60; //Seconds
    unsigned long durMM = ((elapsedMillis + TotalMillis) / (60000)) % 60; //Minutes
    unsigned long durHH = ((elapsedMillis + TotalMillis) / (3600000)); //Hours
    durHH = durHH % 24;
    String durMilliSec = timeMillis(durHH, durMM, durSS, durMS);
    lcd.setCursor(0, 1);
    lcd.print(durMilliSec);
    delay(150);
  }
  resetDebouncer2.update();
  if (resetDebouncer2.fell())
  {
    resetState = HIGH;
  }
  if (resetState)
  {
    // clear screen for the next loop:
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("S - Start/Stop");
    lcd.setCursor(0, 1);
    lcd.print("R - Reset");
    delay(100);
    TotalMillis = 0;
    resetState = LOW;
  }
}

String timeMillis(unsigned long Hourtime, unsigned long Mintime, unsigned long Sectime, unsigned long MStime)
{
  String dataTemp = "";
  if (Hourtime < 10)
  {
    dataTemp = dataTemp + "0" + String(Hourtime) + "h:";
  }
  else
  {
    dataTemp = dataTemp + String(Hourtime) + "h:";
  }
  if (Mintime < 10)
  {
    dataTemp = dataTemp + "0" + String(Mintime) + "m:";
  }
  else
  {
    dataTemp = dataTemp + String(Mintime) + "m:";
  }
  if (Sectime < 10)
  {
    dataTemp = dataTemp + "0" + String(Sectime) + "s:";
  }
  else
  {
    dataTemp = dataTemp + String(Sectime) + "s:";
  }
  dataTemp = dataTemp + String(MStime);
  return dataTemp;
}

Compiled, not tested.

That's it! That's exactly what the original sketch should have done.
Thank you.

So here is my final sketch. I decided to keep the seconds just as visual feedback and added an LED to blink on the second just for confirmation that the clock is counting.

//Stopwatch with one button
//Original sketch by Door Mick and Dankjewel Bart



// include the library code:
#include <LiquidCrystal.h>
#include <Bounce2.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 6, rw = 5, en = 4, d4 = 8, d5 = 9, d6 = 10, d7 = 11;
//LiquidCrystal(rs, rw, enable, d4, d5, d6, d7)
LiquidCrystal lcd(rs, rw, en, d4, d5, d6, d7);
const byte ledPin = 13;
const byte startButton = 7;
// Instantiate a Bounce object
Bounce startDebouncer1 = Bounce();
const byte resetButton = 3;
// Instantiate another Bounce object
Bounce resetDebouncer2 = Bounce();

void setup()
{
  pinMode(startButton, INPUT_PULLUP);
  // After setting up the button, setup the Bounce instance :
  startDebouncer1.attach(startButton);
  startDebouncer1.interval(5); // interval in ms
  pinMode(resetButton, INPUT_PULLUP);
  // After setting up the button, setup the Bounce instance :
  resetDebouncer2.attach(resetButton);
  resetDebouncer2.interval(5); // interval in ms
  pinMode(ledPin, OUTPUT);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  // Print a message to the LCD.
  lcd.print("Starting...");
  digitalWrite(ledPin, HIGH);
  //lcd.setCursor(0, 1);
  //lcd.print("*** Stopclock***");
  //delay(1500);
  //lcd.setCursor(0, 0);
//
  // clear screen for the next loop
  delay(1500);
  digitalWrite(ledPin, LOW);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Press button");
  lcd.setCursor(0, 1);
  lcd.print("to start/stop");
}
bool startState = LOW;
bool resetState = LOW;
unsigned long startMillis;
unsigned long currentMillis;
unsigned long elapsedMillis;
unsigned long TotalMillis = 0;

void loop()
{
  // Update the Bounce instances :
  startDebouncer1.update();
  if ( startDebouncer1.fell() )   // Call code if button transitions from HIGH to LOW
  {
    startState = !startState; // Toggle start button state
    if (startState)
    {
      TotalMillis += elapsedMillis;
    }
    startMillis = millis();
  }
  if (startState)
  {
    currentMillis = millis();
    elapsedMillis = (currentMillis - startMillis);
    lcd.setCursor(0, 0);
    lcd.print("TOTAL TIME      ");
    lcd.setCursor(0, 1);
    lcd.print(" ");
    unsigned long durMS = ((elapsedMillis + TotalMillis) % 1000); //Milliseconds
    unsigned long durSS = ((elapsedMillis + TotalMillis) / 1000) % 60; //Seconds
    unsigned long durMM = ((elapsedMillis + TotalMillis) / (60000)) % 60; //Minutes
    unsigned long durHH = ((elapsedMillis + TotalMillis) / (3600000)); //Hours
    durHH = durHH % 24;
    String durMilliSec = timeMillis(durHH, durMM, durSS, durMS);
    lcd.setCursor(0, 1);
    lcd.print(durMilliSec);
    digitalWrite(ledPin, HIGH);
    delay(100);
    digitalWrite(ledPin, LOW);
    delay(900);
  }
  resetDebouncer2.update();
  if (resetDebouncer2.fell())
  {
    resetState = HIGH;
  }
  if (resetState)
  {
    // clear screen for the next loop:
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("S - Start/Stop");
    lcd.setCursor(0, 1);
    lcd.print("R - Reset");
    delay(100);
    TotalMillis = 0;
    resetState = LOW;
  }
}

String timeMillis(unsigned long Hourtime, unsigned long Mintime, unsigned long Sectime, unsigned long MStime)
{
  String dataTemp = "";
  if (Hourtime < 10)
  {
    dataTemp = dataTemp + "0" + String(Hourtime) + "h:";
  }
  else
  {
    dataTemp = dataTemp + String(Hourtime) + "h:";
  }
  if (Mintime < 10)
  {
    dataTemp = dataTemp + "0" + String(Mintime) + "m:";
  }
  else
  {
    dataTemp = dataTemp + String(Mintime) + "m:";
  }
  if (Sectime < 10)
  {
    dataTemp = dataTemp + "0" + String(Sectime) + "s";
  }
  else
  {
    dataTemp = dataTemp + String(Sectime) + "s";
  }
  //dataTemp = dataTemp + String(MStime);
  dataTemp = dataTemp + "  ";
  return dataTemp;
}

Thanks guys for your help.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.