We debounce dirty signals like contact switches closing and opening (tiny sparks) which you won't get with reflected IR.
The OP's problem is not due to the nature of the reflected IR but with the behavior of the lm 393 comparator ( used in the circuit without feedback )which is processing the signal from the IR receiver photo transistor.
The constant detachment and reattchment of the interrupt is not correct. Attach it only once in setup and use the noInterrupts() and interrupts() calls to pull unchanging data from the isr.
Here is a cleaner form of the code to read a period of time for a number of pulses.
volatile byte count = 0;
byte numCount = 50;
volatile unsigned long startTime;
volatile unsigned long endTime;
unsigned long copy_startTime;
unsigned long copy_endTime;
volatile boolean finishCount = false;
float period;
unsigned int rpm = 0;
void setup()
{
Serial.begin(115200);
Serial.println("start...");
attachInterrupt(digitalPinToInterrupt(3), isrCount, FALLING);//interrupt on pin3
}
void loop()
{
if (finishCount == true)
{
finishCount = false;//reset flag
// disable interrupts, make protected copy of time values
noInterrupts();
copy_startTime = startTime;
copy_endTime = endTime;
interrupts();
period = (copy_endTime - copy_startTime) / 1000.0;//micros to millis
Serial.println(period);//debug
rpm = numCount * 30.0 * (1000.0 / period);//two ccounts per revolution
Serial.print("RPM = ");
Serial.println(rpm);
}
}
void isrCount()
{
count++;
if (count == 1)//increments on first entry to isr
{
startTime = micros();
}
if (count == numCount)
{
endTime = micros();
finishCount = true;
count = 0;
}
}