1

I have a sketch simulating a bicyle tail light. When I click button, led starts blinking. When I click again, it stops blinking.

If I turn blinking on and off without taking too long, everything works fine. However, if I let the blinking off for more than a few dozens of seconds, the next time I press the button it takes lots of seconds for the led to start blinking again.

I cannot imagine why this should happen. I thought about millis() rollover, but that would take more than a few days, wouldn't it?

Any clue? Code is below:

const int timeLedOn = 20;
const int timeLedOff = 7 * timeLedOn;


const int ledPin =  8;

int buttonLevel = LOW;
int previousButtonLevel = LOW;

int ledState = LOW;

bool blinkingTurnedOn = false;

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;

volatile unsigned long lastMicros;
long debouncingTime = 1000 * 200;


void setup() {
  // use interrupt 0 (pin 2) for 
  attachInterrupt(0, debounceInterrupt, RISING);

  pinMode(ledPin, OUTPUT);  

  // disable onboard led
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);    

  // turn led off
  digitalWrite(ledPin, LOW);
}



void loop() {
  currentMillis = millis();

  if (blinkingTurnedOn) {
    performBlinking();
  }
  else {
    digitalWrite(ledPin, LOW);
  }
}

void debounceInterrupt() {
  if ((long)(micros() - lastMicros) > debouncingTime) {
    toggleBlinking();
  }
  lastMicros = micros();
}

void toggleBlinking() {
    blinkingTurnedOn = !blinkingTurnedOn;  
}

void performBlinking() {
    int timeDelta = currentMillis - previousMillis;

    // check if time "off" elapsed
    bool elapsedOff = ledState == LOW && timeDelta > timeLedOff;

    // check if time "on" elapsed
    bool elapsedOn = ledState == HIGH && timeDelta > timeLedOn;

    // blinking itself
    if (elapsedOff || elapsedOn) {
      toggleLedState();
    }  
}

void toggleLedState() {  
  ledState = 1 - ledState;
  digitalWrite(ledPin, ledState);
  resetMillis();  
}

void resetMillis(){
  previousMillis = currentMillis; 
}
heltonbiker
  • 26,657
  • 28
  • 137
  • 252

1 Answers1

2

I suspect the reason for the delay may be that the blinkingTurnedOn flag is not marked as volatile (in the same way as the lastMicros variable). Since it is changed (indirectly) from within an interrupt its new value may not be immediately visible to the code called from loop() without the volatile modifier to tell it to always read the value from memory (rather than assuming the current value in a register is up-to-date). Arduino reference.

Changing the declaration to:

volatile bool blinkingTurnedOn = false;

should fix the problem.

Matthew Murdoch
  • 30,874
  • 30
  • 96
  • 127
  • Now the code appears to be working. The exact paragraph supporting your answer, and very pertinent to my code by the way, says "A variable should be declared volatile whenever its value can be changed by something beyond the control of the code section in which it appears, such as a concurrently executing thread. In the Arduino, the only place that this is likely to occur is in _sections of code associated with interrupts_, called an interrupt service routine." Thank you very much! – heltonbiker Apr 03 '15 at 02:13