Crazy RPM readings

Hello everybody, First of all I want to say that I am a newbie at arduino. I am working on a school project. The idea is simple: - 1 intel pc cooler 4 wires(PWM on pin 9), TACH to pin 2 (intrreupt 0) - 1 potentiometer (Signal on pin A0) - 1 arduino duemilanove

What i want to do is use the potentiometer to set the speed of the pc fan, used it as the setPoint to feed it to a PID, get the rpm of fan(code copied from rpm post :D ), feed the rpm to the pid, and calculate the output. So far with out the analogWrite function i get normal readings of the rpm: 1660 1650 rpm, when ai insert in the loop analogWrite(9,128), the rpm readings send mutate to HULK-like values 56000-7800 rpm: Here is ze code:

#include "TimerOne.h"

 volatile byte rpmcount;

 unsigned int rpm;
 int value,pwm;
 unsigned long timeold;

 void rpm_fun()
   //Each rotation, this interrupt function is run twice
 void setup()
   attachInterrupt(0, rpm_fun, RISING);
   //my code
   rpmcount = 0;
   rpm = 0;
   timeold = 0;
 void loop()
   if (rpmcount >= 20) {
     //Update RPM every 20 counts, increase this for better RPM resolution,
     //decrease for faster update
     rpm = 30*1000/(millis() - timeold)*rpmcount;
     timeold = millis();
     rpmcount = 0;

Did something like this happen to someone else?

What i want to do is use the potentiometer to set the speed of the pc fan, used it as the setPoint to feed it to a PID, get the rpm of fan(code copied from rpm post), feed the rpm to the pid, and calculate the output.

I don't see anything to do with PID in this code.

When calculating RPM, you should disable interrupts. Re-enable them when done. This will prevent an RPM interrup fro occurring while you are calculating the speed.


A0 is the name of the analog pin when used as a digital pin. Is that the case here? If not, you can't set the mode of the analog pins, since they can only be input pins.

rpmcount is a lousy name, since you are not counting rpms. You are counting revolutions, and computing revolutions per minute.

     rpm = 30*1000/(millis() - timeold)*rpmcount;
     timeold = millis();

You will get two different values from lillis on these two calls. You really want to use set timeold to the value used in the first statement. This will require storing the current time and using that time in both places.

What is the significance of 30 in that statement? There are not 30 seconds in a minute. You're variable name does not imply revolutions per half minute.

Hello, About the missing pid. i will get to that, but first i must find a decent way to get everything to go well. From the fan spec the tach output is made off 2 pulses in a revolution, that's for the 30 thing.

A0 is connected to a pull-up rezistor that in turn is connected to the tach output(it's open-collector). With the aid of this pin i want to do something like this: value=analogRead(A0); analogWrite(9,map(value,0,1023,0,255));

I will give it a try with sei and cli :D, thx


implies that you are using analog pin 0, not pin 14. You really should ditch the A0 name to avoid confusion, along with the pinMode statement.

Use of the map function is overkill.


This is my problem: 1540,1300,1120,960,860,820,820,820,820,820,820 are the output for this code

   if (rpmcount >= 20) {
     //Update RPM every 20 counts, increase this for better RPM resolution,
     //decrease for faster update
     rpm = 30*1000/(acc - timeold)*rpmcount;
     timeold = acc;
     rpmcount = 0;
  // analogWrite(9,128);
  attachInterrupt(0, rpm_fun, RISING);

Now if we remove the comment from analogWrite and upload it: 10000 ,8100,9360,,8100,8940,8000,8820,8100,8680,8560,8560,8100,8320,8200,9820

Because pinMode(9,OUTPUT), and the pin is attached to the pwm input of the fan , the fan is running on minimum rpm, 30% according to the specs. When no pwm, 9 not set, fan is at max rpm

Wait to hear back from you Paul :D

With the analogWrite statement in effect, does the speed of the fan actually change? (Ignoring the "measured" output). Can you detect an actual change in the fan speed?

The detach/attach statements should be in the if(rpmcount) block, not performed on every pass through loop.

YES, it does

Yo Paul, here is something else: analogWrite(9,255) WORKS analogWrite(9,254) on the other hand :( doesn't. Reading the .c files of the arduino, i found that analogWrite(9,255) is eq with digitalWrite(9,255), no timers involved.

There are 3 timers or more on the Arduino. The various PWM pins use various timers. Does changing the PWM pin have any affect on the problem?

Hey, Every pin I tried didn't work, I got even worse readings from pins 5 & 6. But thanks to your idea I've detected something else, when I removed the cable to switch to other pins (from 9 to 10) as soon as pulled the darn thing out, the readings came back to normal(1680 and so one), maybe the nature of my problem could be electrical, some parasitic capacitance somewhere, pwm going along the wire. What do you think?

Noise is most definitely a possibility. However, detecting noise by hot swapping wires is a good way to short the Arduino out. I'd recommend that you NOT hot-swap wires to the Arduino.

Looking at the Intel fan specification ( I see several issues.

Fan power is 12v. Are you supplying 12v to the power line of the fan?

The TACH output expects a pull-up TO THE 12v RAIL.

Luckily the PWM signal is a 5v TTL signal so that's fine.

You should add a pull-up resistor. I didn't look hard enough to find a recommendation. You MAY be able to get away with a 5V pull-up rather then the specified 12V.

Edit: Oh, and they specify a 25 KHz PWM pulse rate. The Arduino reference says 490 Hz (less than 1/50th the specified rate). You may want to implement a fast PWM with Timer 2.

Hello John,
You are wright,I do have a pullup to 5V on tach. This was my Muse.
As for 25 kh pwm signal. I went to my school where i used the oscilloscope to calibrate a special library function :
I just used the analogWrite, to prove my point :). In this library there is a function Timer1.pwm(pin,duty_cycle, period).
When I set the function to (9,512,32) i got a pwm signal 50% duty cycle an 28 khz, so that is not the issue, but still i can’t figure out what the problem might me.

PS: because you all have real names, mine is Mircea :slight_smile: