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);
}
asked Nov 28, 2022 at 20:03
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 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();
 }
answered Nov 29, 2022 at 7:07

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.