combining StopWatch code with my code

Hi all,

I'm new to Arduino and with pretty poor coding skills so please be gentle :confused:
I'm trying to control a relay with a single push button (ON/OFF) and present the status in the LCD.

I succeed on doing that (WOOWWWW) but now I'm trying to add a StopWatch that will start to run when it's "ON"(after pushing the button) and when I'll push the button again it will freeze and so on.

I found this:
http://arduinoprojects101.com/arduino-stopwatch/

code that seems to do exactly what I need but I don't know how to combine between this code and my code (below)... Can someone help me please???

 // include the library code
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display

// Using a push button switch for stay-on/stay-off push button . 
// beating a dead horse, again. Most of the real work is from other people. 


int switch1 = 12; // connect a push button switch between this pin and ground
int ledpin = 13; // internal led, external LED, relay, trigger for other function, some other device, whatever.
boolean flag = true;

void setup()
{
  lcd.init(); //initialize the lcd
  lcd.backlight(); //open the backlight
  pinMode(ledpin,OUTPUT); // this pin controlled by flipflop() function
  pinMode (switch1,INPUT_PULLUP); // keeps pin HIGH via internal pullup resistor unless brought LOW with switch
  Serial.begin(9600); // just for debugging, not needed.
  lcd.clear();
}

void loop()
{ 
  if (digitalRead(switch1)==LOW){ // check the state of switch1 every time we run through the main loop  
  delay(5); // I don't REALLY know why this delay helps, but it does. 
      flipflop(); // hops out of main loop and runs the flipflop function
  }// end of check for button press.

  // other sketch code here

} // end of main loop.

void flipflop(){  //funtion flipflop 
  flag = !flag;  // since we are here, the switch was pressed So FLIP the boolian "flag" state (we don't even care if switch was released yet)
  Serial.print("flag =   " );   Serial.println(flag);   // not needed, but may help to see what's happening.
 

  if (flag == HIGH){  // Use the value of the flag var to change the state of the pin
    digitalWrite(ledpin,HIGH ); // if the flag var is HIGH turn the pin on
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.println("Water Heater>ON ");
    Serial.print("ON");
  }
  if (flag == LOW) {
    digitalWrite(ledpin,LOW); // if the flag var is LOW turn the pin off 
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.println("Water Heater>OFF");
    Serial.print("OFF");
  }
  while(digitalRead(switch1)==LOW); // for "slow" button release, keeps us in the function until button is UN-pressed
  // If you take out this "while" the function becomes a flipflop oscillator if the button is held down. 
  delay(50); // OPTIONAL - play with this value.  It is probably short enough to not cause problems. deals with very quick switch press.
}

Everything you need is here:

  if (digitalRead(switch1)==LOW){ // check the state of switch1 every time we run through the main loop  
  delay(5); // I don't REALLY know why this delay helps, but it does. 
      flipflop(); // hops out of main loop and runs the flipflop function
  }// end of check for button press.

The delay is for debouncing purpose. If you don't know what it means, just google for "arduino button debouncing' and you'll find lots of explaination.

In this piece of code, when the button in pressed, you run a function (called flipflop) that displays a message on your LCD. You just need to take what you want from the code you found and put it in another function that you can call just after 'flipflop();'

I see this is about controlling a heater. If what you want is to display the time during which the heater is on, then you can also add your new code into the flipflop function. Or you can return the value of the flag variable to use it in your new function.

Thanks a lot lesept!

The notes in the code are not mine but thanks for the explanation mate.

This is exactly what I'm trying to do :slight_smile:
I though about calling the function that start and freeze the StopWatch somewhere here.
But the problem is that the StopWatch code has so many functions and I couldn't figure out what start the StopWatch and what freezing it. I don't know what I should keep and what should I remove from the StopWatch code...

if (flag == HIGH){  // Use the value of the flag var to change the state of the pin
    digitalWrite(ledpin,HIGH ); // if the flag var is HIGH turn the pin on
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.println("Water Heater>ON ");
    Serial.print("ON");
    lcd.setCursor(0,1);
    >>>>>>Start the StopWatch from 0 here
  }
  if (flag == LOW) {
    digitalWrite(ledpin,LOW); // if the flag var is LOW turn the pin off 
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.println("Water Heater>OFF");
    Serial.print("OFF");
    lcd.setCursor(0,1);
    >>>>>>>Freeze the StopWatch here
  }

It depends on what you mean by "freeze". When you restart the SW, does it start from zero again or from the time it stopped?

Anyways, the basic principle is the same : you have to use the millis() function. This function provides the number of milliseconds since the moment the code began to run.

So, you need to use a variable to store the SW value, let's call it stopWatch. Declare it global before the setup:

unsigned long stopWatch = 0;

Then, whenever you want to start the SW, you store in that variable the millis value

stopWatch = millis();

Anytime you want to know the time since the SW was launched, just compute

millis() - stopWatch

and change it to hours - minutes - seconds using the code in your link

If you want to stop the SW, store this millis() - stopWatch value in another (unsigned long) variable. You'll use it to display the time or to restart from this moment.

If you want to start the SW from zero, just initialize the stopWatch variable with millis() again.

I hope it's clear, if not just ask and I'll help...

Thank you so much man.
I’ll have to play with it a little bit and see if I got it.

Basically I mean that the SW will show the time when I’m stopping it (by clicking OFF) when I say freeze.

Thanks again!

OK. I tried to use your instructions, I combined the 2 codes and I have some progress! :slight_smile: wowww

But, I think I did something wrong because now I'm facing 2 problems:

  1. The time doesn't run on the LCD screen when I click ON, it does run in the back (because I see the time added when I'm clicking OFF).

  2. When I'm clicking "ON" it doesn't start from zero, it starts from the time presenting on the screen in OFF mode.

Any idea?

// include the library code
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display

// Using a push button switch for stay-on/stay-off push button . 
// beating a dead horse, again. Most of the real work is from other people. 


int switch1 = 12; // connect a push button switch between this pin and ground
int ledpin = 13; // internal led, external LED, relay, trigger for other function, some other device, whatever.
boolean flag = true;

 //StopWatch
int blinking;                       // condition for blinking - timer is timing
int frameRate = 100;                // the frame rate (frames per second) at which the stopwatch runs - Change to suit
long interval = (1000/frameRate);   // blink interval
long previousMillis = 0;            // variable to store last time LED was updated
unsigned long startTime = 0;       // start time for stop watch
unsigned long elapsedTime = 0;            // elapsed time for stop watch
int fractional;                     // variable used to store fractional part of Frames
int fractionalSecs;                 // variable used to store fractional part of Seconds
int fractionalMins;                 // variable used to store fractional part of Minutes
int elapsedFrames;                  // elapsed frames for stop watch
int elapsedSeconds;                 // elapsed seconds for stop watch
int elapsedMinutes;                 // elapsed Minutes for stop watch
char buf[10];                       // string buffer for itoa function


void setup()
{
  lcd.init(); //initialize the lcd
  lcd.backlight(); //open the backlight
  pinMode(ledpin,OUTPUT); // this pin controlled by flipflop() function
  pinMode (switch1,INPUT_PULLUP); // keeps pin HIGH via internal pullup resistor unless brought LOW with switch
  Serial.begin(9600); // just for debugging, not needed.
  lcd.clear();
}

void loop()
{ 
  if (digitalRead(switch1)==LOW){ // check the state of switch1 every time we run through the main loop  
  delay(200); // I don't REALLY know why this delay helps, but it does. 
      flipflop(); // hops out of main loop and runs the flipflop function
  }// end of check for button press.

  // other sketch code here

} // end of main loop.

void flipflop(){  //funtion flipflop 
  flag = !flag;  // since we are here, the switch was pressed So FLIP the boolian "flag" state (we don't even care if switch was released yet)
  Serial.print("flag =   " );   Serial.println(flag);   // not needed, but may help to see what's happening.
 

  if (flag == HIGH){  // Use the value of the flag var to change the state of the pin
    digitalWrite(ledpin,HIGH ); // if the flag var is HIGH turn the pin on
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.println("Water Heater>ON ");
    Serial.print("ON");
    millis() - elapsedTime;        // store elapsed time
    blinking = true;                                  // turn on timing
    delay(10);                                         // short delay to debounce switch
    lcd.setCursor(0,1);
    // Routine to report elapsed time 
         elapsedMinutes = (elapsedTime / 60000L);      // divide by 60000 to convert to minutes - then cast to an int to print
         elapsedSeconds = (elapsedTime / 1000L);       // divide by 1000 to convert to seconds - then cast to an int to print
         elapsedFrames = (elapsedTime / interval);     // divide by 40 to convert to 1/25 of a second - then cast to an int to print
         fractional = (int)(elapsedFrames % frameRate);// use modulo operator to get fractional part of 25 Frames
         fractionalSecs = (int)(elapsedSeconds % 60L); // use modulo operator to get fractional part of 60 Seconds
         fractionalMins = (int)(elapsedMinutes % 60L); // use modulo operator to get fractional part of 60 Minutes

       if (fractionalMins < 10){                     // pad in leading zeros
         lcd.print("0");                             // add a zero
         }

       lcd.print(itoa(fractionalMins, buf, 10));   // convert the int to a string and print a fractional part of 60 Minutes to the LCD
         lcd.print(":");                             //print a colan. 

       if (fractionalSecs < 10){                     // pad in leading zeros 
         lcd.print("0");                             // add a zero
         }

       lcd.print(itoa(fractionalSecs, buf, 10));   // convert the int to a string and print a fractional part of 60 Seconds to the LCD
         lcd.print(":");                             //print a colan. 

       if (fractional < 10){                         // pad in leading zeros 
         lcd.print("0");                             // add a zero
         }
          lcd.print(itoa((fractional), buf, 10));  // convert the int to a string and print a fractional part of 25 Frames to the LCD
         }  

  if (flag == LOW) {
    digitalWrite(ledpin,LOW); // if the flag var is LOW turn the pin off 
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.println("Water Heater>OFF");
    Serial.print("OFF");
    elapsedTime = millis();                            
    blinking = false;                                  // turn off timing
    delay(10);                                         // short delay to debounce switch
    lcd.setCursor(0,1);
    // Routine to report elapsed time            
   elapsedMinutes = (elapsedTime / 60000L);
   elapsedSeconds = (elapsedTime / 1000L);              // divide by 1000 to convert to seconds - then cast to an int to print
   elapsedFrames = (elapsedTime / interval);            // divide by 100 to convert to 1/100 of a second - then cast to an int to print
   fractional = (int)(elapsedFrames % frameRate);       // use modulo operator to get fractional part of 100 Seconds
   fractionalSecs = (int)(elapsedSeconds % 60L);        // use modulo operator to get fractional part of 60 Seconds
   fractionalMins = (int)(elapsedMinutes % 60L);        // use modulo operator to get fractional part of 60 Minutes
   
 if (fractionalMins < 10){                            // pad in leading zeros
      lcd.print("0");                                 // add a zero
      }

    lcd.print(itoa(fractionalMins, buf, 10));       // convert the int to a string and print a fractional part of 60 Minutes to the LCD
      lcd.print(":");                                 //print a colan. 

 if (fractionalSecs < 10){                            // pad in leading zeros
      lcd.print("0");                                 // add a zero
      }

 lcd.print(itoa(fractionalSecs, buf, 10));          // convert the int to a string and print a fractional part of 60 Seconds to the LCD
   lcd.print(":");                                    //print a colan. 

 if (fractional < 10){                                // pad in leading zeros 
      lcd.print("0");                                 // add a zero
      }     

 lcd.print(itoa(fractional, buf, 10));              // convert the int to a string and print a fractional part of 25 Frames to the LCD
   }
    
}

I solved it!

Thanks a lot for your help.

Here is the solution:

// include the library code
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display

// Using a push button switch for stay-on/stay-off push button . 
// beating a dead horse, again. Most of the real work is from other people. 


int switch1 = 12; // connect a push button switch between this pin and ground
int ledpin = 13; // internal led, external LED, relay, trigger for other function, some other device, whatever.
boolean flag = false;

 //StopWatch
int blinking;   // condition for blinking - timer is timing
int buttonState; 
int lastButtonState;
int frameRate = 5;                // the frame rate (frames per second) at which the stopwatch runs - Change to suit
long interval = (1000/frameRate);   // blink interval
long previousMillis = 0;            // variable to store last time LED was updated
long startTime;       // start time for stop watch
long elapsedTime;            // elapsed time for stop watch
int fractional;                     // variable used to store fractional part of Frames
int fractionalSecs;                 // variable used to store fractional part of Seconds
int fractionalMins;                 // variable used to store fractional part of Minutes
int fractionalHrs; 
int elapsedFrames;                  // elapsed frames for stop watch
int elapsedSeconds;                 // elapsed seconds for stop watch
int elapsedMinutes;                 // elapsed Minutes for stop watch
int elapsedHrs;
char buf[10];                       // string buffer for itoa function


void setup()
{
  lcd.init(); //initialize the lcd
  lcd.backlight(); //open the backlight
  pinMode(ledpin,OUTPUT); // this pin controlled by flipflop() function
  pinMode (switch1,INPUT_PULLUP); // keeps pin HIGH via internal pullup resistor unless brought LOW with switch
  Serial.begin(9600); // just for debugging, not needed.
  lcd.clear();
}

/*void loop()
{ 
  buttonState = digitalRead(switch1);
  if (buttonState==LOW){ // check the state of switch1 every time we run through the main loop  
  #delay(200); // I don't REALLY know why this delay helps, but it does. 
      flipflop(); // hops out of main loop and runs the flipflop function
  }// end of check for button press.

  // other sketch code here

} // end of main loop.*/

void loop(){
  buttonState = digitalRead(switch1);
  if (buttonState == LOW && lastButtonState == HIGH  &&  flag == false){
    
    startTime = millis();                               // store the start time
      flag = true;                                  // turn on blinking while timing
      delay(10);                                         // short delay to debounce switch
      lastButtonState = buttonState;                    // store buttonState in lastButtonState, to compare next time 
   }
   else if (buttonState == LOW && lastButtonState == HIGH && flag == true){
   
   flag = false;                                    // turn off blinking, all done timing
   lastButtonState = buttonState;                       // store buttonState in lastButtonState, to compare next time

// Routine to report elapsed time            
   elapsedTime =   millis() - startTime;                // store elapsed time
   elapsedMinutes = (elapsedTime / 60000L);
   elapsedSeconds = (elapsedTime / 1000L);              // divide by 1000 to convert to seconds - then cast to an int to print
   elapsedHrs = (elapsedTime / 3600000L);
   elapsedFrames = (elapsedTime / interval);            // divide by 100 to convert to 1/100 of a second - then cast to an int to print
   fractional = (int)(elapsedFrames % frameRate);       // use modulo operator to get fractional part of 100 Seconds
   fractionalSecs = (int)(elapsedSeconds % 60L);        // use modulo operator to get fractional part of 60 Seconds
   fractionalMins = (int)(elapsedMinutes % 60L);        // use modulo operator to get fractional part of 60 Minutes
   fractionalHrs = (int)(elapsedHrs % 60L);
    digitalWrite(ledpin,LOW); // if the flag var is LOW turn the pin off
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.println("Water Heater>OFF ");   
    lcd.setCursor(0,1);
   if (fractionalHrs < 10){                            // pad in leading zeros
      lcd.print("0");                                 // add a zero
      }

    lcd.print(itoa(fractionalHrs, buf, 10));       // convert the int to a string and print a fractional part of 60 Minutes to the LCD
      lcd.print(":");   
  if (fractionalMins < 10){                            // pad in leading zeros
      lcd.print("0");                                 // add a zero
      }

    lcd.print(itoa(fractionalMins, buf, 10));       // convert the int to a string and print a fractional part of 60 Minutes to the LCD
      lcd.print(":");                                 //print a colan. 

 if (fractionalSecs < 10){                            // pad in leading zeros
      lcd.print("0");                                 // add a zero
      }

 lcd.print(itoa(fractionalSecs, buf, 10));          // convert the int to a string and print a fractional part of 60 Seconds to the LCD
                                      

 /*if (fractional < 10){                                // pad in leading zeros 
      lcd.print("0");                                 // add a zero
      }     

 lcd.print(itoa(fractional, buf, 10));              // convert the int to a string and print a fractional part of 25 Frames to the LCD
   */}

 else{
      lastButtonState = buttonState;                  // store buttonState in lastButtonState, to compare next time
   }

   if ( (millis() - previousMillis > interval) ) {

    if (flag == true){
       previousMillis = millis();                    // remember the last time we blinked the LED

 
       elapsedTime =   millis() - startTime;         // store elapsed time
         elapsedMinutes = (elapsedTime / 60000L);      // divide by 60000 to convert to minutes - then cast to an int to print
         elapsedSeconds = (elapsedTime / 1000L);       // divide by 1000 to convert to seconds - then cast to an int to print
         elapsedFrames = (elapsedTime / interval);     // divide by 40 to convert to 1/25 of a second - then cast to an int to print
         fractional = (int)(elapsedFrames % frameRate);// use modulo operator to get fractional part of 25 Frames
         fractionalSecs = (int)(elapsedSeconds % 60L); // use modulo operator to get fractional part of 60 Seconds
         fractionalMins = (int)(elapsedMinutes % 60L); // use modulo operator to get fractional part of 60 Minutes
         elapsedHrs = (elapsedTime / 3600000L);
         fractionalHrs = (int)(elapsedHrs % 60L);
         digitalWrite(ledpin,HIGH ); // if the flag var is HIGH turn the pin on
         lcd.clear();
        lcd.setCursor(0,0);
        lcd.println("Water Heater>ON ");   
        lcd.setCursor(0,1);                                 // clear the LDC
      if (fractionalHrs < 10){                            // pad in leading zeros
      lcd.print("0");                                 // add a zero
      }

    lcd.print(itoa(fractionalHrs, buf, 10));       // convert the int to a string and print a fractional part of 60 Minutes to the LCD
      lcd.print(":");  
       if (fractionalMins < 10){                     // pad in leading zeros
         lcd.print("0");                             // add a zero
         }

       lcd.print(itoa(fractionalMins, buf, 10));   // convert the int to a string and print a fractional part of 60 Minutes to the LCD
         lcd.print(":");                             //print a colan. 

       if (fractionalSecs < 10){                     // pad in leading zeros 
         lcd.print("0");                             // add a zero
         }

       lcd.print(itoa(fractionalSecs, buf, 10));   // convert the int to a string and print a fractional part of 60 Seconds to the LCD
         

      /* if (fractional < 10){                         // pad in leading zeros 
         lcd.print("0");                             // add a zero
         }
          lcd.print(itoa((fractional), buf, 10));  // convert the int to a string and print a fractional part of 25 Frames to the LCD
         */}


 }

}