Understanding Interrupts

I have made a simple traffic light sketch, and I wanted to test interrupts. I should mention that this is using the arduino as ISP programming an ATTiny85. I have included an interrupt sub-routine, however, when the ISR runs I only get about half the delay time (5 seconds instead of 10 seconds). I don't understand why and was wondering if I am missing something.

The code is below

const int greenLED = 3;
const int yellowLED = 4;
const int redLED = 0;
const int button1 = 1;

const unsigned long interval = 1000;
unsigned long previousMillis;

void setup() {
  noInterrupts();
  pinMode(greenLED, OUTPUT);
  pinMode(yellowLED, OUTPUT);
  pinMode(redLED, OUTPUT);
  interrupts();
  attachInterrupt(0, Interrupt, FALLING);
}

void greenLight(void)  {
    digitalWrite(greenLED, HIGH);
    digitalWrite(yellowLED, LOW);
    digitalWrite(redLED, LOW);
}

void yellowLight(void)  {
  digitalWrite(greenLED, LOW);
  digitalWrite(yellowLED, HIGH);
  digitalWrite(redLED, LOW);
}

void redLight(void) {
  digitalWrite(greenLED, LOW);
  digitalWrite(yellowLED, LOW);
  digitalWrite(redLED, HIGH);
}

void redYellowLight(void)  {
  digitalWrite(greenLED, LOW);
  digitalWrite(yellowLED, HIGH);
  digitalWrite(redLED, HIGH);
}

void Interrupt(void)  {
  noInterrupts();
  digitalWrite(greenLED, LOW);
  digitalWrite(yellowLED, LOW);
  digitalWrite(redLED, LOW);
  delay(10000);
  interrupts();
}

void loop() {
  
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis < (5 * interval)) {
     greenLight();
  }
  if((currentMillis - previousMillis >= (5 * interval)) && (currentMillis-previousMillis < (7 * interval))) {
     yellowLight();
  }
  if((currentMillis - previousMillis >= (7 * interval)) && (currentMillis - previousMillis < (12 * interval))) {
     redLight();
  }
  if((currentMillis - previousMillis >= (12 * interval)) && (currentMillis - previousMillis < (14 * interval))) {
     redYellowLight();
  }
  if(currentMillis - previousMillis >= (14 * interval))  {
     previousMillis = currentMillis;
  }
}

When you were investigating interrupts, did you miss the bit about delay() doesn't work in interrupts?

Rule 1 of interrupts, they should be as quick as possible. Adding a delay doesn't make it short...

Aside from the fact that it simple won't work right, using delay() in an interrupt handler completely defeats the purpose of an interrupt. Interrupt handlers should do as little as possible, then return. You should never do time-consuming operations, most especially time-wasting operations like delay(), in an interrupt handler.

Regards,
Ray L.

Ahh, thanks...now that you mention it I think I may have read that before. I will re-think my strategy for the delay :slight_smile:

Actually, I just threw the delay in there very lazily to enable me to see the interrupt working, as I have never used an interrupt before. Then I was confused as to why the timing was wrong.

After a little bit of experimentation I realized that interrupts don't seem to handle millis() either (obviously taking up too much time as well) .

So my question is;

Can I use interrupts to run a segment of code that will take some time to perform?....in this case, I want to use interrupts to stop the normal sequential program and switch everything off for a 10 seconds.

Can I use interrupts to run a segment of code that will take some time to perform?..

Flag the fact that the interrupt has occurred and do your waiting elsewhere in the program using millis(), or don't use an interrupt at all.

Thank you,

I have used a boolean case to acheive this and it has worked well. I'm hoping this way of thinking will come a little bit easier with more practice :slight_smile:

See Nick Gammon's interrupt tutorial

...R

delay() will hang indefinitely if called in an ISR because it waits for other interrupts
to happen, but they cannot because interrupts are already disabled due to being inside
the first ISR...

For the same reason you cannot call Serial methods.

Basically if your ISR takes longer than 100us, think again...