Debouncing an ISR within and ISR

Hi all,

Thanks for reading these. Here's the scoop:

Goal: to record the exact time an IR barrier has been crossed and reformed.

Equipment: Arduino Mega, IR LED (toned at 37kHz), IR Receiver (TSOP 38238)

Code:

volatile bool pinState [1][3] = {0, 0, 0};
volatile unsigned long interruptTime [1][3] = {0, 0, 0};
int debounceDelay = 100;
volatile bool pinFlag [1][3] = {0, 0, 0};
int IRPin [1][3] = {2, 3, 19};

void ISRIRCheck0 () {
  if (millis () && (millis () - interruptTime [0][0]) > debounceDelay) {
    pinFlag [0][0] = 1;
    pinState [0][0] = digitalRead (IRPin [0][0]);
    //I will put the SD code stuff here.
  }
}

void ISRIRCheck1 () {
  if (millis () && (millis () - interruptTime [0][1]) > debounceDelay) {
    pinFlag [0][1] = 1;
    pinState [0][1] = digitalRead (IRPin [0][1]);
    //I will put the SD code stuff here.
  }
}

void ISRIRCheck2 () {
  if (millis () && (millis () - interruptTime [0][2]) > debounceDelay) {
    pinFlag [0][2] = 1;
    pinState [0][2] = digitalRead (IRPin [0][2]);
    //I will put the SD code stuff here.
  }
}

void setup () {
  pinMode (12, OUTPUT);
  tone (12, 37000);
  for (int i = 0; i <= 2; i++) {
    pinMode (IRPin [0][i], INPUT_PULLUP);
  }
  Serial.begin (9600);
  attachInterrupt (digitalPinToInterrupt (IRPin [0][0]), ISRIRCheck0, CHANGE);
  attachInterrupt (digitalPinToInterrupt (IRPin [0][1]), ISRIRCheck1, CHANGE);
  attachInterrupt (digitalPinToInterrupt (IRPin [0][2]), ISRIRCheck2, CHANGE);
}

void loop () {
  for (int i = 0; i <= 2; i++) {
    if (pinFlag [0][i] == 1) {
      pinFlag [0][i] = 0;
      Serial.print (i);
      Serial.print ("_");
      Serial.println (pinState [0][i]);
    }
  }
}

Expectation: When I cross the IR barrier with my finger, I expect to get a single reading in the serial monitor. Similarly, when I remove my finger, I also expect to get a single reading in the serial monitor.

Reality: I crossed and reformed the IR barrier across the three IR sensors only once, and have copied and pasted the serial monitor reading below. As you can see, it's not stable.

18:24:28.446 -> 0_1
18:24:28.479 -> 0_0
18:24:28.479 -> 0_1
18:24:28.479 -> 0_1
18:24:28.479 -> 0_0
18:24:28.479 -> 0_1
18:24:28.479 -> 0_0
18:24:28.479 -> 0_1
18:24:28.524 -> 0_1
18:24:28.524 -> 0_1
18:24:29.491 -> 0_0
18:24:29.491 -> 0_1
18:24:29.491 -> 0_0
18:24:29.491 -> 0_1
18:24:29.525 -> 0_0
18:24:29.525 -> 0_1
18:24:29.525 -> 0_1
18:24:29.525 -> 0_0
18:24:29.525 -> 0_1
18:24:29.525 -> 0_0
18:24:29.525 -> 0_1
18:24:29.559 -> 0_1
18:24:29.559 -> 0_0
18:24:29.559 -> 0_1
18:24:29.559 -> 0_0
18:24:31.263 -> 1_1
18:24:31.301 -> 1_0
18:24:31.301 -> 1_1
18:24:31.301 -> 1_1
18:24:31.301 -> 1_0
18:24:31.301 -> 1_1
18:24:31.301 -> 1_0
18:24:31.301 -> 1_1
18:24:31.335 -> 1_1
18:24:31.335 -> 1_0
18:24:31.335 -> 1_1
18:24:31.335 -> 1_0
18:24:31.335 -> 1_1
18:24:31.335 -> 1_1
18:24:31.335 -> 1_1
18:24:32.058 -> 1_1
18:24:32.058 -> 1_1
18:24:32.058 -> 1_0
18:24:32.058 -> 1_1
18:24:32.058 -> 1_1
18:24:32.058 -> 1_0
18:24:32.058 -> 1_1
18:24:32.092 -> 1_1
18:24:32.092 -> 1_0
18:24:32.092 -> 1_1
18:24:32.092 -> 1_0
18:24:32.092 -> 1_0
18:24:32.092 -> 1_1
18:24:32.128 -> 1_1
18:24:32.128 -> 1_0
18:24:32.128 -> 1_1
18:24:32.128 -> 1_0
18:24:32.128 -> 1_0
18:24:33.802 -> 2_1
18:24:33.802 -> 2_0
18:24:33.802 -> 2_1
18:24:34.535 -> 2_0
18:24:34.535 -> 2_1
18:24:34.535 -> 2_1
18:24:34.535 -> 2_1
18:24:34.572 -> 2_1
18:24:34.572 -> 2_0
18:24:34.572 -> 2_1
18:24:34.572 -> 2_0

Now, the question might be why am I trying to debounce the interrupt within the ISR. My final code is going to be lengthy, and so if the goal is to record the exact timing of the IR changes, I can't rely on a flag and an in-loop() debounce.

Please let me know if I need to add anything else. Thank you again.

What you need to do is fix the hardware, so you get clean transitions. How can you possibly capture "exact timing" if the signal is bouncing all over the place?

Use a digital sensor, or add hysteresis. Something as simple as a Schmitt trigger buffer might be enough.

Regards,
Ray L.

Thanks for your response. My IR sensor is digital, though here's the thing:

If I hold my finger at just the right location, I see the following in the serial monitor (simple analog read of the signal pin):

19:52:10.168 -> 12
19:52:10.168 -> 13
19:52:10.202 -> 13
19:52:10.202 -> 18
19:52:10.202 -> 13
19:52:10.202 -> 13
19:52:10.202 -> 14
19:52:10.202 -> 17
19:52:10.202 -> 1022
19:52:10.202 -> 18
19:52:10.202 -> 18
19:52:10.237 -> 18
19:52:10.237 -> 17
19:52:10.237 -> 13
19:52:10.237 -> 1022
19:52:10.237 -> 14
19:52:10.237 -> 13
19:52:10.237 -> 13
19:52:10.274 -> 18
19:52:10.274 -> 1022
19:52:10.274 -> 17
19:52:10.274 -> 18
19:52:10.274 -> 18
19:52:10.274 -> 18
19:52:10.274 -> 17
19:52:10.274 -> 17
19:52:10.274 -> 13
19:52:10.310 -> 1022
19:52:10.310 -> 1022
19:52:10.310 -> 13
19:52:10.310 -> 13
19:52:10.310 -> 14
19:52:10.310 -> 16
19:52:10.310 -> 18
19:52:10.343 -> 18
19:52:10.343 -> 18
19:52:10.343 -> 18
19:52:10.343 -> 17
19:52:10.343 -> 12
19:52:10.343 -> 13
19:52:10.343 -> 1022
19:52:10.343 -> 1022
19:52:10.389 -> 13
19:52:10.389 -> 1022
19:52:10.389 -> 1021
19:52:10.389 -> 16
19:52:10.389 -> 18

So quick changes between highs and lows. Are you perhaps aware of any filters that would, let's say, look at a population of "interrupt signals" (maybe 5 instances) so see what proportion of the signals are high vs low, and then "adjudicate" the final output (for example, only if all 5 signals were high would the final output be counted as high)?

It won't be as precise time wise, but it might be just precise for my application.

Perhaps you could treat the first interrupt as valid, then, while still inside the ISR, disable the interrupt and clear any interrupt flags. Leave a flag for your main loop which would signal it to poll the value of the interrupt pin until it settles down, and only then re-enable the interrupt to allow another transition.

But I think your problem may be that the IR receiver you're using isn't just an IR phototransistor. It's an IR 38K demodulator normally used in remote controls, and not in breaking-the-beam situations like yours. You might do better with plain non-modulated IR at both ends - an IR LED and an IR phototransistor. Then a normal R/C filter would work, but might not even be needed.