Go Down

Topic: Updated stopwatch class on the playground. (Read 10463 times) previous topic - next topic

robtillaart

Jun 15, 2011, 09:50 am Last Edit: Jun 15, 2011, 09:53 am by robtillaart Reason: 1
Today I updated my stopwatch class on the playground.

Changes:
- added state() to reflect state { STOPWATCH_RESET, STOPWATCH_RUNNING, STOPWATCH_STOPPED}
 => to differentiate between STOPPED and RESET.  In the previous version this was not possible.
- added #define STOPWATCH_LIB_VERSION
- some minor edits.

Have a look at - http://www.arduino.cc/playground/Code/StopWatchClass - for the details.

Suggestions, improvements and other comments ? let me know : enjoy tinkering

Rob
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

mojotexas

Just giving this a spin and having a little trouble.
I have created a StopWatch librabry and placed the .h and .cpp files there.
When I try and run the provided example sketch I get an error:

Code: [Select]

sketch_jul14a.cpp: In function 'void loop()':
sketch_jul14a:61: error: 'STOPWATCH_STATE_RESET' was not declared in this scope
sketch_jul14a:64: error: 'STOPWATCH_STATE_RUNNING' was not declared in this scope
sketch_jul14a:67: error: 'STOPWATCH_STATE_STOPPED' was not declared in this scope


What am I doing wrong?
thanks for the great library.

P.S. Is there a way to have it count down to zero instead of up?
Arduino Uno (IDE 22)
Ubuntu 10.10 Maverick

robtillaart

#2
Jul 14, 2011, 03:24 pm Last Edit: Jul 14, 2011, 03:34 pm by robtillaart Reason: 1
Bug in the example code, my fault.

I shortened some defines but forgot the sample code, change the three names to

STOPWATCH_RESET
STOPWATCH_RUNNING
STOPWATCH_STOPPED

I will update the playground asap
-- update --
done

I like the idea of counting down, can you tell me what you want it to do, callback function or just stop at 0 or ....

Rob
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

mojotexas

Thanks for the quick reply! That change worked for me after I edited the sketch.

The Countdown is for a movie special effect. An astronaut has an LCD timer that counts down from 20 minutes oxygen remaining to 0.
So, it needs to start at 20 minutes, then go backwards to 0.
Display 0:20:00.000
0:19:59.999
0:19:58.999

the milliseconds I can fake by printing "millis()"

I need to add a couple buttons for setting the timer, so the start time can be upped and downed by minutes. (director might want to film starting at 0:03:00:000.
I might also trigger an event at 1:00.
I am using the LCDbargraph library to represent the remaining time as a bar.

So, any thoughts on making the stopwatch count backwards?
Arduino Uno (IDE 22)
Ubuntu 10.10 Maverick

retrolefty

Quote
the milliseconds I can fake by printing "millis()"


That should be interesting to see.  ;)

Lefty

robtillaart

Quote
So, any thoughts on making the stopwatch count backwards?

No, not gonna make the stopwatch class count backwards. you could do something like next sketch quite easily.

Code: [Select]

#include <StopWatch.h>

StopWatch SW;

unsigned long start = 180000L;   // 3 minutes in millisec

void setup()
{
  SW.reset();
  SW.start();
}

void loop()
{
  unsigned long down = start - SW.value();
  if (down > 0)
    Serial.println( down );  // OK, you can beautify this in min:sec:mil
  else
    Serial.println(0);
}


You can set the start to any value with switches, and after a start signal you can do the above.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

OptoLcd

Hi All.

My first post and I am totally new to Arduino.
I copied the StopWatch.h and StopWatch.cpp into sketch folder.
When I verify the StopWatch.pde I get the following compile error.

core.a(main.cpp.o): In function `main':
/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino/main.cpp:7: undefined reference to `setup'
/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino/main.cpp:10: undefined reference to `loop'


Any help gratefully received.
Austin

robtillaart

StopWatch.h & stopWatch.cpp must be in the library folder .

To use this library, make a folder in your SKETCHBOOKPATH\libaries with the name StopWatch and put the .h and .cpp there. Close all your IDE's and then it is ready to use.

Adviced reader (part about installing libs) - http://arduino.cc/en/Hacking/LibraryTutorial -
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)


mromani

Hi,
I like your code. I've made an attempt to improve it based on my TimeUtils class.
I've added support for different resolutions, millis and micros.
Resolution is selected at object creation time.
Also, I think elapsed() is a better name than value(), therefore I've added the former as a synonym for the latter.
Finally, I've replaced the #defines with an enum.
If you find this interesting, let me know what you think.

:-)

Code: [Select]

#ifndef StopWatch_h
#define StopWatch_h
//
//    FILE: StopWatch.h
//  AUTHOR: Rob Tillaart
// PURPOSE: Simple StopWatch library for Arduino
// HISTORY: See StopWatch.cpp
//     URL: http://www.arduino.cc/playground/Code/StopWatchClass
//
// Released to the public domain
//

#define STOPWATCH_LIB_VERSION "0.1.02"

class StopWatch
{
public:
    enum State { RESET, RUNNING, STOPPED };
    enum Resolution { MILLIS, MICROS };
    StopWatch(enum Resolution res = MILLIS);
    void start();
    void stop();
    void reset();
    unsigned long value();
    unsigned long elapsed() { return value(); };
    bool isRunning();
    enum State state();

private:
    enum State _state;
    enum Resolution _res;
    unsigned long _starttime;
    unsigned long _stoptime;
    unsigned long _gettime();
};

#endif
// END OF FILE


Code: [Select]

//
//    FILE: StopWatch.cpp
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.02
// PURPOSE: Simple StopWatch library for Arduino
//
// The library is based upon millis() and therefore
// has the same restrictions as millis() has wrt overflow.
//
// HISTORY:
// 0.1.00 - 2011-01-04 initial version
// 0.1.01 - 2011-01-04 Added better state
// 0.1.02 - 2011-06-15 Added state() + #defines + lib version
//
// Released to the public domain
//

#if ARDUINO >= 100
    #include "Arduino.h"
#else
    #include "WProgram.h"
#endif
#include "StopWatch.h"


StopWatch::StopWatch(enum Resolution res)
{
    _res = res;
    reset();
}

void StopWatch::reset()
{
    _state = StopWatch::RESET;
    _starttime = _stoptime = 0;
}

void StopWatch::start()
{
    if (_state == StopWatch::RESET || _state == StopWatch::STOPPED)
    {
        _state = StopWatch::RUNNING;
        unsigned long t = _gettime();
        _starttime += t - _stoptime;
        _stoptime = t;
    }
}

unsigned long StopWatch::value()
{
    if (_state == StopWatch::RUNNING) _stoptime = _gettime();
    return _stoptime - _starttime;
}

void StopWatch::stop()
{
    if (_state == StopWatch::RUNNING)
    {
        _state = StopWatch::STOPPED;
        _stoptime = _gettime();
    }
}

bool StopWatch::isRunning()
{
    return (_state == StopWatch::RUNNING);
}

enum StopWatch::State StopWatch::state()
{
    return _state;
}

unsigned long StopWatch::_gettime() {
    return (_res == StopWatch::MILLIS ? millis() : micros());
}

// END OF FILE

robtillaart


Quote
If you find this interesting, let me know what you think.

At first sight it looks like a great improvement, thanx,

Quote
Resolution is selected at object creation time

good, backwards compatible, ==> OK

Quote
elapsed() is a better name than value()

Agree partially, because of ambiguity of definition elapsed time:
- if a stopwatch is stopped and started a few times the elapsed time since first start is longer than the time on the stopwatch.
  That said , think elapsed is better than value though, other words I considered were counts and ticks ... what do you think of them?
  ==> OK

Quote
I've replaced the #defines with an enum

Good step, add SECONDS too?
==> OK

Open issues
+ the version number should be updated, propose 1.0.00 as it is a major step

+ credits for your update

+ missing function to ask the mode. enum Resolution resolution() { return _res; }

+ _getTime() could be inline to minimize the time used by the class itself. (speed versus size discussion)

What do you think?

Rob
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

mromani



Quote
If you find this interesting, let me know what you think.

At first sight it looks like a great improvement, thanx,


Thank you for your interest in my edits. It's a pleasure to work on good code :-)


Quote
Resolution is selected at object creation time

good, backwards compatible, ==> OK


I wanted the code default behaviour to be the same as the original one.

Regarding the resolution selection time, I thought about two possible choices: set it once at object creation time, and/or allow the user to select it at (re)start() time. As the former looked simpler to implement and use, I opted for it, but I'm open to discussion on the latter.
API-wise, it would look something like:
obj.start(MILLIS) // this would be the default, obviously
obj.start(MICROS)  // next value() or elapsed() would return micros, instead of millis.
As for the implementation, I think some complexity would arise due to conversion between millis and micros...
Do you think this would have a use case ?


Quote
elapsed() is a better name than value()

Agree partially, because of ambiguity of definition elapsed time:
- if a stopwatch is stopped and started a few times the elapsed time since first start is longer than the time on the stopwatch.
  That said , think elapsed is better than value though, other words I considered were counts and ticks ... what do you think of them?
  ==> OK


I'm not a native english speaker, so take this with a grain of salt... elapsed makes me think about the time since the last start, not the first start. From ticks() I would expect instead to receive the number of time units since the first start. Those would be millis, micros or seconds based on what was was passed to the constructor.


Quote
I've replaced the #defines with an enum

Good step, add SECONDS too?
==> OK


Agreed.


Open issues
+ the version number should be updated, propose 1.0.00 as it is a major step


I'd stick with something a little below 1.0, since it's not really feature-complete, IMHO.


+ credits for your update


How could I disagree ?

:-)


+ missing function to ask the mode. enum Resolution resolution() { return _res; }


Agreed.


+ _getTime() could be inline to minimize the time used by the class itself. (speed versus size discussion)


I thought the compiler was smart enough to inline such a trivial function, treating it more or less as a #define.


What do you think?

Rob


Now it's my turn to ask you this question :-)

Macello

PS: updated code will follow soon.

mromani

Please forget what I wrote about elapsed vs. ticks. I think I didn't fully understand your code.

I still vote for elapsed(). I'd put disambiguation into docs :)

mromani


mromani

Code: [Select]

#include <StopWatch.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

StopWatch sw_millis;    // MILLIS (default)
StopWatch sw_micros(StopWatch::MICROS);
StopWatch sw_secs(StopWatch::SECONDS);

void setup() {
    lcd.begin(16,2);
    Serial.begin(9600);
    sw_millis.start();
    sw_micros.start();
    sw_secs.start();
}


void loop() {
    Serial.print("sw_millis=");
    Serial.println(sw_millis.elapsed());
    Serial.print("sw_micros=");
    Serial.println(sw_micros.elapsed());
    Serial.print("sw_secs=");
    Serial.println(sw_secs.elapsed());
   
    lcd.clear();
    lcd.print("s=");
    lcd.print(sw_secs.elapsed());
    lcd.print(" ms=");
    lcd.print(sw_millis.elapsed());
    lcd.setCursor(0, 1);
    lcd.print("us=");
    lcd.print(sw_micros.elapsed());
   
    delay(1000);
}



Code: [Select]

#ifndef StopWatch_h
#define StopWatch_h
//
//    FILE: StopWatch.h
//  AUTHOR: Rob Tillaart
// PURPOSE: Simple StopWatch library for Arduino
// HISTORY: See StopWatch.cpp
//     URL: http://www.arduino.cc/playground/Code/StopWatchClass
//
// Released to the public domain
//

#define STOPWATCH_LIB_VERSION "0.1.02"

class StopWatch
{
public:
    enum State { RESET, RUNNING, STOPPED };
    enum Resolution { MILLIS, MICROS, SECONDS };
    StopWatch(enum Resolution res = MILLIS);
    void start();
    void stop();
    void reset();
    unsigned long value();              // should this be deprecated ?
    unsigned long elapsed() { return value(); };
    bool isRunning();
    enum State state();
    enum Resolution resolution() { return _res; };

private:
    enum State _state;
    enum Resolution _res;
    unsigned long _starttime;
    unsigned long _stoptime;
    unsigned long _gettime();
};

#endif
// END OF FILE



Code: [Select]

//
//    FILE: StopWatch.cpp
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.02
// PURPOSE: Simple StopWatch library for Arduino
//
// The library is based upon millis() and therefore
// has the same restrictions as millis() has wrt overflow.
//
// HISTORY:
// 0.1.00 - 2011-01-04 initial version
// 0.1.01 - 2011-01-04 Added better state
// 0.1.02 - 2011-06-15 Added state() + #defines + lib version
//
// Released to the public domain
//

#if ARDUINO >= 100
    #include "Arduino.h"
#else
    #include "WProgram.h"
#endif
#include "StopWatch.h"


StopWatch::StopWatch(enum Resolution res)
{
    _res = res;
    reset();
}

void StopWatch::reset()
{
    _state = StopWatch::RESET;
    _starttime = _stoptime = 0;
}

void StopWatch::start()
{
    if (_state == StopWatch::RESET || _state == StopWatch::STOPPED)
    {
        _state = StopWatch::RUNNING;
        unsigned long t = _gettime();
        _starttime += t - _stoptime;
        _stoptime = t;
    }
}

unsigned long StopWatch::value()
{
    if (_state == StopWatch::RUNNING) _stoptime = _gettime();
    return _stoptime - _starttime;
}

void StopWatch::stop()
{
    if (_state == StopWatch::RUNNING)
    {
        _state = StopWatch::STOPPED;
        _stoptime = _gettime();
    }
}

bool StopWatch::isRunning()
{
    return (_state == StopWatch::RUNNING);
}

enum StopWatch::State StopWatch::state()
{
    return _state;
}

unsigned long StopWatch::_gettime() {
    switch(_res) {
        case MICROS:
            return micros();
           
        case MILLIS:
            return millis();
           
        case SECONDS:
            return millis()/1000;
    }
}

// END OF FILE

Go Up