1

I am new to arduino.

Why does this not work the way it's supposed to?
Shouldn't it block all interrupts for 3secs after it received one from digi pin 2?

How would I accomplish this: Running a method whenever the value on this pin changes, execute it and then listen for more interrupts from that pin?

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(2), test, CHANGE);
}

int i = 0;

void loop(){}

void test(){
  noInterrupts();
  Serial.println("Interrupt registered - waiting " + i);
  delay(3000);
  Serial.println("done waiting!" + i);
  i++;
  interrupts();
}
  • What is it doing that it isn't supposed to? I think delay and Serial depend on interrupts being active, you should never disable them globally for an appreciable amount of time. Handlers need to run fast. Also running an interrupt and then continuing to trigger future interrupts is the default behavior. – BrettAM Feb 9 '16 at 19:48
2

You could achieve that by this simple rewrite:

void setup() {
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(2), test, CHANGE);
}

volatile bool changed = false;
int i = 0;

void loop() {
  if (!changed) return;
  Serial.print(F("Interrupt registered - waiting "));
  Serial.println(i);
  delay(3000);
  Serial.print(F("done waiting "));
  Serial.println(i);
  i += 1;
  changed = false;
  clearInterrupt(digitalPinToInterrupt(2));
  attachInterrupt(digitalPinToInterrupt(2), test, CHANGE);
}

void test() {
  changed = true;
  detachInterrupt(digitalPinToInterrupt(2));
}

The interrupt service routine (ISR), test(), is really short and does not call functions that actually need interrupts to work (e.g. delay(), Serial). Please see Nick Gammon's comment below on clearInterrupt(), i.e. EIFR = bit (INTF0);

An alternative rewrite is to use the BlinkWithDelay-pattern and a somewhat more complex state-machine:

volatile bool changed = false;
bool waiting = false;

const unsigned long waitIntervalMillis = 3000UL;
unsigned long waitStartMillis = 0L;

int i = 0;

void setup() {
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(2), test, CHANGE);
}

void loop() {

  // Check for change
  if (!changed) return;

  // Check for change before wait interval
  if (!waiting) {
    Serial.print(F("Interrupt registered - waiting "));
    Serial.println(i);
    waiting = true;
    waitStartMillis = millis();
  }

  // Check if wait interval has expired
  else {
    unsigned long currentMillis = millis();
    if ((currentMillis - waitStartMillis) >= waitIntervalMillis) {
      Serial.print(F("done waiting "));
      Serial.println(i);
      i += 1;
      changed = false;
      waiting = false;
    }
  }
}

void test() {
  changed = true;
}

A third rewrite is possible. Assuming that the pin is connected to a push button, the interrupt handler can be replaced by simply reading the pin with a low frequency (for debouncing).

Cheers!

| improve this answer | |
  • If the switch bounces it will probably register (queue) another interrupt during your delay. I suggest doing EIFR = bit (INTF0); before attaching the interrupt again. See: Interrupts. – Nick Gammon Feb 9 '16 at 22:24
  • This is one of those disturbing things. There was a pull request to fix that nearly two years ago; github.com/matthijskooijman/Arduino/commit/…. It must have broken something else as it was removed/not merged. They could at least added a clearInterrupt(pin) function just for the symmetry of things. Anyway, that is a very good catch! – Mikael Patel Feb 9 '16 at 22:52
  • Once people get used to behaviour (no matter how annoying it might be) it is hard to change it. – Nick Gammon Feb 9 '16 at 22:56
  • why do you need to disable and reenable interrupts at all? – BrettAM Feb 10 '16 at 4:57
  • The question is why use interrupts at all if the signal is generated from a button pushed? In any case, I do agree, it is possible to do yet anther rewrite without attach/detach interrupt. – Mikael Patel Feb 10 '16 at 6:28
1

Probably your biggest problem is that delay() cannot be used inside interrupt service routines (ISR's) and it doesn't work if interrupts are turned off because it uses interrupts to function.

ISR's should be as short as possible, because they stop normal operation of the device while they execute. A good ISR will set a few variables, and then return, while the main program loop checks the state of those variables and actually does stuff. Mikael Patel's answer shows how you can rewrite your sketch to do this.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.