2

I wrote a simple Timer class that's designed to work even in the face of the 49 day wrap of the millis() counter. I wanted a library that I could easily re-use and I could never remember the right way of dealing with the wrap-around so I thought: do it once, right. However, it has not gone according to the script!

Here's the source code, header first.

class Timer
    {
public:
    Timer();
    void SetDuration(unsigned long duration);
    bool Expired();
    unsigned long Elapsed();
    unsigned long Remaining();
    void Repeat();
    bool Enabled();
    void Stop();
private:
    unsigned long startedAt;
    unsigned long interval;
    };

...and the implementation...

#include "Timer.h"

Timer::Timer()
    {
    startedAt = 0;
    interval = 0;
    }

/*
 * Sets the timer interval and establishes the reference datum as the instant when this method was called.
 */
void Timer::SetDuration(unsigned long duration)
    {
    startedAt = millis();
    interval = duration;
    }

unsigned long Timer::Elapsed()
    {
    if (!Enabled())
        return 0UL;
    unsigned long elapsed = millis() - startedAt;
    return elapsed;
    }

unsigned long Timer::Remaining()
{
    return interval - Elapsed();
}

bool Timer::Expired()
    {
    return Enabled() ? Elapsed() >= interval : false;
    }

/*
 * Repeats the timer interval but does not reset the reference datum.
 * This should be used when repeatedly timing the same interval, and it is
 * intended that the intervals be consistent _on average_.
 */
void Timer::Repeat()
    {
    startedAt += interval;
    }

bool Timer::Enabled()
{
    return interval > 0;
}

void Timer::Stop()
{
    interval = 0;
}

Now my problem is this. My sketch gets to a certain point then crashes (re-runs from the start). The behaviour seems a lot like an odd stack corruption that's causing the code to branch to Oblivion. I've spent several hours doing a binary-chop on the code to narrow down the cause (it's a big sketch) and much to my surprise, the culprit appears to be the Repeat() method in my timer class. I use it in just one place in my code. When I call the Repeat() method, it crashes my sketch; If I don't call Repeat() but instead call SetDuration(n), the program doesn't crash and everything is fine. I've tried this in two different sketches with consistent results.

I've got spots before my eyes from trying to understand what's happening here. I'm a C# programmer most of the time although I'm not completely new to C and C++, but I've made dumb mistakes in Arduino code before. Repeat() could hardly be simpler or safer code - but is it? Is there anything wrong with my code that I'm just not seeing?

UPDATE: Stack Overflow effect (where you see the solution yourself as soon as you post a question) has kicked in and I've solved it. My implementation of Repeat() was moving startedAt ahead of millis() giving a negative amount of elapsed time (which in unsigned math means a very large positive amount of elapsed time). This was causing immediate time-out of the timer and causing the sketch to think the sky was falling in. So not a memory corruption, just some poorly implemented unsigned math.

closed as unclear what you're asking by Juraj, VE7JRO, sempaiscuba, MatsK, MichaelT Mar 13 at 17:32

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    gets to a certain point what point? how long? Can you provide some code that uses your whatever it is and demonstrates the issue – Jaromanda X Mar 11 at 1:45
  • @JaromandaX Stack Overflow effect (where you see the solution yourself as soon as you post a question) has kicked in and I've solved it. My implementation of Repeat() was moving startedAt ahead of millis() giving a negative amount of elapsed time (which in unsigned math means a very large amount of elapsed time). This was causing immediate time-out of the timer and causing the sketch to think the sky was falling in. – Tim Long Mar 11 at 2:48
  • Indeed - I hate it when MCU's think the sky is falling :p I had similar effect after approximately 50 days when millis "overflows" – Jaromanda X Mar 11 at 4:34
  • 2
    You can answer your own question and accept it. That helps mark it as answered and may help future visitors find the solution to this issue. – ratchet freak Mar 11 at 11:01