Expectation:
Every time I break the beam between the IR LED and the IR receiver, I expect to get a serial printout. I expect the serial printout only ONCE per change (or my perceived or expected change in the IR signal).
Reality and my issue:
As I cross the IR "line"' with my finger, it seems like my Arduino detects many changes (LOWs to HIGHs) before settling on one. I'm inclined to want to somehow "debounce" this interrupt, where if an interrupt is not temporarily separated enough from the previous interrupt, the ISR is not ran. I think I then need to somehow timestamp the occurrence of the interrupts, but since millis() does not work in an ISR (and micros() is too small for the time differences that I'm interested in) I'm at a loss.
The ISR has a count++ of some sort, then in the void loop () part of the code this count is monitored after a certain amount of time passes between 2 point?
I'm inclined to want to somehow "debounce" this interrupt, where if an interrupt is not temporarily separated enough from the previous interrupt, the ISR is not ran. I think I then need to somehow timestamp the occurrence of the interrupts, but since millis() does not work in an ISR (and micros() is too small for the time differences that I'm interested in) I'm at a loss.
millis() will not change within an interrupt, but the value can be accessed and used for a timestamp to determine a lock out period.
void isrWithLockOut()
{
unsigned long debounceLockOut = 100;//set lock out time
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > debounceLockOut)
{
//execute isr
}
last_interrupt_time = interrupt_time;
}
Quick update: I added a debounce portion, but the serial monitor sometimes shows a couple of back to back "Highs." I have a couple of ideas why this might have happened, and would also greatly appreciate your ideas.
First, you need to learn when and where you need to put semi-colons, and when and where you don't. You have several extra ones in that short snippet of code. Hint: You DON'T need a semi-colon after the closing '}' of any if, for, while, function definition, or any other multi-statement code block.
Second, your de-bounce logic is wrong. You CANNOT properly de-bounce in the ISR. When the bouncing stops, the ISR is no longer called, so how can you use the ISR to determine when the bouncing has stopped?
Look at the code I provided that uses the ISR to tell you WHEN the pin changes state, but uses loop to tell you WHEN the pin has STOPPED bouncing.
debouncing typically looks for a repeated condition after some minimal amount of time. some people just check to see if it's the same value as previously read.
your ISR sets a state regardless of the previous value and only after is just changed. it could be bouncing, but the ISR will likely report the first change without waiting for it to be stable.
wouldn't it be much less complicated to not use an ISR and monitor changes in loop()?
Thank you for the tips, I definitely will change my habit of ';' input. Also I apologize for not looking at your code earlier—my mind totally blanked.
Quick question about my code (just so I know exactly what's wrong with it):
You mentioned that my debounce logic was wrong. I want to articulate my logic here first, and then would really appreciate your feedback on it:
I wanted this to happen: let's say a change is detected on the interrupt pin. Then the ISR is ran. That particular ISR is then time stamped with the millis() function and the value of that is compared with the tDebounce, the time stamp from the last debounced ISR. If this value is less than the debounceDelay, then the ISR is effectively "ignored" we get back to the loop(). Next time the ISR is called, and if millis()-tDebounce is greater than the debounceDelay, the ISR is ran and tDebounce is updated.
I would not use an ISR and just debounce the input like you would a mechanical button. There many examples of button debounce and your code would be a lot simpler.
I want to articulate my logic here first, and then would really appreciate your feedback on it:
Your logic is correct. Accept the first interrupt and lock out anything that follows for a period of time. I don't see any real difference between having the lock out in loop or in the isr itself.
The issue is that you accept the initial interrupt, and do not use a routine which requires a stable signal for a period of time. This makes thing susceptible to "noise" which can generate a interrupt not triggered by the sensor response.
You will need to do some study of your IR sensor, and whether or not you see false triggers with no beam break. If there is a beam break, how long of a signal do you get?
I think you are using a 38KHz modulated sensor and its not clear to me if the output from that unit is well suited to an interrupt.
You code also had the same issue:
15:45:50.511 -> high
15:45:51.131 -> low
15:45:51.759 -> high
15:45:52.351 -> low
15:45:53.195 -> high
15:45:53.753 -> low
15:45:54.581 -> high
15:45:55.213 -> low
15:45:56.636 -> high
15:45:57.235 -> low
15:45:58.225 -> high
15:45:58.609 -> low
15:45:59.239 -> high
15:45:59.587 -> high
15:45:59.872 -> low
15:46:00.370 -> high
15:46:00.515 -> low
15:46:00.923 -> low
15:46:01.410 -> low
15:46:01.689 -> low
15:46:01.934 -> low
15:46:02.070 -> low
15:46:02.529 -> low
15:46:03.494 -> high
15:46:03.667 -> low
15:46:04.672 -> low
15:46:05.748 -> low
15:46:06.754 -> high
15:46:07.059 -> low
15:46:08.556 -> high
15:46:09.006 -> low
15:46:10.754 -> low
15:46:12.282 -> low
15:46:13.324 -> low
15:46:14.093 -> low
15:46:15.238 -> low
15:46:16.095 -> low
15:46:17.984 -> low
15:46:18.536 -> low
15:46:19.048 -> low
15:47:04.624 -> high
15:47:05.042 -> low
15:47:07.004 -> high
15:47:07.364 -> low
15:47:08.643 -> low
15:47:09.718 -> low
If I cross the IR barrier quickly with my finger, it seems like by the time the digitalRead () function is called inside the ISR, the pin state has already gone back to LOW. If I cross the barrier slower, this issue does not happen.