1

I realize my question is not precise, so I have a simple contrived example to illustrate better what I am asking.

I am trying to use EVERY_N_SECONDS inside a member function of a class that is invoked in the sketch's loop() method. And this works fine, but when I have two instances of the class, each has its member function called in the loop(), but one instance seems to "win" and the other instance never seems to hit the inside of the EVERY_N_SECONDS block.

For example, the following code produces this output (I expected both a2 and a1 to appear in "a2 is in the EVERY_N_SECONDS loop"):

a1 is in the loop
a1 is in the EVERY_N_SECONDS loop
a2 is in the loop
a1 is in the loop
a1 is in the EVERY_N_SECONDS loop
a2 is in the loop
a1 is in the loop
a1 is in the EVERY_N_SECONDS loop
a2 is in the loop

Here is the code, a silly little program to illustrate the question:

#include <Streaming.h>
#include <FastLED.h>

class A {
public:
 String tag;
 void loop() 
 { 
   Serial << tag << " is in the loop" << endl;
   EVERY_N_SECONDS(2) {
      Serial << tag << " is in the EVERY_N_SECONDS loop" << endl;
   }
 }
};

A a1, a2;

void setup() {
  Serial.begin(9600);
  a1.tag = "a1";
  a2.tag = "a2";
}

void loop() {  
  a1.loop();
  a2.loop();
  FastLED.delay(5000);
}
1
  • When looking at its definition and the line below, it seems like static. Though I don't quite understand what they are doing there
    – chrisl
    Commented Nov 28, 2022 at 20:44

1 Answer 1

1

Assuming that the link of chrisl points to the relevant source...

Your source code:

    EVERY_N_SECONDS(2) {
        Serial << tag << " is in the EVERY_N_SECONDS loop" << endl;
    }

expands to (line split for readability):

    static CEveryNSeconds PER__COUNTER__(2);
    if( PER__COUNTER__ ) {
        Serial << tag << " is in the EVERY_N_SECONDS loop" << endl;
    }

So, yes, the instance controlling the conditional statement is static.

This is the definition of CEveryNSeconds:

template<typename timeType,timeType (*timeGetter)()>
class CEveryNTimePeriods {
public:
    timeType mPrevTrigger;
    timeType mPeriod;
    CEveryNTimePeriods() { reset(); mPeriod = 1; };
    CEveryNTimePeriods(timeType period) { reset(); setPeriod(period); };
    void setPeriod( timeType period) { mPeriod = period; };
    timeType getTime() { return (timeType)(timeGetter()); };
    timeType getPeriod() { return mPeriod; };
    timeType getElapsed() { return getTime() - mPrevTrigger; }
    timeType getRemaining() { return mPeriod - getElapsed(); }
    timeType getLastTriggerTime() { return mPrevTrigger; }
    bool ready() {
        bool isReady = (getElapsed() >= mPeriod);
        if( isReady ) { reset(); }
        return isReady;
    }
    void reset() { mPrevTrigger = getTime(); };
    void trigger() { mPrevTrigger = getTime() - mPeriod; };
    operator bool() { return ready(); }
};
typedef CEveryNTimePeriods<uint16_t,seconds16> CEveryNSeconds;

Its operator bool() returns only once the value true, if the period is elapsed. The first instance of your A receives this true, but never the second instance.

These are the relevant methods, sorted and formatted for better understanding:

    operator bool() {
        return ready();
    }

    bool ready() {
        bool isReady = (getElapsed() >= mPeriod);
        if ( isReady ) {
            reset();
        }
        return isReady;
    }

    timeType getElapsed() {
        return getTime() - mPrevTrigger;
    }

    void reset() {
        mPrevTrigger = getTime();
    }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.