Rpm not going to zero

I’m using some code that i found here somewhere (thanks to whoever wrote this) for reading rpm on an input. It seems to be working fine except when i remove the input the output in the serial monitor doesn’t drop to zero.
Am i missing something obvious?

The input signal is generated using tone from another arduino

int rpm = 0;
const int DispSampleTime = 200;               //[millisec] //= 0.1sec 
volatile unsigned long lastTime;
volatile unsigned long thisTime;
volatile unsigned long duration;

unsigned long disp_timeold = 0UL;
unsigned long timetemp = 0UL;

volatile uint32_t rev; // Revolution Count
unsigned long measureTime = 0;


void setup() {
Serial.begin(9600);
attachInterrupt(0, rpm_interrupt, FALLING);
}

void loop() {
// DISPLAY RPM
  timetemp = millis() - disp_timeold;
  if( timetemp >= DispSampleTime) 
   {
    disp_timeold += timetemp;
    
    rpm = 60e6/duration;  // 60.000.000 micros / duration in micros
   }
Serial.print("RPM");  // prints RPM value
Serial.println(rpm);
}
void rpm_interrupt() 
{
  lastTime = thisTime;
  thisTime = micros();
  duration = thisTime-lastTime;
}

Edit: There is a pullup through a 10k resistor on the input

And the input is on pin 0.

Try it on a pin like 2 or 3 or 4, at least not 0 and 1 which might be the prob.

The input signal is generated using tone from another arduino

Nice trick for development purposes!

a7

Obviously you are using interrupt at pin0. If you disconnect the input, the interrupt function rpm_interrupt() is not called, the value of duration is not changed.
On the other hand, how do you want to get zero if rpm = 60e6/duration? What duration need to be to get rpm = 0?
You can add one more check: if the timetemp is longer than for example 1 second, simply print 0.

Hello
the sketch is doing exately what it be. The variable duration contains the last time measured.
I did made some mods to your sketch wrt the mentioned variable. Test it. It´s untestet and uncompiled.

int rpm = 0;
const int DispSampleTime = 200;               //[millisec] //= 0.1sec
volatile unsigned long lastTime;
volatile unsigned long thisTime;
volatile unsigned long duration;
unsigned long disp_timeold = 0UL;
unsigned long timetemp = 0UL;
volatile uint32_t rev; // Revolution Count
unsigned long measureTime = 0;
void setup() {
  Serial.begin(9600);
  attachInterrupt(0, rpm_interrupt, FALLING);
}
void loop() {
  // DISPLAY RPM
  timetemp = millis() - disp_timeold;
  if ( timetemp >= DispSampleTime)
  {
    disp_timeold += timetemp;
    if (!duration) {
      rpm = 60e6 / duration; // 60.000.000 micros / duration in micros
      duration = 0;
    } else rpm = 0;
  }
  Serial.print("RPM");  // prints RPM value
  Serial.println(rpm);
}
void rpm_interrupt()
{
  lastTime = thisTime;
  thisTime = micros();
  duration = thisTime - lastTime;
}

Yes, duration is not changed in the original if the ISR is not triggered. Here, however, I think the test should be

   if (duration) {

?

a7

Interrupt 0 is on pin 2 of the Arduino Uno. What Arduino are you using?

that was the task for the TO to find this :slight_smile:

Haha, of course it is. THX!

That’s why you’ll see

 digitalPinToInterrupt(pin)

used sometimes, which would have keep me on track.

a7

Hi,

What happens if you gnd the open circuit input pin?
Good that you have a 10K pullup on it. :+1:

Tom… :grinning: :+1: :coffee: :australia:

Yep used map () and a pot to give the range I wanted, works nicely.

I have no idea how to quote with this new forum. Should have mentioned in the first post it was a nano, so interrupt 0 is pin 2.
The solution was what paulpaulson posted, with ‘if (duration)’ as pointed out by alto777.
Here’s the working code. Gives a clean output with minimal accuracy loss and no massively long delays.

int rpm = 0;
const int DispSampleTime = 200;               //[millisec] //= 0.1sec
volatile unsigned long lastTime;
volatile unsigned long thisTime;
volatile unsigned long duration;
unsigned long disp_timeold = 0UL;
unsigned long timetemp = 0UL;
volatile uint32_t rev; // Revolution Count
unsigned long measureTime = 0;
void setup() {
  Serial.begin(9600);
  attachInterrupt(0, rpm_interrupt, FALLING);
}
void loop() {
  // DISPLAY RPM
  timetemp = millis() - disp_timeold;
  if ( timetemp >= DispSampleTime)
  {
    disp_timeold += timetemp;
    if (duration) {
      rpm = 60e6 / duration; // 60.000.000 micros / duration in micros
      duration = 0;
    } else rpm = 0;
  }
  Serial.print("RPM");  // prints RPM value
  Serial.println(rpm);
}
void rpm_interrupt()
{
  lastTime = thisTime;
  thisTime = micros();
  duration = thisTime - lastTime;
}

Did you try selecting some text in the post that you were replying to ?

I did this time haha thanks, I’m used to the older style where you click the button