• Welcome to Overclockers Forums! Join us to reply in threads, receive reduced ads, and to customize your site experience!

Making a display for fan RPM

Overclockers is supported by our readers. When you click a link to make a purchase, we may earn a commission. Learn More.
Something I have noted is that some of my fans put significant negative voltage on the tach pin, 0.7v in the case of the JouJye at full speed and a fair amount of air restriction.
It's transient, but it's there.
Might not be a bad idea to put a low drop diode (schottky's from PSUs work great :D) between that pin and ground, with the stripe on the pin end of things.
 
Yeah, this pulseIn thing won't work with failure alarms:

Code:
unsigned long data;
void setup(){
  pinMode(2,INPUT);
  Serial.begin(9600);
}


void loop(){
  data = pulseIn(2,HIGH);
  Serial.print(15000000 / data);
  Serial.print(", ");
  Serial.println(1000000 / data * 60 / 4);
  delay(500);
}

I didnt' wanna crew around with resistors and such so I pulled the pin 2 HIGH, and polled for LOW

If you stop the fan or pull the rpm wire out the reading gets massively skewed....

How did you guys pull the output off your serial monitor anyway? I can't seem to do it and dont' care to figure it out:confused:
 
Sure it will, tell it to look for a pulse larger than 1000000, that's either lower than 60 RPM or quite dead :D
My little LCD takes serial input at 9600, really really simple and only uses one wire.
 
Sure it will, tell it to look for a pulse larger than 1000000, that's either lower than 60 RPM or quite dead :D
My little LCD takes serial input at 9600, really really simple and only uses one wire.

Nope, pull the wire off pin 2, the ouput jumps above 10000000, ie a really big number.

It never shows "0" which is what you want of the fan quits ie the power dies to it.

Code:
// Include the library
#include <LiquidCrystal.h>

// Initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7,8,9,10,11, 12); 


int NbTopsFan; //store count total
int Calc;            //store result after calculation is complete          
int hallsensor = 2;          //the pin location of the sensor


typedef struct{              //Defines the structure for multiple fans and their dividers
  char fantype;
  unsigned int fandiv;
}

fanspec;
fanspec fanspace[3]={{0,1},{1,2},{2,8}}; //used to select the fan divider 

char fan = 1;   //This is the varible used to select the fan and it's divider(reference the above line)

void rpm ()      //This is the function that the interupt calls 
{ 
 NbTopsFan++; //increment the counter
} 

void setup() {
  Serial.begin(9600);
   lcd.begin(16, 2); // Initialize LCD
   pinMode(hallsensor, INPUT); //Set Hallsensor, which is attached to digital   pin2, to INPUT
   digitalWrite(hallsensor, HIGH);  //use Arduino internal pullup resistor
   attachInterrupt(0, rpm, RISING); //Uno has numbers 0 (on digital pin 2) and 1 (on digital pin 3). 
}

void loop() 
{
   NbTopsFan = 0;	//Set NbTops to 0 ready for calculations
   sei();		//Enables interrupts
   delay (1000);	//Wait .5 second
   cli();		//Disable interrupts
   Calc = ((NbTopsFan * 60)/fanspace[fan].fandiv); //Times NbTopsFan (which is apprioxiamately the fequency the fan is spinning at) by 60 seconds before dividing by the fan's divider
   lcd.setCursor(0, 0);
   Serial.print(NbTopsFan);
   Serial.print(",");
   Serial.println(Calc);
   
   lcd.print("TEST");
   lcd.setCursor(0, 1);
   lcd.print(Calc,DEC);
}

Seebs whats your output from this on your serial monitor
 
Nope, pull the wire off pin 2, the ouput jumps above 10000000, ie a really big number.

It never shows "0" which is what you want of the fan quits ie the power dies to it.

Just change your fan failed alarm to trigger on a huge pulseIn number rather than a really low (like zero) RPM number.
 
Just change your fan failed alarm to trigger on a huge pulseIn number rather than a really low (like zero) RPM number.

lol I'm starting to realize you are the King of the "work around".

You are very much the "The end justifies the means"

I'm very direct and am a perfectionist, I'm not happy with work arounds because I know in the back of my head something is wrong and not working.

Although, yes! You are correct, I suppose as a work around you can set a threshold to where if the return value is abnormally high, throw an alert.

Although this method complicates coding. Now you have to add extra steps to get things to work. ie, when outputting to an LCD you'll have to brute force it to display "0"rpm. You also have to add code for the alarm as you just said.

To each his own lol Workarounds are definitely a useful tool, I prefer not to use them though. The creativity behind coming up with work around is phenomenal, that type of awesome imagination is great in devising ways to solve problems through alternative methods I definitely like me a good workaround once in a while. Shows cleverness and ability to think outside the box:thup:
 
Ok seriously though guys, how the heck are you pulling your outputs off the serial monitor???
 
Seebs whats your output from this on your serial monitor


Here you go...

Low values is 0% duty cycle on the Nidec
Mid values is 50% duty cycle
High values is 100% duty cycle

I'm going to eat some dinner and will be back in like 20 mins... I'm running on a bowl of cereal from this morning and my sugar level is taking a dive right now.

Code:
59,1770
59,1770
60,1800
61,1830
58,1740
64,1920
66,1980
63,1890
52,1560
64,1920
64,1920
62,1860
61,1830
66,1980
60,1800
64,1920
101,3030
163,4890
212,6360
243,7290
233,6990
253,7590
253,7590
259,7770
241,7230
277,8310
292,8760
243,7290
246,7380
254,7620
254,7620
256,7680
288,8640
280,8400
295,8850
272,8160
278,8340
342,10260
470,14100
617,18510
534,16020
547,16410
524,15720
555,16650
534,16020
525,15750
544,16320
543,16290
531,15930
555,16650
595,17850
588,17640
415,12450
 
I just realized the code ya'll are using is pulling the #2 pin HIGH and your also polling for HIGH. You should be polling for LOW, since that is what the RPM wire is actually doing...pulling the pin to ground.

Idk if that makes any difference, just a thought
 
Here you go...

Low values is 0% duty cycle on the Nidec
Mid values is 50% duty cycle
High values is 100% duty cycle

Code:
59,1770
59,1770
60,1800
61,1830
58,1740
64,1920
66,1980
63,1890
52,1560
64,1920
64,1920
62,1860
61,1830
66,1980
60,1800
64,1920
101,3030
163,4890
212,6360
243,7290
233,6990
253,7590
253,7590
259,7770
241,7230
277,8310
292,8760
243,7290
246,7380
254,7620
254,7620
256,7680
288,8640
280,8400
295,8850
272,8160
278,8340
342,10260
470,14100
617,18510
534,16020
547,16410
524,15720
555,16650
534,16020
525,15750
544,16320
543,16290
531,15930
555,16650
595,17850
588,17640
415,12450

Hey hey!!! That looks good!!! No fluctuations! This means you are polling correctly, now you just need to figure out the math part.

now change this:

char fan = 1;

to

char fan = 2;

...your dividers are jacked up and need to be adjusted for your fan speed. That your problem. BC that output right there shows near perfect scale wtih no abrupt fluctuations
 
oops, nevermine lol poor math on my part lol

change this:

fanspec fanspace[3]={{0,1},{1,2},{2,8}
to
fanspec fanspace[3]={{0,1},{1,2},{2,5.5}

then

char fan = 2;
 
Ok seriously though guys, how the heck are you pulling your outputs off the serial monitor???

I open the serial monitor, disable AutoScrolling, let it run for a few seconds and then copy as many lines as I want to show into clipboard.... Then it's just about pasting it in the forum. :D

Edit...

Here's the output with the changed dividers.
Low = 0% duty cycle (10% actual as that's the lowest teh fan will go)
Mid = 50%
High = 100%

For reference... This fan should do 900 - 1000 at 10% duty cycle and 6000 - 6300 at 100% duty cycle.

Code:
60,720
54,648
62,744
69,828
71,852
64,768
74,888
66,792
70,840
72,864
65,780
69,828
71,852
94,1128
149,1788
214,2568
245,2940
255,3060
265,3180
288,3456
255,3060
287,3444
302,3624
304,3648
290,3480
260,3120
277,3324
271,3252
328,3936
464,5568
637,7644
634,7608
595,7140
592,7104
601,7212
607,7284
588,7056
616,7392
616,7392
624,7488
600,7200
588,7056
606,7272
603,7236
606,7272
585,7020
597,7164
589,7068
591,7092
657,7884
 
Last edited:
I open the serial monitor, disable AutoScrolling, let it run for a few seconds and then copy as many lines as I want to show into clipboard.... Then it's just about pasting it in the forum. :D

Pfft how embarassing...

Anyway...Yeah I figured it out. you need a custom divider for your fan. Adjust the right hand number of the fanspec array till you get as close as you can to your fans live RPM, compare it against your mobo readings.

Thats all it is, your fan is pulsing several more times that any conventional fans, hence your readings are higher than normal

Looks like your divider assuming a 6500rpm fan and judging by the output u have is around 5-5.5

so:

fanspec fanspace[3]={{0,1},{1,2},{2,"5" through "5.5"}<--dial in as necessary

and select:

char fan = 2;

Boom! Done son!
 
Also, remember this is all just math.

The fan itself is doing nothing at all but constantly pulling pin 2 LOW several times a second, it's not sending any packets of "1s" or "0s" that the Arduino can "read". If anything all the arduino sees is a string of "0s" which is the same as "LOW" in digital logic terms. You TELL the Arduino how to interpret the pulses through math.
 
Pfft how embarassing...

Anyway...Yeah I figured it out. you need a custom divider for your fan. Adjust the right hand number of the fanspec array till you get as close as you can to your fans live RPM, compare it against your mobo readings.

Thats all it is, your fan is pulsing several more times that any conventional fans, hence your readings are higher than normal

Looks like your divider assuming a 6500rpm fan and judging by the output u have is around 5-5.5

so:

fanspec fanspace[3]={{0,1},{1,2},{2,"5" through "5.5"}<--dial in as necessary

and select:

char fan = 2;

Boom! Done son!

I figured that would be the way to go.... I have the fan running full bore right now... PWM wire disconnected from teh motherboard and monitoring RPMs with HWMonitor... I'll let it run for a few minutes and then will calibrate my dividers based on teh highest recorded RPM I get from it... That should at least give me a constant baseline for the calculations.

Thanks for all your help man.

On a positive note though... I did figure out hat sending PWM out to the fan to control its duty cycle is quite easy and the default "frequency" that the arduino sends out works for all my fans (Nidec, San Ace, Sharkoon)... Don't know how that is since two of them are 16KHz to 25KHz (San Ace and Sharkoon) and the Nidec is 5Hz to 5KHz.... Go figure.
 
When I copy/pasted the code seebs was using earlier I got tach readings that jumped from 1800 to 2500 to 4800 from a nice normal polite fan running ~2000rpm.
I never did figure out why, the picture on my scope was perfectly happy. I suspected it may have been something involving turning the interrupts on/off so I went back to an old really simple interrupt counter I had and tested with that, from that I found that the interrupt was simply firing at odd times, regardless of what I used for a pullup and whether I put a cap on it.
That's when I changed to using pulseIn, which worked great for me on all fans tested (ranging from the polite 2krpm to the 6300rpm joujye and 5k+ delta). pulseIn counting the LOW time didn't work very well for any of the fans, even the polite one. On the joujye it was laughable really!
pulseIn on HIGH worked nicely though.


I would love to put one of s33bs fans on a scope to see what the hell it is putting put (pulling in, whatever)!

On the HIGH or LOW, most fans (I can't say all as I have not tested all) use a latching hall effect sensor, so the time spent LOW and the time spent HIGH is identical. That assumes you're a human, to a MCU a spike down to -0.7v or up to 1.1v may be considered HIGH, in which case you're in trouble :D


It is worth noting that I didn't spend much time playing with the code of the example I copied from post 269, I made the assumption that it was a HW problem I was running into and worked on that front. It's possible that using a different form of interrupt (pin change might actually work really well, now that I think of it) or some averaging would solve the issues.

And, of course, as we're rapidly discovering we all have different fans that put out different signals!


EDIT:
Fans seem to be weird about what they accept, I've had some that really didn't appreciate low frequency and others that love it.
I've given up on assumptions :p
2.EDIT: Which is why my fan controller can switch between 25k and 3k.
 
Really, you're lucky BC the default freq on some of the pins is 31khz and the last 2 are 1khz or ~500hz which makes for strange sounds at ~20% duty cycle.

I can't remember.
 
Back