Port interrupt gets called multiple times (RPM)

Hey there,

I allready posted another thread regarding this project but the question evolved so I make a new one. Thanks to the people who got me where I am now project wise :wink:

Im using this sensor: TCRT5000 IR Barrier Sensor

My code (simplified, the code is much longer):

unsigned long rpmLastReading = 0;
volatile unsigned int rpmSensorPulses = 0;
unsigned int rpm = 0;

void setup()
{
    interruptPin(9);
}

void loop()
{
   getRPM();
}

void interruptPin(byte pin)
{
    *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
    PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
    PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}

unsigned int getRPM()
{
  if (millis() - rpmLastReading > 1000)
  {
    unsigned int dTime = millis() - rpmLastReading;
    noInterrupts();
    unsigned int sPulse = rpmSensorPulses; 
    rpmSensorPulses = 0;
    interrupts(); 
    rpm = sPulse * 30 * dTime/1000.0;
    rpmLastReading = millis();
    Serial.println(rpm);
  }
  return rpm;
}

ISR (PCINT0_vect)
{    
   rpmSensorPulses++; 
}

Wiring is simple: D0 (digital out of sensor) -> Pin 9 on Arduino
D0 is LOW when a black stripe is before the sensor otherwise its HIGH.

I need to get the PORT interrupt because I need an encoder simultaniously and its works like a charm on the external pins 2 & 3.

I adjusted the poti on the sensor accordingly and it works like a charm. I checked the value with the help of an anlaog reading of the sensor ( approx. 50 when "white", 600 when "black") -> the sensor has also an analog output besides the digital output. I know the sensor pulses on every change. Not rising or falling edge. Every time the black stripe gets by, there should be 1 pulse and when the black stripe leaves there should be another pulse. So each revolution has 2 pulses.

  • Unfortunately the ISR gets called multiple times and it varies between 6 - 10 pulses for each change event. I check via Serial.print(). Is it possible to get a clean reading?

  • Furthermore I get sort of RPM readings (approx. 60RPM) on very low speeds. If it goes higher the rpm drops to 0. Any ideas why?

You are probably experiencing a floating pin issue. Connect a resistor from the interrupt pin to ground, to pull the pin LOW when the stripe is nowhere in sight. 10K should work.

Wiring is simple: D0 (digital out of sensor) -> Pin 9 on Arduino
D0 is LOW when a black stripe is before the sensor otherwise its HIGH.

PaulS:
You are probably experiencing a floating pin issue. Connect a resistor from the interrupt pin to ground, to pull the pin LOW when the stripe is nowhere in sight. 10K should work.

@PaulS Other way around.
The interrupt pin needs a pull up resistor to 5v for when there is no stripe. again 10K should work.

In case anyone is wonder, the datasheet calls these "pin change" interrupts, not port interrupts. There
is/are library(s) to manage these I believe.

Thanks guys!

It seems to work now. My poor mans dso shows me some missed pulses but at max speed I get a reading of 3300 RPM and the motor is rated 3000 so thats good enough for me.
I think now its a matter of adjusting the sensor sensitivity, distance and the black bar.

I also changed the code to

rpm = sPulse * 30; // * dTime/1000.0; removed this part

gives me better results. Dont know why.

As a goody... the action attached. :wink:

Best and thanks all for your help.

gives me better results. Dont know why.

Here's a clue:

    unsigned int dTime = millis() - rpmLastReading;

What type does millis() return? What type is rpmLastReading? What type SHOULD dTime be?