Notifications
Clear all

Multiple Timer Library

35 Posts
2 Users
1 Likes
6,154 Views
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

Do you need many timers in one sketch? With the help of my OOP mentor and muse @frogandtoad, I have come up with this simple library for millisecond and microsecond timers that only really need one line of code.

OK two lines.

In the header the timers are invoked like this:

#include <multiTimer.h>

Timer timer1, timer2; //as many timers as you want

And in the main loop():

void loop() {

  if(timer1.pause(0, 5000)){
    Serial.println("5000 milliseconds period"); // or do something else every 5 seconds
  }
  /*
  Alternatively, use MILLIS instead of 0
  if(timer1.pause(MILLIS, 5000))
  */
  
  if(timer2.pause(MICROS, 3300000)){
    Serial.println("3300000 microsecond period"); // or do something else
  }
  /*
  Alternatively, use 1 instead of MICROS
  if(timer2.pause(1, 3300000))
  */
}

Install the contents of the attached .zip file in your Arduino/libraries directory and off you go!!

If you run into any problems, let me know in this thread, more functionality is yet to come.


   
Quote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

@frogandtoad

Points taken!!

I am getting a compiler error <'tim' is not a namespace-name>

but

namespace tim {

  my code

}

is in the .cpp file


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

@frogandtoad

I also wanted to run this by you, for a bit of added functionality:

#include <multiTimer2.h>

Timer timer1, timer2;

void setup() {
  
  Serial.begin(9600);
  Serial.println("Sketch starting...");
}

void loop() {

  timer1.isRunning = false;
  if(timer1.pause(0, 5000)){
    Serial.println("5000 milliseconds period");
  }
  
  timer2.isRunning = true;
  if(timer2.pause(MICROS, 3300000)){
    Serial.println("3300000 microsecond period");
  }
  
}

.h file

#ifndef TWO_TIMERS
#define TWO_TIMERS

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

enum DELAY_MODE{MILLIS, MICROS};

class Timer
{
public:
/* declaring member functions */
bool isRunning;
bool pause(DELAY_MODE delay_mode, unsigned long delay_time);

private:
/* hidden private variables */
unsigned long _previous_time;
unsigned long _current_time;

};

#endif

.cpp file

#include <multiTimer2.h>

namespace tim {

bool Timer::pause(DELAY_MODE delay_mode, unsigned long delay_time){

if(delay_mode == MILLIS && isRunning){

_current_time = millis();

if(_current_time >= _previous_time + delay_time) {
_previous_time = _current_time;
return true;
}
}

if(delay_mode == MICROS && isRunning){

_current_time = micros();

if(_current_time >= _previous_time + delay_time) {
_previous_time = _current_time;
return true;
}
}
return false;
}

}

   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 
Posted by: @pugwash

@frogandtoad

Points taken!!

I am getting a compiler error <'tim' is not a namespace-name>

but

namespace tim {

  my code

}

is in the .cpp file

Sorry, had to attend to something.

Yes, but was missing from the header file!

Where is the function for: "isRunning", or is it supposed to be just a variable?
I'm not sure what it's doing 🙂


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

@frogandtoad

Yes, but was missing from the header file!

Are you saying that I have to put the class inside a namespace? That makes no sense if it is to be available globally!

"isRunning", I have made as a class member, in the .h file!


   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

@pugwash

Posted by: @pugwash

Are you saying that I have to put the class inside a namespace? That makes no sense if it is to be available globally!

Yes, of course... that's how namespaces work!  The header file should be wrapped in a namespace as well as the implementation file, but for the implementation file you can also use the direct label with the scope resolution operator for maximum security.

I'll show you an example... gimme some time to code it up.

As for the member, according to the comment I thought you were going to make it a function.

Anyhow, how do you intend to check it?

Cheers!


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

@frogandtoad

I see "isRunning" as just a class property not a class method. Just sets the instance property to true or false depending on whether I want a specific timer to run or not to run. I could have done this outside the class, of course.

 

 


   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

@frogandtoad

Ok, as for "isRunning"... what is the need to check if the pause is running?

Because I may want to start or stop the timers with code, button or interrupt, rather than just leaving the timers to run constantly, with no control over them!

**********************************

Also, you should not use zero(0) for the function call, because the enum could be written as:

 enum DELAY_MODE{MILLIS=1000, MICROS=1000000};

I have seen this done elsewhere and as far as I am concerned an enumerator attaches a numeric value to the list of descriptors. If this is hardcoded, I don't see the problem.

An example from the rf24 library:

 radio.setPALevel(2); // Options are RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX
radio.setDataRate(0); // Options are RF24_1MBPS, RF24_2MBPS, RF24_250KBPS
radio.setCRCLength(2); // Options are RF24_CRC_DISABLED, RF24_CRC_8, RF24_CRC_16

*********************************

Finally, if the declaration of a library object instance should always be

tim::Timer t1, t2;

why have I never seen this convention used anywhere before?


   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

@pugwash

Posted by: @pugwash

Ok, as for "isRunning"... what is the need to check if the pause is running?

Because I may want to start or stop the timers with code, button or interrupt, rather than just leaving the timers to run constantly, with no control over them!

OK, fair enough.

Posted by: @pugwash

Also, you should not use zero(0) for the function call, because the enum could be written as:

 enum DELAY_MODE{MILLIS=1000, MICROS=1000000};

I have seen this done elsewhere and as far as I am concerned an enumerator attaches a numeric value to the list of descriptors. If this is hardcoded, I don't see the problem.

The whole idea behind this approach is to have meaningful descriptors, and if you always use the descriptor, then you can't enter the wrong number by accident.  As I said, the C++ standards committee think it's enough of a problem to make it illegal in their upcoming release, so there must have been a lot of submissions for safety reasons.

Posted by: @pugwash

Finally, if the declaration of a library object instance should always be

tim::Timer t1, t2;

why have I never seen this convention used anywhere before?

I didn't say it should always be, I said it is the safest and most preferred way, well amongst the professionals at least.  I'm not sure why you haven't seen it before?  But I have seen it and used it a lot in usenet groups for 20 years.

A lot of people will generally just use:

using namespace X;

... and then there is no need to do: X:: in front of every identifier, but by doing this, you bring all objects in that namespace into global scope, which increases the risk of name clashes.  Many people also do this out of pure laziness, just to avoid the labels 🙂

Cheers!


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

@frogandtoad

As I understood from the scope code in the other thread where we were discussing this, using namespace is to throw a fence around code to protect it, but in the main sketch or anywhere else, you always have to climb over the fence to get at that particular protected function/method by using an extra identifier.

If that is the purpose of using namespace, then I think I have got it and can see reasons for using it in large programs, but I think it is a bit "OTT" for the small stuff that fits in an Arduino! 


   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

@pugwash

Posted by: @pugwash

If that is the purpose of using namespace, then I think I have got it and can see reasons for using it in large programs, but I think it is a bit "OTT" for the small stuff that fits in an Arduino! 

Yes, I think you've pretty much got it.  Of course, you do not have to incorporate namespace(s) if you do not wish to for personal small programs, but if you want to create libraries for others to use, then I'd say it's a mandatory requirement, so not a bad habit to get into anyway, unless you're lazy! 😛  

For example, what would you think (and what would you do?), if you downloaded or purchased someone else's math library, but as soon as you #include<> the library, it has a pause and a delay function that clashes with not only your library function and the Arduino function too?  Will you rename the functions in the math library? your library? etc... what can you do? You'll most likely throw that library out, look for a new one, and curse the person who wrote the library giving him a bad reputation, when no one will ever purchase their library ever again! - You get the gist!

Now put your print2Digits thingamabob in there, and rename it to, oh I dunno... pw_utilities.h? 🙂

Cheers!


   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

Correction:

A few posts earlier (in option 2), I rushed and wrongly labeled:

tim::millis();

... the tim:: label should have been applied to tim::MICROS instead.

Cheers!

   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

   
ZeFerby reacted
ReplyQuote
Page 1 / 3