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;
}
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.
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 ...
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.
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.
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.
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).
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.
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.