ISR set up using FALLING but I still seem to see a few interrupts caused by what must surely be RISING edges

I have a gearmotor with a piece of reflective tape on one of the gears we are trying to use as a crude counter for rotations of that gear. There is a hole in the gearmotor housing with a BTS7960 sensor that reads LOW when the tape is in "view" of the sensor.

I was hoping that setting up the ISR to only trigger on a FALLING edge would eliminate any occurrences of the ISR getting triggered while the tape was still triggering the interrupt. But I still see an occasional HIGH reading - as shown in the Serial Monitor output included below. I tried to write the code to minimize any other triggers such as might be caused by Serial.println(), etc.

Any ideas ?

Here is the code:

const int MOTORSPEED_DEFAULT = 25;  // For Power Wheels gear motor
const int MotorSpeed = MOTORSPEED_DEFAULT;

const int PIN_IR_Digital = 3;
const int PIN_LED = LED_BUILTIN;
int IRvalueD = 0;

const int PIN_PWM_RIGHT = 11; // OUTPUT to motor driver, controls right (clockwise) rotation
const int PIN_PWM_LEFT = 10; // OUTPUT to motor driver, controls left (counter-clockwise) rotation

static int nWriteIt = 0;

void setup()  ///  SETUP 
{
  // Serial communications setup
  Serial.begin(9600);

  attachInterrupt(1, ISR_FALLING, FALLING);
 
  pinMode(PIN_IR_Digital,INPUT);
  pinMode(PIN_LED,OUTPUT);

  pinMode(PIN_PWM_RIGHT,OUTPUT);
  pinMode(PIN_PWM_LEFT,OUTPUT);

  analogWrite(PIN_PWM_RIGHT,0);
  analogWrite(PIN_PWM_LEFT, MotorSpeed);
  Serial.println(__FILE__);
}

void loop()  // LOOP 
{
    if (nWriteIt)
    {
       char buf[100];
       sprintf(buf, " D3 %d", IRvalueD);
       Serial.println(buf);
       nWriteIt = 0;   
    }
}

void ISR_FALLING () 
{
   int D3Reading = digitalRead(3);
   IRvalueD = D3Reading;
   nWriteIt = 1;
}

And the Serial Monitor output:


18:47:18.848 ->  D3 0
18:47:18.848 ->  D3 0
18:47:19.413 ->  D3 0
18:47:19.413 ->  D3 0
18:47:19.965 ->  D3 0
18:47:19.965 ->  D3 0
18:47:20.489 ->  D3 0
18:47:20.535 ->  D3 0
18:47:21.043 ->  D3 0
18:47:21.089 ->  D3 0
18:47:21.607 ->  D3 0
18:47:21.607 ->  D3 0
18:47:22.184 ->  D3 0
18:47:22.184 ->  D3 0
18:47:22.696 ->  D3 0
18:47:22.743 ->  D3 0
18:47:23.262 ->  D3 0
18:47:23.262 ->  D3 0
18:47:23.842 ->  D3 0
18:47:23.842 ->  D3 0
18:47:24.278 ->  D3 0
18:47:24.278 ->  D3 0
18:47:24.366 ->  D3 0
18:47:24.366 ->  D3 0
18:47:24.930 ->  D3 0
18:47:24.930 ->  D3 0
18:47:25.485 ->  D3 0
18:47:25.485 ->  D3 0
18:47:26.016 ->  D3 0
18:47:26.016 ->  D3 0
18:47:26.600 ->  D3 0
18:47:26.600 ->  D3 0
18:47:27.124 ->  D3 1
18:47:27.124 ->  D3 0
18:47:27.699 ->  D3 0
18:47:27.699 ->  D3 0
18:47:28.249 ->  D3 0
18:47:28.249 ->  D3 0
18:47:28.788 ->  D3 0
18:47:28.788 ->  D3 0
18:47:29.363 ->  D3 0
18:47:29.363 ->  D3 0
18:47:29.907 ->  D3 0
18:47:29.907 ->  D3 1
18:47:30.427 ->  D3 0
18:47:30.472 ->  D3 0
18:47:31.007 ->  D3 0
18:47:31.007 ->  D3 0
18:47:31.007 ->  D3 0
18:47:31.541 ->  D3 0
18:47:31.541 ->  D3 0
18:47:32.117 ->  D3 0
18:47:32.117 ->  D3 0
18:47:32.592 ->  D3 0
18:47:32.676 ->  D3 0
18:47:32.676 ->  D3 0
18:47:33.238 ->  D3 0
18:47:33.238 ->  D3 0
18:47:33.766 ->  D3 0
18:47:33.766 ->  D3 0
18:47:34.303 ->  D3 0
18:47:34.303 ->  D3 0
18:47:34.850 ->  D3 0
18:47:34.891 ->  D3 0
18:47:35.437 ->  D3 0
18:47:35.437 ->  D3 1
18:47:35.977 ->  D3 0
18:47:35.977 ->  D3 0
18:47:36.448 ->  D3 0

Can you see the signal and verify it has only one rising and one falling edge per pulse?

Try just counting the pulses, you may be able to see multiple transitions that the ISR picks up.

The ISR could ignore anything for a brief period, too short to miss the next real pulse but long enough to not get trickt by hoisy edges.

Just a thought, blood sugar a bit low now.

a7

1 Like

Don't really have anything to look at actual pulses right now. It sure would be a big help to do so, though! Thanks for the thought!

How fast is the gear turning, and how long do you expect the low period to last?

There are ways other than lock out to filter noise in the isr.

You could use something like this to check for a pulse which lasts longer than 10 ms. Using less delay is better for everything else in the program, but if you really can't eliminate the root cause of the noise it may be worth a try.

void ISR_FALLING () 
{
   delayMicroseconds(10000); //noise filtering
   int D3Reading = digitalRead(3);
  //if D3Reading == 0 accept the interrupt
   IRvalueD = D3Reading;
   nWriteIt = 1;
}

Your sensor seems to bounce. Either you believe that a falling edge definitely had occurred when the ISR was called or only poll the pin and add debounce code. Debouncing in an ISR is a stupid idea.

Please do not post the same problem multiple times! Your sensor has a problem with the tape marks. Start fixing the problem there.

Can I specifiy a Interrupt service routine to trigger only on RISING or FALLING edge without using attachInterrupt() - using the ISR structure below ?

I only want to trigger the interrupt when pin D3 goes LOW due to a piece of reflecting tape inside a gear motor triggering a BTS7960 infrared sensor. Also, I do not want to re-trigger the interrupt while the tape is still causing the sensor to go LOW. The tape has a width of about 1/8 inch so it could remain within "view" of the sensor for a few milliseconds until the gear rotates a couple of degrees.

Portions of my code:

void setup()  ///  SETUP 
{
  // Serial communications setup
  Serial.begin(9600);

  // I2C bus setup
  Wire.begin(I2C);
  Wire.onRequest(requestEvent); // register event
  Wire.onReceive(receiveEvent);

  PCICR |= B00000100;       // Bit2 = 1 -> "PCIE2" enabeled (PCINT16 to PCINT23)
  PCMSK2 |= B00111000;      // D3, D4 or D5 will trigger interrupt (added D3 - JCD)
 
  pinMode(PIN_IR_Digital,INPUT);
  pinMode(4,INPUT);
  pinMode(5,INPUT);
  pinMode(PIN_LED,OUTPUT);

  pinMode(PIN_PWM_RIGHT,OUTPUT);
  pinMode(PIN_PWM_LEFT,OUTPUT);

  analogWrite(PIN_PWM_RIGHT,0);
  analogWrite(PIN_PWM_LEFT, MotorSpeed);
  cnt=1;
  Serial.println(__FILE__);
}

ISR (PCINT2_vect) 
{
   int D3Reading = digitalRead(3); // Really only interested in Pin 3
   int D4Reading = digitalRead(4);
   int D5Reading = digitalRead(5);

   char buf[100];
   sprintf(buf, " D3 %d D4 %d D5 %d", D3Reading, D4Reading, D5Reading );
   Serial.print(interrupt_time);
   Serial.println(buf);
}

My apologies if this is duplicating other post. Surely it has been addressed before ...

Why the requirement not to use attachInterrupt() ?

Your posted code is very rudimentary. It's up to you to decide whether or not to use attachInterrupt(). Do you want to use code found somewhere in the Web or do you want to understand enough to write your own code?

Possible solutions:

  • Use an external interrupt pin instead of D3.
  • Or check the state of D3 in the ISR.

Remove excess digitalRead() and all Serial output from the ISR and set a flag for use in the mainstream code.

TOPIC MERGED.

Could you take a few moments to Learn How To Use The Forum.

Other general help and troubleshooting advice can be found here.
It will help you get the best out of the forum in the future.

BTS7960 is a motor driver, which IR sensor are you using?

Not surprised because:

  • you're printing after every interrupt
  • serial print uses its own interrupt and the print speed is very slow (9600 baud).
1 Like

Whoops - my mistake!
The sensor is a TCRT5000

My apologies for the other post with same problem. I intended to remove it.
thanks for merging it.

Good points. I need to do some more experiment to determine the duration of the gear's rotation.
I'll give the delay a try - I had thought of that but I thought I also read where delayMicroseconds() uses interrupts. Anyway, I will look into it and post what I find here.
Thanks !

Is there a better/different way to check the state of D3 than I did here ?

I am using pin D3 because I found documentation that only pins D2 & D3 can be used for interrupts on the UNO. The board I am constrained to use is a UNO derivative.

thanks again for your help

Many others have had issues with interrupts and these low cost sensors based on lm393 comparators. Performance is often improved with a cap between D0 and ground.

Take a look at this thread
https://forum.arduino.cc/t/solved-falling-and-rising-interrupt-seem-to-behave-the-same-as-change/666236/3

1 Like

Now that is an awesome tip!
Thanks !!!!

You can simply trust the interrupt and believe that D3 had a falling edge and is low now. If you don't trust the interrupt then you should not use it.

Or you replace the slow digitalRead() by a faster direct port access that won't give the signal a chance to bounce back to high again.

That's the line I was also thinking.

At the very first occurence of the falling edge of the interruptng signal at INT1-pin, the INTF1-bit (Fig-1) immediately gets set and triggers the MCU to execute the relevant interrupt service routine (ISR).
fallingEdgeDPin3
Figure-1:

However due to poor coupling between the sensor and the motor gear, the output signal of the sensor might jitter/bounce (low-high-low... and then settle). The slow digitalRead(3) could have sampled DPin-3 while it was at HIGH; but, it does not matter much as the MCU has gone to ISR long ago.

Thanks to both GolamMostafa & DrDiettrich. :grinning:
After reading your responses it caused me to realize that all I really want is to merely get the ISR to be invoked once per rotation of the gear, so that I can update a counter variable. I was worrying about whether the trigger was rising or falling to try to achieve that result. Any suggestions to that end would be appreciated.
Thanks again, very much.