FC-51 RPM Counter...Accuracy??

Arduino UNO and I.D.E 1.8.0.
I am trying to use an FC-51 IR distance sensor to measure rpms of a small fan. Many versions of similar sketches abound on the internet. Below is what I am using. I have experienced similar problems as I will describe below with other sketches. I have modified the sketch to lcd.print the 'rev' count and 'time' only for debugging and corrected some minor formatting issues. The concept is quite straightforward. The interrupt runs for 1000ms before detaching, then calculates the time between start and stop of the interrupt and uses the 'rev' count as 1/60th the rpm. OK, except it is terribly inaccurate and perhaps someone can identify a basic programming error. In the attached photo, upper panel shows the setup of the FC-51 just a couple inches away from the fan, with white tape stripe. Middle panel shows the lcd display with 'rev' count and 'time' count. The bottom panel show my scope display with input from the Arduino digital pin 2 and you can see the wave cycle rate is ~12Hz, whereas the lcd is showing 47. Curiously, the ratio between the two is very nearly 4. Any ideas out there?

LiquidCrystal lcd(12,11,7,6,5,4);
//from: How to make Arduino based Digital Tachometer │RPM Counter simple DIY tutorial - YouTube

float value=0;
volatile float rev=0;
int rpm;
int oldtime=0;
int time;

void isr() //interrupt service routine

void setup()
lcd.begin(16,2); //initialize LCD

attachInterrupt(digitalPinToInterrupt(2),isr,FALLING); //attaching the interrupt
// with FC-51 normally HIGH, interrupt checks for a drop in signal

void loop()
delay(1000); //while interrupt gets # of 'rev' during delay
detachInterrupt(0); //detaches the interrupt
time=millis()-oldtime; //finds the time
rpm=(rev/time)601000; //calculates rpm

oldtime=millis(); //saves the current time

attachInterrupt(digitalPinToInterrupt(2),isr,FALLING); //re-attaches interrupt for next readings


I have sketch that will read the rpm of a turntable. it looked like same project your trying to accomplishing. I used a ir sensor to trigger an interrupt. Try and see if does what you want. You need one bar of reflective material to generate the pulse. It is a simple program. attached it is the sketch. I am using interrupt pin 3. and a I2C display.

turntable_rpm_lcd_disp_03_27_2017_1.ino (4.28 KB)

Thank you for commenting. I tried your sketch, only modified for my standard 16x2 lcd. I slowed down my motor as slow as possible. As far as the sketch, while I see how your isr calls start and end time with FALLING criteria, I am unclear on the rpm calculation theory, i.e., taking the inverse of calc_time multiplied by 60. I also find that the rpm value is pretty unstable, sometimes values changing dramatically . Please see my attached photo for the rpm measured by my oscilloscope trace and the lcd display...still pretty far off. Ideas? btw, before powering the fan, I can move the rotor back and forth with my fingers and the white stripe passing in front of the IR sensor and it has no problem picking that up.

Checking the reading from the scope it should be 283 rpm. So your calculation it is right. What I do in my program it is go to the interrupt routine wait until the pulse arrive read the start time, wait for the second pulse read the time and calculate the rpm. Can you print to the monitor the calculate time before the rpm calculatio9n.? Serial.println( calc_time,DEC);

I am using the sketch in my turntable with no problem. I think we are using the same sensor.

Can you get the sensor as close as possible? My it is about 1/2 inch from the strip. I am using a reflective stripe of a 1/4 inch width. How many blades does the fan have?

Attached it is picture of my setup.

Sorry about the attached picture the bytes size was too big. Anyway I did a test using my sensor with a 12 volts fan and the reading compared with an rpm meter. So it is possible that it is the sensor that you are using, also I am using a reflective stripe.
Now attached it is a picture of my sensor. It is a KY-033. I bought it at Ebay $0.99 cents.

Thanks for all your comments. I hope I answer all your questions. I have found that the "best" position for the sensor is about 1"=1.5" away from the fan blades. Your sensor is a bit different than mine(see attached), although apparently yours also goes low when it detects something in from of the IR.The fan has 7 blades, all black and my white tape, while not reflective in the true sense, is also 1/4" wide. I'm not fully knowledgeable on flags and some of the tricks in your sketch, so I'm a bit confused. But, in looking at my sketch, where I am incrementing rev++ in the isr, if I am counting the FALLING signals due to the interrupt on the exact same wire where I have my scope probe attached, over a delay(1000) which when you subtract millis()-old_time is 1002, or so, then the scope and interrupt D2, or D3(I also tried another pin), then Arduino rev and scope Hz should be the same over the period of 1 second. But, it's not. I wish I had a metronome. I'll try some very slow "flicking" back and forth and time that.


Just for a test try to add a .04uf capacitor to the output pin. see if it does any difference

OK...I'll try that along with my 'flicking' test and get back tomorrow a.m.

Remembered that Digital Pins Usable For Interrupts Uno, Nano, Mini, other 328-based pins 2, 3

Thinking last night about what better way to test my rpm sketch than using a second UNO to drive the FALLING interrupt at a precise manner. So, using the sketch below, I have a 10Hz pulsing routine with 100ms period. See the attached photo. You'll see that the scope shows a 10Hz as does the lcd display with it's "rev" display on the 1st line and "time" of 1002 millis on the second line. So, my sketch works...now to dig into the IR sensor/fan setup. I'll try that .04uf cap as you suggested.

modified 28 March 2017 by JFL
gives a "FALLING" pulse for and interrupt on a 2nd Arduino

int pulsePin = 8;
float pulsePeriod;
const int pulseFreq = 10;
const int pulseDuration = 3;

void setup() {
pinMode(pulsePin, OUTPUT);
pulsePeriod = 1000/pulseFreq; //milliseconds length of pulse period

void loop() {
digitalWrite(pulsePin, HIGH);// turn the pin on
delay(pulsePeriod-pulseDuration); // wait
digitalWrite(pulsePin, LOW); // turn the pin off
delay(pulseDuration); // wait

Very, very interesting today.

  1. The first item was confirming that the Arduino #2 drove the FALLING interrupt on Arduino #1 lcd display identical to the oscilloscope.

  2. Then, when placing a .04mfd disc capacitor across the output pin of the IR sensor and ground the lcd display, i.e., Arduino #1 interrupts and Hz counter immediately very closely matched the oscilloscope. Interestingly, that capacitor has no influence on the scope display at all. I'm a little puzzled as to why the influence on Arduino interrupts when the scope display show very sharp and well-defined waveform with FALLING characteristics. But happy that it is resolved.

Thank you very much for your suggestion.

Congratulation that you was able to make it worked. I came with the same conclusion. The capacitor does not do anything to the signal. What I think it does is provide more power to the Arduino UNO pin. In my original project I used the Mouser Photologic® Reflective Object Sensor OPB760, Buffered Totem-Pole. It is a TTL output and no problem with it. It is very clean.