Timer duration changing in strange ways


I have 2 timers defined:

    tp = new Timer (10000, &Tent::displayLightLow, *this, 1);
    tp1 = new Timer (12000, &Tent::displayLightOff, *this, 1);

I start them like this


The first time, they run OK.

But when I start() them again, they run around 2x as long.

And when I start them again, they run much longer.

Maybe it has something to do with me using pointers?

The full code is here.

Does somebody know why this happens?

That’s probably due to your displayBrightness value you are goint into the timer callback.
May be worth checking the value before entering your while(displayBrightness > 30) loop.

Adding some Serial.print() statements for debugging may help locating where the issue happens.

You should also move the timer construction and the attachInterrupt() out of the constructor and rather place that into a Tent::begin() function.

thanks, I did those things, but it didn’t fix it yet.

My updated code is here.

The serial monitoring showed that the timer duration gets longer.

My displayBrightness value is ok.

I’d like to add that this used to work before the 1.0.1 update.

Do you have another idea I could try?

That’s interesting - may need some stripped down test code to see where this behaviour comes from.

But one other thing you should change.
Your dimmerButtonPressed variable should be volatile since you are setting it from within an ISR.
Also using a global variable for classes to communicate isn’t quite the way how it’s meant to be done.

I have stripped down (and slightly altered) your project to only test the timers and that test shows it’s not an issue with SoftwareTimers in 1.0.1 so it must be something with the code that’s not present in my test code anymore

volatile bool dimmerButtonPressed = false;

class Tent {
  uint16_t DIM_PIN;  
  unsigned long lastTime = 0;

  Tent(uint16_t dimPin);
  Timer *tp;
  Timer *tp1;

  void begin(int timeOff = 12000, int timeLow = 10000);
  void setDimButtonPressed();
  void displayLightLow(void);
  void displayLightOff(void);
  bool displayLightHigh(void);

Tent::Tent(uint16_t dimPin) {
  this->DIM_PIN = dimPin;

void Tent::begin(int timeOff, int timeLow) {
  tp  = new Timer(timeLow, &Tent::displayLightLow, *this, 1);
  tp1 = new Timer(timeOff, &Tent::displayLightOff, *this, 1);
  pinMode(this->DIM_PIN, INPUT_PULLUP);
  attachInterrupt(this->DIM_PIN, &Tent::setDimButtonPressed, this, FALLING);

void Tent::setDimButtonPressed() {
  static uint32_t msLast = 0;
  if (millis() - msLast < 100) return; // 100ms debounce
  msLast = millis();
  dimmerButtonPressed = true;

uint32_t msLastLow = 0;  // for debugging
uint32_t msLastOff = 0;  // for debugging

void Tent::displayLightLow(void) {
  Serial.printlnf("tp  LOW: %.1f", (millis() - msLastLow) / 1000.0);

void Tent::displayLightOff(void) {
  Serial.printlnf("tp1 Off: %.1f", (millis() - msLastOff) / 1000.0);

bool Tent::displayLightHigh()
  unsigned long now = millis();
  if ((now - lastTime) >= 15000 || lastTime == 0) {
    lastTime = now;

    msLastLow = msLastOff = millis();    
    Serial.printlnf("tp & tp1 restart at %.1f", millis() / 1000.0);
    return true;
  return false;

Tent tent(D1);  // pass in trigger pin

void setup() {
  pinMode(D7, OUTPUT);  // bridge D7 to your trigger pin (e.g. D1)
  tent.begin(5000, 3000);

void loop() {
  digitalWrite(D7, digitalRead(BTN));  // use SETUP button to drive D7 LOW hence triggering  
  if (dimmerButtonPressed) {
    Serial.printlnf("%s", tent.displayLightHigh() ? "OK" : "too early");
    dimmerButtonPressed = false;

You see I’ve added some more Serial.print() statements in places of interest to see what happens when. You should do the same with your code to see when what action causes what.
I suspect for some reason your code is resetting the timers unexpectedly.

BTW, SYSTEM_MODE() has no business inside the STARTUP() macro.

1 Like

Its working, thank you.

There were I2C calls in another timer callback. They screwed it up.
I placed them in the loop.

And moved SYSTEM_MODE.

Thanks a lot for the help and creating the stripped down version.