Problem about reading CPU Fan RPM when Fan is PWM Controlled

I have a circuit to read the cpu fan speed. The fan I'm using is a 3pin fan. I want to read the RPM of the fan when I set the PWM pin from 0 to 255.

  • The following image is basically how I've connected everything, with the addition of a orrange PWM control wire coming out of enA of the L298N motor driver and going straight into digital pin 9.
    Diagram

  • I connected 10kΩ Resistor in 5 V bias of Arduino board and connect Resistors another end to Fan signal pin (green wire) & Arduino Digital pin D2 together. The 12V battery to DC L298N motor driver and bring common ground to Arduino board.

  • However, the fan speed I'm reading back is very wrong and I dont know why.
    Result

Here is my code:

//-------------------------------------------------------------------------------------------------
int in1 = 4;
int in2 = 5;
int enA = 9;

volatile int Hz = 0;
int rpm = 0;
unsigned long lastmillis = 0;

void setup()
{
Serial.begin(9600);
attachInterrupt(0, rpm_fan, FALLING);

pinMode(enA, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);

digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
analogWrite(enA, 50);
delay(10);
}

void loop()
{
if (millis() - lastmillis >= 1000){

noInterrupts();

rpm = Hz * 60;

Serial.print("RPM =\t");
Serial.print(rpm);
Serial.print("\t Hz=\t");
Serial.println(Hz);

Hz = 0;
lastmillis = millis();
interrupts();
}
}

void rpm_fan(){
Hz++;
}
//-------------------------------------------------------------------------------------------------

Can anyone help me about this? Thanks in advance.

  noInterrupts();
   
    rpm = Hz * 60;
   
    Serial.print("RPM =\t");
    Serial.print(rpm);
    Serial.print("\t Hz=\t");
    Serial.println(Hz);
   
    Hz = 0;
    lastmillis = millis();
    interrupts();

Why are you Serial.print()ing with interrupts disabled?

You should have interrupts disabled ONLY LONG ENOUGH TO COPY AND RESET variables.

Forget about calculating RPM. How many pulses does the fan output in one second? Is that more than fits in an int? Why ARE you using a signed value to hold a number that can NEVER be negative?

After corrections you should have something like this:

int in1 = 4;
int in2 = 5;
int enA = 9;


volatile unsigned long Revolutions = 0;
unsigned long rpm = 0;
unsigned long lastmillis = 0;


void setup()
{
  Serial.begin(9600);
  
  pinMode(2, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), rpm_fan, FALLING);


  pinMode(enA, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);


  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  analogWrite(enA, 50);
  delay(10);
}


void loop()
{
  if (millis() - lastmillis >= 1000)
  {
    lastmillis += 1000;
    
    noInterrupts();
    unsigned long RPS = Revolutions;
    Revolutions = 0;
    interrupts();


    rpm = RPS * 60;


    Serial.print("RPM =\t");
    Serial.print(rpm);
    Serial.print("\t RPS=\t");
    Serial.println(RPS);
  }
}


void rpm_fan()
{
  Revolutions++;
}

Thank PaulS and johnwasser for your quick replys. Sorry for my simple topic, Im just a newbie and have less experience with arduino.

  • The cpu fan I got outputs 1 pulse in 1 revolution.

  • I also copied johnwasser's code and tried it but it did not still look good. This is the result I got: new result. And in the meantime, I observed when I stopped the fan by my finger, speed of fan was still 88200 rpm instead of 0 rpm (the speed did not change into 0, this makes no sense).

  • But if I put directly 1 DC power supply like 9 VDC on fan instead of controlling by pwm, the fan speed I get is correct result (no pwm).

Please help me!

Why on earth would you post links to pictures of text?

It sounds like your PWM signal is getting into the fan speed signal. That would indicate a wiring mistake or a design limitation which you will have to discover and fix. An oscilloscope would be a good tool to use.

Are you sure the Arduino and Fan share a Ground?