Timers on Argon and best way to approach them?

Hello…
I have a bunch of code where I am running a state machine…I need to have certain pieces run for 20 minutes, others at 20 seconds, others at 2 seconds, etc.
Can someone tell me how to do this?

I was given the following code:
My concern here is the first line msDelay = 0 works fine if you are just booting up the device (because millis() will return 0) but in other instances you have NO clue what millis() will return. Doesn’t it make sense to make the first line as this would guarantee DELAY as desired. Potentially the other way you could immediately have met the condition without even doing a delay. This is very true if you were using the condition sometime later in your program after it has been up and running for a while.

static uint32_t msDelay = millis();
  static uint32_t msDelay = 0;
  if (millis() - msDelay >= DELAY) {
    msDelay = millis();
    // do your stuff here
}

Not sure what you intend to say with that.
Make the first line what?

(not sure what other way, but I assume presetting with 0)
That's the point. When you rebooted the device you already had some delay (the time the device was not running :wink: ). And any time after that the intended cadence will be met.

With static uint32_t msDelay = 0; the code will execute on first visit when DELAY is less or equal the boot-up time and as early as possible for DELAY greater than that.

Alternatively you could rewrite the condition like that

static uint32_t msDelay = 0;
if (millis() - msDelay >= DELAY || !msDelay)

This way you make sure that the timed code will always run immediately after boot-up and from then on keep the delay period consistent.

Which way you write it depends on what exactly you need :wink:
Should your code execute as early or as late as possible?
That obviously impacts how what the initial state should be coded.

3 Likes

yes, what @ScruffR said.

This phrase jumped out to me. I recalled an earlier post which discussed millis() and rollover which I used to straighten out my code, at the time. My thought was this might have been why you were given the code in the main block (5 lines).

https://community.particle.io/t/millis-and-rollover-tutorial/20429

Sorry for the ambiguity there…

What I was trying to ask…Doesn’t it make sense to make the first line:

static uint32_t Delay = millis();

if you want to create a timed event after something has else has occurred? For instance I have an event happen and I want to wait 2 seconds later to create the 2nd event. I don’t want the 2nd event to occur THEN occur thereafter every 2 seconds. I just want it to occur for a period then the code moves on. Make sense?

For me your initial post sounded as if you had three concurrent time frames rahter than consecutive.

If you want three concurrent “timers”, you’d either use three independent msLastEvent### variables to keep track of the respective last occurrence and three independent msPERIOD### constants (I’d opt for an array[3] for that).
Or you find a common base (e.g. 1 sec) and a iteration counter which you check like this
e.g.

void loop() {
  static uint32_t msLastTime = 0;
  static int countIterations = 0;
  if (millis() - msLastTime >= 1000) {
    msLastTime = millis();
    countIterations++;
    if (!countIterations % 2) {
      // do 2-second stuff
    }
    if (!counterIterations % 20) {
      // do 20-second stuff
    }
    if (!counterIterations % 60 * 20) {
      // do 20-minute stuff
      counterIterations = 0;
    }
}

However, as always there are loads of ways to achieve the same goal - knowing as many ways to do it as possible and picking the right one for the task is a skill in itself :wink:

For non-concurrent (but at least partly parallel) timed events you’d probably need to go with independent time keeping for each and using the msLastEvent### == 0 as a flag whether the condition should be interpreted or not.

BTW, there are also SoftwareTimes that can be used quite flexibly.

1 Like

Hi, I think so. When it is less than or equal to the startup time, static uint32_ t msDelay = 0;, The code will be executed in delay on the first access. If it is later than the startup time, execute delay as early as possible

Was looking at the SoftwareTimers that you mentioned…
The web page is somewhat esoteric in it’s description.

Does IsActive() mean running? or is there more to it?

Can you show me an example how to use the startFromISR(), stopFromISR()?

Thanks

isActive() means it's currently "running" so it was started and not stopped (or for one-shot timers hasn't expired yet).

There isn't much to it.
If you have an ISR (e.g. hooked to a pin via attachInterrupt()) you just call yourTimer.startFromISR() to start and yourTimer.stopFromISR() to stop that timer from within that ISR.

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