I made a "simple" interface for an automotive speedometer that uses a variable reluctance sensor(permanent magnet generator). The sensor outputs an analog sine wave so I built a full wave rectifier connected to a 2n2222 transistor then to Mega 2560(with current limiting resistors inline). The code below doesn't use any interrupts which was a requirement for me(don't ask why just accept it).
It works using "pulseIn" counting the low time between pulses, combined with things like feet per mile, pulses per tire revolution, tire rolling circumference, a few other items and a scalar. Now, with some smoothing/averageing, the code is pretty darn accurate according to the speeo in my truck. You're welcome to try it if it will work for you.
//VEHICLE SPEED SENSOR INTERFACE CODE
//AUTOTCU(c) 2014,2015 BRIGHTSPARK ELECTRONICS
//Bwallace 2015
#include <Wire.h> // Comes with Arduino IDE
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
#define DIV 120
#define FPM 5280
#define TIME 1000
const float TIRCIR = 7.56;
const float PPR = 123.2;
unsigned int vsspulse = 0;
const byte vssIn = 4;
double time1 = 0.001;
const int numReadings = 30;
int readings[numReadings]; // the readings from the input
int index = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
float scalar1 = 1.70; //error correction scalar
void vss()
{
// tone(4,2000);
unsigned int vsspulse = pulseIn(vssIn, LOW);
float vssval = (vsspulse * time1) ;
byte MPH = ((1 / vssval) / time1 * 2 / FPM * TIRCIR / PPR * DIV * 4 * scalar1 );
// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = MPH;
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;
// calculate the average:
average = total / numReadings;
// send it to the computer as ASCII digits
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Veh MPH = ");
lcd.setCursor(12,0);
lcd.print(average);
lcd.setCursor(0,1);
lcd.print("Pulse in = ");
lcd.setCursor(12,1);
lcd.print(vsspulse);
lcd.setCursor(0,2);
lcd.print("vssval = ");
lcd.setCursor(12,2);
lcd.print(vssval);
lcd.setCursor(0,3);
lcd.print("Average = ");
lcd.setCursor(12,3);
lcd.print(MPH);
delay(100);
}
void setup()
{
// Serial.begin(115200);
lcd.begin(20,4); // initialize the lcd for 20 chars 4 lines, turn on backlight
lcd.backlight(); // finish with backlight on
pinMode(vssIn, INPUT_PULLUP);
lcd.clear();
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
}
void loop()
{
vss();
}
If you can get away with a lower "numberofReadings[]" it will speed up the refresh rate especially on deceleration. With a numbofreading of 30 i get a little wonky 2-3 MPH fluctuation but below that it is pretty stable and can use a lower number of readings if you dont get to 70MPH often.
The PPR, is pulse per tire revolution. My reluctor/tone ring has 40 teeth and truck has a gear ratio pf 3.08:1 so 40 * 3.08 = 123.2. Since your bike is likely 1:1 at the axle, just use the number of readings you will get per tire rev(i.e. if you have a 50/50 wheel shutter, your PPR should be 1).
The TIRCIR is the rolling feet of your tire. How many feet does your tire travel in one revolution? You can convert to your desired unit of measure but you will have to change the FPM as well.
It works, I've used it, here it is.
Bill