Counter Help with Time Period Change

Here is a counter, that has a time period of every 60 seconds. every 60 seconds it does something.However on the first iteration of the counter only i want it to do the some of TimePeriod-LastCellNumber i.e it counts 40 seconds. Currently it does this fine on the first iteration but how would i then make the change from the 40 second interval to the 60 second interval. In reality the 20s interval (LastCellNumber) is reading from EEPROM but this simulates my issue nicely.

boolean ReadActivationStartTime = false;
unsigned long elapsed;
unsigned long StartTime =0;
unsigned long TimePeriod = 60000;
unsigned long LastCellNumber =20000;
 
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  myDelay();
//Serial.println("in void loop");
}
void myDelay() {
  //Serial.println("in mydelay");
   if (ReadActivationStartTime == false)
        {
          ReadActivationStartTime = true;
          StartTime = millis();

        }
       
        unsigned long now = millis();         // now: timestamp
        elapsed = now - StartTime;
        unsigned long elapsed2 = 4294967295 - StartTime + now;// elapsed: duration if roll over
        unsigned long AdjustedTimePeriod = TimePeriod - LastCellNumber;
        Serial.println("Now");
        Serial.println( now);
        Serial.println("Elapsed");
        Serial.println( elapsed);
        Serial.println("LastCellNumber");
        Serial.println( LastCellNumber);
        Serial.println(" AdjustedTimePeriod");
        Serial.println( AdjustedTimePeriod);
        if (StartTime < now && elapsed >= AdjustedTimePeriod)                    // comparing durations: OK
        {
          Serial.println("Do something here");
          ReadActivationStartTime = false;         
        }
}
1 Like

Like this?
( I thought the LastCellNumber will be not used for something else later. )

unsigned long TimePeriod = 60000;
unsigned long LastCellNumber = 20000;
void setup() {
  Serial.begin(9600);
  Serial.println("Start sketch");
  /* Please add EEPROM reading code at this line. */
}
void loop() {
  myDelay();
}
void myDelay() {
  static unsigned long StartTime = 0;
  unsigned long now = millis();
  if (now - StartTime < TimePeriod - LastCellNumber) return;
  LastCellNumber = 0;
  StartTime = now;
  myTask();
}
inline void myTask() {
  Serial.println("Do something here");
}
1 Like

to start with thankyou that did exactly what i was after, and i have never heard of a static variable before, so that has just opened up my code to being much shorter and easier to follow so thanks. Whilst i think i follow the logic or declaring them globally and changing after first use (which is what i need), why is there a return here?

if (now - StartTime < TimePeriod - LastCellNumber) return;

The this "if" instruction is execute completed in one line.
Because it doesn't have a scope block with braces.
return will be executed when if the calclated elapsed time is less than the period.
Therefore the myDelay function will be exited immediately.

That is when the elapsed time exceeds the period, first time it execute code after "if".
:exclamation:Note: Attention to the orientation of the comparison operator.
Well, it's the same result even if you write it in braces... :grin:

unsigned long TimePeriod = 60000;
unsigned long LastCellNumber = 20000;
void setup() {
  Serial.begin(9600);
  Serial.println("Start sketch");
  /* Please add EEPROM reading code at this line. */
}
void loop() {
  myDelay();
}
void myDelay() {
  static unsigned long StartTime = 0;
  unsigned long now = millis();
  if (now - StartTime >= TimePeriod - LastCellNumber) {
    LastCellNumber = 0;
    StartTime = now;
    Serial.println("Do something here");
  }
}

ok that helped clear things up though i am definitely more familiar with the latter method. So given that knowledge i attempted to try put 2 different timing periods into the same void function. I generally use 2 different void functions to do this however i was curious if it could be done in 1. below is an attempt at such, however it works for timer 1, however 20 seconds later (ant timer2 not activating) everything goes wrong. any suggestions? can it be done? should it be done?

unsigned long TimePeriod = 60000;
unsigned long TimePeriod2 = 10000;
unsigned long LastCellNumber = 20000;
void setup() {
  Serial.begin(9600);
  Serial.println("Start sketch");
  
}
void loop() {
  myDelay();
}
void myDelay() {
  static unsigned long StartTime = millis();
  unsigned long now = millis();
  if (now - StartTime >= TimePeriod - LastCellNumber){
    LastCellNumber = 0;
    myTask();
  }
   if (now - StartTime >= TimePeriod + TimePeriod2 - LastCellNumber){
    LastCellNumber = 0;
    StartTime = now;
    myTask2();
  }
  }

void myTask() {
  Serial.println("-----------------------Timer 1 Complete-------------------");
  }
  
  void myTask2() {
  Serial.println("-----------------------Timer 2 Complete-------------------");
  }

Timers with different intervals must even have different start values.
Like this.

unsigned long TimePeriod1 = 5000;
unsigned long TimePeriod2 = 2000;
unsigned long LastCellNumber1 = 4000; // The mean of the "1" is to make it clear that it applies to Period1.
void setup() {
  Serial.begin(9600);
  Serial.println("Start sketch");
}
void loop() {
  myDelay();
}
void myDelay() {
  static unsigned long StartTime1 = 0;
  static unsigned long StartTime2 = 0;
  unsigned long now = millis();
  if (now - StartTime1 >= TimePeriod1 - LastCellNumber1) {
    StartTime1 = now;
    LastCellNumber1 = 0;
    myTask1();
  }
  if (now - StartTime2 >= TimePeriod2) {
    StartTime2 = now;
    myTask2();
  }
}
inline void myTask1() {
  Serial.println("-- Task1 Done. --");
}
inline void myTask2() {
  Serial.println("-- Task2 Done. --");
}

However... It's a little difficult, but...
I like to use array because add the number of tasks as so much easy.

I'll hide it. Click to expand.
#define MAX_TASK_NUM 3

unsigned long StartTime[MAX_TASK_NUM];
unsigned long TimePeriod[MAX_TASK_NUM];
unsigned long LastCellNumber[MAX_TASK_NUM];
typedef void (*taskPointer)();

inline void myTask0() {
  Serial.println("--+-- Task1 Done --+--");
}
inline void myTask1() {
  Serial.println("-+-+- Task2 Done -+-+-");
}
inline void myTask2() {
  Serial.println("-+++- Task3 Done -+++-");
}

taskPointer doMyTask[] = {
  myTask0,
  myTask1,
  myTask2
};

void setup() {

  TimePeriod[0] = 5000;
  TimePeriod[1] = 2000;
  TimePeriod[2] = 10000;

  LastCellNumber[0] = 1000;
  LastCellNumber[1] = 0;
  LastCellNumber[2] = 9000;

  Serial.begin(9600);
  Serial.println("Start sketch");
}

void loop() {
  myDelay();
}

void myDelay() {
  unsigned long now = millis();
  for (byte b = 0; b < MAX_TASK_NUM; b++) {
    if (now - StartTime[b] >= TimePeriod[b] - LastCellNumber[b]) {
      StartTime[b] = now;
      LastCellNumber[b] = 0;
      (doMyTask[b])();
    }
  }
}

:wink:

I just noticed. :bulb:

I thought the timers were in parallel, but is that need a series?
For example, when there are timers of 60 seconds and 20 seconds.

60sec -> 20sec -> 60sec -> 20sec -> ...

It mean above? If so, the code needs to be modified.

In the code I posted, the timers run in parallel.

60sec -------------------> 60sec ----------- ...
20sec -> 20sec -> 20sec -> 20sec -> 20sec -> ...

again wow! thank you! But i got a final question that may test your abilities. i am using 2 timers so i can call timer 1 then continue in my state-machine, which activates the second timer in my void loop to then do "whatever action".

I think its better to use 2 separate timers (at least to my understanding of coding) but i'll ask anyway. If i need on Time period 1 to continue in my state-machine, time period 2 will never activate. Is there a way to do it so at time interval 1 my state machine will continue but still have it check to see if timer 2 is complete? I cant see a logical way personally however you have impressed me so I'm kind of curious if you know another technique i don't.

Also yes its in series and thanks all modified

What I lack seems to be reading comprehension, not coding skills. :roll_eyes:
I think you can clearly see the expected conditions in your mind, but you didn't clearly informed me.
Can you explain the timer conditions with a image?
Yes, funny handwriting is especially good. :pencil2:
Finaly, I'm sure the it I can write to code. :wink: