Hi Community,
I'm getting inconsistent results with a small non-blocking interval timer function when using multiple instances of it within a sketch. Rather than rewrite the same piece of code at the start of every function that requires an interval between actions, I wrote a small function intervalTimer() which returns true or false. I've seen this general method documented many times, but I can't find a specific example that answers why I'm getting inconsistent results. I've tried it on various Uno and Nano boards with the same type of error.
The desired output is all three messages printed every second, but the output shows only one message being printed each second. Which message is printed seems random, causing some functions to have an actual interval multiple times the desired interval.
I wonder if this is a memory issue as the interval timer function works perfectly when only called by one function. My understanding is that each time this function is incorporated within another function, a new memory space is allocated for the local static variables, but I'm starting to think I've misunderstood this, given the output.
I would really appreciate if someone could explain why I'm seeing this behaviour and offer a recommendation for an alternative that isn't just repeating code. I had thought about creating the interval function within a class to allow for multiple timer objects, but I wanted to try and understand what's happening here first so I can apply this learning to other projects.
Full code:
// call timer function at the begining of a function with an 'if not, return' statement.
bool intervalTimer(uint16_t interval /*milliseconds*/)
{
// last trigger marker.
static uint32_t lastTriggerMk;
// read current time.
uint32_t currentTime = millis();
// has interval elapsed?
if (currentTime - lastTriggerMk < interval)
{
// no, exit false.
return false;
}
// yes, reset last trigger mark to current time.
lastTriggerMk = currentTime;
// exit true.
return true;
}
// prints a message when function is triggered, along with how long sinse it was last triggered.
void functionOne()
{
if (!intervalTimer(1000))
{
return;
}
static uint32_t lastMillis;
uint32_t currentMillis = millis();
uint16_t actualInterval = currentMillis - lastMillis;
lastMillis = currentMillis;
Serial.print(F("Function 1 triggered. Interval: "));
Serial.println(actualInterval);
Serial.println(F("--------"));
}
// prints a message when function is triggered, along with how long sinse it was last triggered.
void functionTwo()
{
if (!intervalTimer(1000))
{
return;
}
static uint32_t lastMillis;
uint32_t currentMillis = millis();
uint16_t actualInterval = currentMillis - lastMillis;
lastMillis = currentMillis;
Serial.print(F("Function 2 triggered. Interval: "));
Serial.println(actualInterval);
Serial.println(F("--------"));
}
// prints a message when function is triggered, along with how long sinse it was last triggered.
void functionThree()
{
if (!intervalTimer(1000))
{
return;
}
static uint32_t lastMillis;
uint32_t currentMillis = millis();
uint16_t actualInterval = currentMillis - lastMillis;
lastMillis = currentMillis;
Serial.print(F("Function 3 triggered. Interval: "));
Serial.println(actualInterval);
Serial.println(F("--------"));
}
// runs all 3 test functions in a loop.
void testOne()
{
functionOne();
functionTwo();
functionThree();
}
//////// //////// //////// //////// //////// //////// //////// ////////
void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
}
void loop()
{
// put your main code here, to run repeatedly:
testOne();
}
//////// //////// //////// //////// //////// //////// //////// ////////
Serial Output:
[Starting] Opening the serial port - COM4
Function 3 triggered. Interval: 1000
--------
Function 3 triggered. Interval: 1000
--------
Function 3 triggered. Interval: 1000
--------
Function 3 triggered. Interval: 1000
--------
Function 3 triggered. Interval: 1000
--------
Function 3 triggered. Interval: 1000
--------
Function 3 triggered. Interval: 1000
--------
Function 3 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 9000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 2 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 25000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 1 triggered. Interval: 1000
--------
Function 3 triggered. Interval: 37000
--------
Function 1 triggered. Interval: 2000
--------
Function 3 triggered. Interval: 2000
--------
Function 1 triggered. Interval: 2000
--------
[Done] Closed the serial port
Thanks in advance for any help! Tom