delay() doesn't work as expected when using interrupt

Hello all,

I am puzzled about different behaviour of 'delay()', perhaps anyone has an idea what is wrong.
I'm using Arduino UNO.
delay(2000) shall be used to switch the LED on pin 13 on and off so I have it 2 seconds on, 2 seconds off.

It works with this simple code:

void setup() {    // put your setup code here, to run once:

pinMode(13, OUTPUT);
}

void loop() {    // put your main code here, to run repeatedly:

    digitalWrite(13, HIGH);
    delay(2000);
    digitalWrite(13, LOW);
    delay(2000);

}

But if I try to use an interrupt to let the LED be on for 2 seconds, I only see a short flash (not even a second).

int LedOnTime = 2000;    // LED shall be on for 2 seconds
int LoopDelay = 500;     // something for the loop to do

void setup() {  // put your setup code here, to run once:

  cli();   //stop interrupts

//set timer1 interrupt at 4 Hz
    TCCR1A = 0;// set entire TCCR1A register to 0
    TCCR1B = 0;// set entire TCCR1B register to 0
    TCNT1  = 0;//initialize counter value to 0
    // set compare match register for 4 Hz increments
    OCR1A = 65535;// = (16*10^6) / (4*1024) - 1 (must be <65536)
    // turn on CTC mode
    TCCR1B |= (1 << WGM12);
    // Set CS10 and CS10 bits for 1024 prescaler
    TCCR1B |= (1 << CS12) | (1 << CS10);  
    // enable timer compare interrupt
    TIMSK1 |= (1 << OCIE1A);

    sei();   //allow interrupts

    pinMode(13, OUTPUT);
}


ISR(TIMER1_COMPA_vect) {  //timer1 interrupt 4 Hz toggles pin 13 (LED)

    digitalWrite(13, HIGH);
    delay(LedOnTime);
    digitalWrite(13, LOW);
}
  

void loop() { // put your main code here, to run repeatedly:

    delay(LoopDelay);
}

Increasing the value of LoopDelay doesn't help.
Increasing the value of LedOnTime doesn't do a visible change (5000 still only gives a flash).
Using 'delay(2000)' instead of 'delay(LedOnTime)' makes no difference.

Any idea what I have done wrong?

Thanks in advance for you help,

Volker

Interrupts are turned off in an ISR. Delay() depends on interrupts. See a problem there?

Non-blocking timing tutorials:
Several things at a time.
Beginner's guide to millis().
Blink without delay().

You should never use delay() in an ISR since it doesn't work. A better way to do this would be to count the number of interrupts you have received and then toggle the LED as needed. If you code comments are accurate, your interrupt is every 250 msec and you want the LED to toggle every 2000 msec so that is 8 ticks

ISR(TIMER1_COMPA_vect) {  //timer1 interrupt 4 Hz toggles pin 13 (LED)
    static int ticks = 0;
    if (++ticks >= 8 ) {
      ticks = 0;
      digitalWrite(13, !digitalRead(13));
    }
}

Thanks very much, that helped a lot.
Unfortunately the sources I used to get information about interrupts didn't quote that problems with delay() can be expected.
I'll change to counting the ticks.
I'll also go through the tutorials to improve my knowledge on interrupts and timers.

Best regards, Volker

You could use the avr-libc _delay_ms() function in an isr.
But delaying for “long” times in an isr is not a good thing to do, anyway.

If you could details about your application it is very likely you may not need to use interrupts at all.

vso:
Unfortunately the sources I used to get information about interrupts didn't quote that problems with delay() can be expected.

Note: Inside the attached function, delay() won’t work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function. See the section on ISRs below for more information.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.