Speedometer interrupt counter going higher than expected

Hi Guys,
Basically I want to use a REED switch to build a speedometer for my e-bike. The way I do it is everytime a FALLING signal is detected, the interrupt is triggered and records the time (millis), until a counter reaches three iterations. Once these are reached the time difference between the last two interrupts is calculated and the interrupt pin is deactivated using detachInterrupt. The problem I am getting is that my counter always overshoots 3, I can’t manage to make it stop and reset to 0.
Here are the relevant parts of my code:

#include <LiquidCrystal_I2C.h>
#include <Wire.h> 
#include <EEPROM.h>
[...]
volatile int ispeedo;
volatile long pulse1 = 0, pulse2 = 0, timesp=0;

void speedometer() {
long sensecst=2073;//mm
if (ispeedo==3) {
  velocity=3600*sensecst/(timesp); // m/h
  ispeedo=0;
} 
if ((millis()-pulse1)>2000) {
  ispeedo=0;
  velocity=0;
  pulse1=0;
  pulse2=0;
}
Serial.print(ispeedo);
Serial.print(":");
Serial.print(timesp);
Serial.print(":");
Serial.println(velocity);
}


void speedocount() {
  pulse2 = pulse1;
  pulse1 = millis(); //record latest interrupt time
  ispeedo++; //increase the reading counter
  if(ispeedo == 3){ //if 2 readings have been made...
timesp=pulse1-pulse2;
pulse1=0;
pulse2=0;
detachInterrupt(digitalPinToInterrupt(18));
}
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  start=millis();
  pinMode(43, OUTPUT);//Speedo power
  digitalWrite(43,HIGH);

  lcd.init();
  
  lcd.backlight(); // finish with backlight on  

  lcd.setCursor(2,0); //Start at character 4 on line 0
  lcd.print("FUROSYSTEMS R");

  EEPROMReadlong(addresstd);
  Totaldist=EEPROMReadlong(addresstd);
  Totaldistcheck=Totaldist;
}

void loop() {

elapsed = millis() - start;
start = millis();

if (modechange==1) {
   distance=0;
}
distanceint = (velocity/1000*elapsed/3600);//m
distance += distanceint;
distancedisp += distanceint;
Totaldist += distanceint;

if (abs(Totaldist-Totaldistcheck)>=100) { //later do it upon switch off
  EEPROMWritelong(addresstd,round(Totaldist));
  Totaldistcheck=Totaldist;
}

idisp++;

if (idisp>6){
lcd.clear();
//lcd.print(distancedisp/100);
lcd.setCursor(12,2); //Start at character 4 on line 0
//lcd.print(Totaldist);
lcd.setCursor(8,2); //Start at character 4 on line 0
lcd.print(velocity/1000);
idisp=0;
speedometer();
attachInterrupt(digitalPinToInterrupt(18), speedocount, FALLING); 
}

}

Hi, don't like all the stuff you are doing in the interrupt and the attaching and detaching all the time. Try to do as little as you can in the interrupt routine.

Take a look at the FreqMeasure library, maybe that can help.

I just tried using the FreqMeasure library, however, some random very large spikes occur and become very recurrent at higher sampling frequencies.

Hi,

We don't know your circuit but I suspect that you don't use an electronic deboncing circuit between the REED switch and the Arduino.

If that the case, I think you should have one to have a clean pulses train and to make those pulses TTL compatible.

On Arduino UNO, if the frequency is more than 150KHz, the interrupt will stop counting. I had a problem with a light sensor TSL235R that gave a high frequency at high light intensity. I had to use a divide by then IC and multiply results by 10.

You need to debounce the reed switch - you can get multiple counts when the contacts close (this applies to almost all mechanical switches). You also should put the magnet and sensor in relatively close to the hub on the wheel - if it is out along the periphery of the wheel, at speed, the magnet goes past the pickup too fast to trigger the reed switch typically (the angular velocity is the same everywhere, but the linear velocity is much faster the farther you go out on the wheel). I agree with others about attaching/detaching interrupts - normally, if you are going to use interrupts, you leave them run, do a minimum of things inside the ISR. If you want to enable/disable something being driven from interrupts, set a flag somewhere and use that in your code outside the interrupt.

gpsmikey: You need to debounce the reed switch - you can get multiple counts when the contacts close (this applies to almost all mechanical switches). You also should put the magnet and sensor in relatively close to the hub on the wheel - if it is out along the periphery of the wheel, at speed, the magnet goes past the pickup too fast to trigger the reed switch typically (the angular velocity is the same everywhere, but the linear velocity is much faster the farther you go out on the wheel). I agree with others about attaching/detaching interrupts - normally, if you are going to use interrupts, you leave them run, do a minimum of things inside the ISR. If you want to enable/disable something being driven from interrupts, set a flag somewhere and use that in your code outside the interrupt.

The need for "debounce" may be true, but first, I would suggest a stronger magnet.

Paul