Fast Reading Tachometer!!! YAY!

I have been working on a tachometer for my motorcycle. Using interrupts reacts too slow or is too inaccurate, so I wrote this.

Please let me know if there are any questions or comments. Thanks.

Pulse Tach by R. Drechsler

The setup...
I'm using Arduino Ethernet or Uno but should work with any.
I have a 1.875"dia plexiglass wheel, painted flat black, attached directly to a small motor shaft.
The wheel has a single .116" wide notch cut into, about a .250" deep. The motor is powered by a 0-3A, 0-12V power supply.
I'm using a sparkfun photo interrupter ( sensing the notch. The signal
goes low when the the photo interrupter is blocked. The signal wire is to Pin 2.

The numbers...
Math to define some "magic" numbers... adjust as needed...
  timerrevCalc = duration * 50.7801;  
  RPM = 60000000/timerrevCalc; //See above
duration = amount of time notch exposes IR to sensor in uS.
50.7801 = the notch is 50.7801 times smaller than the remainder of the wheel (so the circumference of my 1.875"dia wheel = 5.8905, 5.8905" / .116" = 50.7801
^^^^^^^ this number needs to be calculated and adjusted per application.
60000000 is a convertion from uS to just minutes.

The good...
This appears to be VERY fast at reading RPM. The RPM is calculated with EACH pulse. So instead of using a interrupt and have to wait
 the interrupt interval to refresh the data, the data comes in after each pulse is timed.
Also, when using interrupts, you have limited resolution. Example, 10 pulses, counted over 250ms = 40 pulses a second. 40 pulses a second x 60 seconds = 2400 RPM, right?
So 1 pulse per 250ms = 4 pulses per second or 240 RPM and 2 pulse per 250ms = 8 pulses per second or 480 RPM!!! 1 pulse more = 240 RPM?!?!
To get better resolution, you need a longer interrupt interval. A longer interrupt interval = slower repsonse.

const int Pin = 2; // Photo Interrupter.
const int ledPin =  9; //LED pin on the arduino ethernet, to help visualize the notch passing by

int photoState = 0;
long RPM = 0;
long timerrevCalc = 0;
unsigned long duration;

void setup() {
  Serial.begin(38400); // had problems with 9600...
  pinMode(ledPin, OUTPUT);      
  pinMode(Pin, INPUT);     

void loop(){

  duration = pulseIn(Pin, HIGH, 100000); //times the amount of microseconds the notch is exposing the IR, Times out after 100000 uS. Raise the timeout for slower RPM readings.
  timerrevCalc = duration * 50.7801; //See above
  RPM = 60000000/timerrevCalc; //See above
  Serial.print(duration); //print out results.
  Serial.print("  ");

Nice work on your program! One question, how do you get by without using float for long timerrevCalc = 0;?

as it is allways positive you might change

unsigned long timerrevCalc = 0;

this code has 2 roundings:

duration = pulseIn(Pin, HIGH, 100000);
timerrevCalc = duration * 50.7801;  
RPM = 60000000/timerrevCalc;

you can merge it to

duration = pulseIn(Pin, HIGH, 100000);
RPM = 1181565219UL/(duration * 1000);

no floating point operations needed anymore (and yes it uses a real magic number)

Thanks guys... it may have been rounding but only a wee bit... Noticed it at 12,000 rpm, my duration was 97 uS instead of 98 uS.

I'll give the improvements a try and see what happens!

A little video showing the reaction time… the servo is a little slow but…

Looks quite good!

Hello, i know its an old one, but is it possible to modify code somehow to use hall sensor and read out RPM from car engine.