Arduino Powered Smart Fan Controller



Introduction
This project will focus on using Arduino to build a smart fan controller. Fan controllers are an effective way to limit or boost the rotation speed of the cooling fans in a desktop computer. While doing something that is CPU and GPU intensive, it may be preferable to have more airflow through the computer case. Quite the opposite is true when there is little load on the CPU and GPU. Silence is golden when performance is not necessary. Typically, case fans are noisy and are connected directly to the 12 Volt power supply. This means the fans are on full strength whether it is needed or not. By limiting the effective voltage in certain situations, one can reduce the noise produced by the fans without affecting performance when needed. The primary objective here is to set a temperature threshold and have the case fans ramp up as needed to keep the case and components cool. To implement a reasonable system where the fans do not kick on and off, proportional-integral-derivative (PID) will be implemented. This feedback mechanism should make sure the fans stay quiet while providing adequate cooling in the computer case. The case fans in any desktop computer are controlled in one of two ways: either they are connected directly to a 12 volt branch of the power supply or they are controlled by the motherboard. Typically, at least the CPU heat-sink’s fan is controlled by the motherboard. The heat-sink’s fan is critical and is excluded from this project. The case fans move air through the chassis, providing cool air across all of the components. The RPM of each case fan is directly related to the voltage applied to the pins cased in their Molex connector. By regulating this voltage, the RPM of each fan can be controlled. By regulating the RPM of the fans, the noise can be reduced when needed.

Off angle picture of fan controller

Reading the Temperature

The first task is to reliably read the temperature, so the PID algorithm in the next section can do its job to regulate the fans. A Dallas One-Wire digital temperature sensor is used to get the temperature (1). As seen later in the wiring diagram (Figure 3), the reading is taken from the middle pin with a pull up resistor. There is a One-Wire library for Arduino, so it is pretty easy to call upon the sensor to get a reading in the main loop.

Dallas One-Wire DS18B20 Digital Temperature Sensor

Dallas One-Wire DS18B20 Digital Temperature Sensor

PID and How it Controls Temperature

PID is a standard way of setting a temperature and having the cooling or heating system reach that temperature without overshooting or undershooting (2) (3). The plot of temperature over time is a smooth curve that reaches the desired temperature. Let’s jump in head first. Here is the equation for PID:

equation for PID

 

Where Proportional Gain equation  is Proportional gain
Integral Gain Equation is Integral gain
Derivative Gain Equation is Derivative gain
e is Error
t is time

There are three terms here: the proportional gain, the integral gain and the derivative gain. The proportional gain is most influential term in the equation. e(t), the error, calculates the distance between the current temperature and the desired temperature and sets the proper adjustment to the output. The constant, Kp, determines the magnitude of change due to the proportional gain. The integral gain adds up the difference between the set point and the desired point over time. Given the history of the error it calculates the required change in output. In plainer terms, it determines the amount of acceleration that is required to reach the set point. Again, the constant, Ki, determines the magnitude of change due to the integral gain. Finally, the last term is the derivative gain. It balances the integral gain by lessening the potential for overshooting the set point. It does so by calculating the slope of the error over time and slows the change in output. Similarly to the previous two terms it also has a constant, Kd, which determines the magnitude of change due to the derivative gain. Taking a step back, one can see that the proportional gain is responsible for adjusting the output to manipulate the temperature; the integral gain is responsible for accelerating or decelerating that change; and the derivative gain is responsible for limiting the aggression of the integral gain when nearing the set point. By manipulating the constants in front of each term one can tune the system to perform within the scale that is needed. For the purpose of a fan controller inside of a computer, the output is in RPM and the set point is a temperature in Celsius. Obviously a higher RPM pushes more air through the case to cool the components. By tweaking the output (RPM) using PID, the temperature can be maintained at a set point with minimal noise and effort from the fans.

How to implement PID in code

Luckily there already exists a library for PID control for Arduino (4). In terms of code, the tunings are set and the adjustment to the output is computed in a loop. For every temperature reading, the output is computed with the PID library command, Compute(), and the output of the fan is set to the value that the library returns. The library also makes a distinction between aggressive PID and conservative PID. This is done so that when the temperature is close to the desired temperature the change in output is more conservative than when the temperature is far away from the desired temperature. In this example, the code specifies that swing to be one degree Celsius. When the temperature is within a degree of the desired temperature the PID responds more slowly and consistently. Conversely, when the temperature is farther than a degree away from the desired temperature, the PID output will be more drastic with larger tuning values.

Results of the PID

There are many methods of setting the tunings. For testing, the temperature sensor (1) was taped to a heating element which was placed in front of the case fan. To get the results displayed here, the integral and derivative gains were initially eliminated to zero. Once the proportional gain was behaving by oscillating around the set point, the last two terms were added in until the plot of temperature over time seemed to be stable. The results are displayed below in Figure 1. In addition, Figure 2 shows the output of the PID to the fan over the same time scale. The output pin on the Arduino microcontroller can be a value between zero and 255. At maximum speed this particular fan rotates at 1200 RPM.

Graph of temperature over time

Figure 1: Temperature over Time

User Interface with a Rotary Encoder and an LCD Panel

The secondary objective is to apply an effective user interface using an LCD panel and a rotary encoder. Since the voltage on the pins of the fan controls the RPM, the noise can be significantly reduced without any decrease in performance. The user should be able to set a temperature in the case and the fans will ramp up accordingly. Of course the hardware must be protected, so if a critical temperature is reached, the fans will turn on with full force and lower the temperature.

Front of LCD

LCD Displaying the Information to the User

The rotary encoder allows the user to set the desired temperature in the case. Rotary encoders work with two pins. Each pin is either high or low. Each pin moves in a certain pattern through high and low states. This is an implementation of a concept called a “Gray code,” because their patterns are the same but shifted by one cycle. As you can see in the below illustration, if there is a low to high transition on pin A and pin B is low, then the wheel must be spinning counterclockwise (left in the diagram). Likewise, if there is a low to high transition on pin A and pin B is high then the wheel must be spinning clockwise (right in the diagram).

Rotary Encoder waveform

Photo Courtesy of Arduino Playground (5)

In the code, interrupts must be used so the turning of the rotary encoder does not disturb the PID loop. When the rotary encoder is turned, it generates an interrupt. The interrupt pauses the main PID loop and iterates a variable in the proper direction. The desired temperature is then set to equal the rotary encoder’s value. The end result is that the user can twist the rotary encoder and the fans will work to make the temperature inside the case equal the temperature set by the user. The LCD panel reflects the current set temperature, the current temperature, and the approximate RPM of the fan. The RPM of the fan is derived from the value that comes off the Arduino pin. In the main loop where the PID is computed and set, the LCD is also updated. The LCD is compatible with the HD44780 chipset. This is a well documented Hitachi chipset, which eases the programming. Have a look at the diagram for the pin out of the LCD panel.

Putting it All Together

There are a few more considerations in putting all of the components together and running the code on the Arduino Uno. The Arduino will be mounted in a 5.25” storage container with the front punched out to make room for the LCD panel and the rotary encoder. The assembly must take power from a typical computer power supply, which is 12 volts. The microcontroller takes the 12 volts from the power supply and regulates it into five volts. The catch is that the temperature sensor needs five volts to operate, but the fan needs the full 12 volts to operate at maximum RPM. The full schematic of the fan controller is below.

Schematic for fan controller

Figure 3: Schematic for the PID Fan Controller

Final Assembly

Final Assembly

To achieve the fan control with the voltage from the power supply, a mosfet is used to handle the switching of the power supply on and off with pulse-width-modulation (PWM). PWM is performed by the Arduino. It is simply a square wave of high voltage and low voltage where the ratio of time off and on is regulated. At its highest, the controller outputs the full 12 volts. At effective half voltage the PWM is on for half the time and at its lowest the controller outputs zero volts. Effectively, this controls the RPM of the fan by quickly switching the motor on and off for a certain amount of time, which is determined by the PID process. This scheme of fan control should provide quiet fans that effectively react to the temperature inside the case and near the critical components while handing control over to the user through the LCD UI. In addition to control, the user should also be able to get real-time temperature and fan statistics from the LCD panel. As a result we have an Arduino-powered smart fan system that is open source and helps users control the temperature and airflow of their desktop computers.

Works Cited

1. Burton, Miles. Dallas Temperature Control Library. MilesBurton.com. [Online] [Cited: May 1, 2011.] http://www.milesburton.com/Dallas_Temperature_Control_Library.

2. Wikipedia. PID Controller. Wikipedia. [Online] [Cited: May 1, 2011.] http://en.wikipedia.org/wiki/PID_controller.

3. Matlab. Control Tutorials for Matlab: PID Tutorial. [Online] [Cited: May 1, 2011.] http://www.engin.umich.edu/group/ctm/PID/PID.html#controller.

4. Arduino Playground. PID Library. Arduino Playground. [Online] [Cited: May 1, 2011.] http://www.arduino.cc/playground/Code/PIDLibrary.

5. —. Reading Rotary Encoders. Arduino. [Online] [Cited: May 1, 2011.] http://www.arduino.cc/playground/Main/RotaryEncoders.

Appendix A: Bill of Materials

Device Quantity Price
DS18B20 Thermometer 1 4.25
IRF510 Mosfet 1 0.79
Molex 8981 1 0.00
5.25” Storage 1 11.99
Display HD44780 1 15.95
Rotary Encoder 1 2.95
10kO Resistor 1 0.02
4.6kO Resistor 1 0.02
1kO Variable Resistor 1 1.49
120mm 3 pin Fan 2 8.99
Breadboard 1 3.95
Diode 1 0.05
Total 13 59.44

Appendix B: The Code


Advertisement

53 Comments

Name
A name is required.
Email
An email is required.
Site
Invalid URL

  1. hello, chris
    Now I find myself with “‘amp’ was Not Declared in this scope” what do I correct? thank you


  2. hello, Chris.
    I can not compile your sketch, it gives me error “OneWire ‘does not name a type”
    I use version 0022. Could you help me? thank you


    • Not sure there. This post is pretty old. I bet it’s some incompatibility between this code and the newer OneWire library or something like that.


  3. J Richardson July 15, 2014

    I am looking at doing something like this with a case fan, but it would not be connected to a computer. I am somewhat new to this and have an arduino uno. Is there a good way to get 12V of power to the fan without a computer power supply?


  4. Burcin Turkmen May 5, 2014

    Hello.
    I need the mathematical modeeling of this project or transfer function and block diagram of this project. How can I do this, I need help.
    Thank you :)


  5. The red wire that goes to Vin actually goes to the +12V and the black wire coming from the fan goes to the ground of the 12V supply.

    In this case, they go straight to the 12V power source and fan will be spinning at full speed, no matter what the arduino is doing.
    I must be missing something….


    • You see how the red wire is connected to the diode (for protection)? And the black wire goes through the diode and the mosfet? That’s how the Arduino pin can control the fan. The mosfet is what regulates the voltage to the fan, keyword “Voltage Regulator”. So they don’t literally go straight to 12V and ground, but wire it up as you see them connected through the diode and mosfet. Perhaps I shouldn’t have used MS paint for that diagram ;)


  6. Thank you Chris.
    I know, this is really a old thread but thank you for taking care of it. :)

    I got it working with 9V and 12V but there is one small nag, that bothers me.
    You see, I am operating in narrow temperature range 18-22C
    Anything below 18C is a bad news and so is >22C

    My problem is, that when temp shows 20 and set point is 22, the fan just keeps going, although the RPM’s on the LCD show 0.0

    BTW, I know nothing about coding but I made one small change

    I removed “(int)” from
    lcd.print(Input);
    Now I can see temperature with 2 decimal places.

    Because there is always a lag with something cooling or heating up, I like to be sure that if I temperature is 0.5C above the setpoint, fan is turned off and stays off until it starts to rise again.


  7. You mentioned, you use 12V for fan.
    Can you please update the schematics to show how it’s wired.

    I like to use this system to control my home brew fermenter temperature where a
    small PC fan will be moving cold air form the “ice box” to fermenter box if the temperature rises above what ever is set.

    If you do not mind, I also started a thread in http://forum.arduino.cc/index.php?topic=231264.msg1667567#msg1667567 for this project.
    I am looking for a way to use different rotary encoder.

    Thank you


    • Sounds like an awesome project! I actually used a 9V battery for the video, but the fan is rated for 12V, so that should be ok. I am now realizing a commenter below was confused about the same thing. The red wire that goes to Vin actually goes to the +12V and the black wire coming from the fan goes to the ground of the 12V supply.


  8. avitron March 13, 2014

    OK, the Rotary Resolution is 12 pulses/360° for each phase.

    Can you count the home many pulses per second per rotation of the fan, and calculate the RPM of the FAN?


  9. avitron March 13, 2014

    why need to mulitply 4.7059 in the code:

    lcd.print((int)Output*4.7059);

    Can you explain it? Thanks


    • Chris Barnes March 15, 2014

      It’s just a scaling factor. I did a regression between the numbers 0-255 and the max rpm of the fan. It’s not accurate. If you need RPM look into reading it off the yellow wire


  10. Solihin Millin February 27, 2014

    Thanks Chris for a awesome project. Most educational. I don’t know much about hardware and tried to use a 12v 1amp 240v power pack. It registered 16v open circuit, but came down to about 14v when just powering the Uno. I then with my lack of knowledge tried to breadboard a external load onto the Uno power plug. ie. sharing power… there was a little spark as I touched the external load onto the Uno power plug (direct onto the plug) and the Uno stopped responding to IDE, ie. leds still on but cannot down load code.

    I did an awful lot of research and found
    http://www.youtube.com/watch?v=fSXZMVdO5Sg
    which seemed to possibly be the problem. Anyway, spent lots of time and had problems with the Flip USB driver on Windows 7 and eventually blew the board by touching the wrong things together :( (you know, the little ‘crackle, pop, smoke thingy’)

    My basic question is Chris,

    ‘It seems playing around with the power supply to the Uno, reset something in the board so it no longer communicated’

    Is there some way to ‘short out’ any noise, sparks, etc so they don’t travel into the Uno via the power supply jack? If so, can you give me a circuit diagram so I can try and implement it with your circuit?

    I only have limited electronics knowledge, but, for example, would you put a small capacitor across the power supply jack to dampen any spurious noise going into the power jack?

    Cheers,

    Sol


    • That’s too much voltage for the Arduino to handle. Use a power supply that is 5V for the Arduino. You can use the Arduino to switch or control larger voltages, but putting that much into the Arduino is going to kill it. Look at the Summary section over here for the recommended voltages: http://arduino.cc/en/Main/arduinoBoardUno


  11. G’day mate! First of all, that’s an awesome project, thanks for sharing it! I just have one question about the “Output” variablie you are using on “analogWrite”.

    As I understood, it should send a value from 0 to 255 to the FAN, but since Output is a “double” variable, it is sending a floating point value, isn’t it ? Is that correct ?

    Thanks!


    • Thanks :) So apparently, analogWrite takes an unsigned 8 byte integer. I haven’t tested this out, but it is probably casting it from a double to a uint8 and truncating. Meaning if the number is 3-point-anything it gets truncated to 3.


  12. hello @Chris, i want to ask, can or not the temperature value were set at 0 Celsius… and are the coding is same ..?or i have to make new coding..i’m new with arduino..


  13. I just used MS Paint. I would not recommend it. Use Fritzing instead.


  14. Anonymous April 13, 2013

    Awesome! I was looking for something exactly like this to cool down my onkyo stero. Quick question, what software did you use for the wire diagram?


  15. Anonymous December 6, 2012

    I made somethink similar, two channel fan speed controller look here PWM Arduino


  16. hi chris. i just have a question. can i put usb cable in arduino and use it as a power supply? sorry , im a newb at arduino


  17. @Alexander
    It has been a while since this project, but I’ll see if I can remember
    1.330 Ohm is what the datasheet stated, so that is what I used.

    I actually used a 9V battery connected to the fan and did not use the Vin pin. The Arduino should regulate the voltage for itself and pass the voltage through to Vin. Google around for a little more detail on how Vin behaves. Also you might look at the video a bit more closely. You can see the molex that is hooked up to a 9V battery and the red and black wires that are the source of the voltage.

    2. That schematic is kind of horrible. I should draw it up in Fritzing or something. Anyway, yes your assertion is correct!

    So the mosfet switches the PWM from the 12V or 9V to the fan and the Arduino regulates the voltage for it’s own use. If you were to break this out onto breadboard you’d have to add the regulators for yourself.


  18. Alexander September 22, 2012

    Hi Chris!

    Really nice project!! I’m on my way of replicating yours but I have a couple of questions.

    1.
    The 330ohm resistance that you use to dim the LEDs, how did you come up with that much of resistance?

    By my own calculations, powering the arduino (UNO) with 12V, 1A DC will result in the 5V out pin on the arduino to only (at tops) produce 450-650mA of current depending on the environment.
    Lets say the current is 450mA. We know that the background LEDs spec. 120mA typical and 160mA max. The voltage spec. of the LEDs is within the 4.2V(typ.)-4.6V(max) range. So in the most “optimal” situation we have ~140mA of current draw and an operating voltage of 4.2V.
    Let´s now say we get the voltage of the 5V rail on the arduino and of course we need to limit that to be within 4.2-4.6V. The voltage drop over the required resistance due to the LEDs is then 5-4.2=0.8V.
    The resistance needed to get us down to those 4.2V is then 0.8/0.150=5.33ohms
    This would produce a power loss due to heat in the resistance of 0.8*0.150=0.12W which indicates that a resistance rating 0.25W will suffice.

    Of course this will give us a display that’s at its max all the time and preferably a much dimmer display would be the perfect choice. But why did you choose a resistance of 330omhs? Wouldn’t that result in a voltage drop of more than 49V? Clearly I’m missing something here =)

    I must say that my electronics skill has degraded by the years and i´m a little rusty around the edges. =)

    2.
    In your schematic, is the negative to the fan connected to the drain of the MOSFET before the diode? I don’t get that since i haven’t worked with MOSFETS before. My guess would of course be yes, or the MOSFET would have no effect what so ever.

    Thanks in advance!
    Alexander


  19. @Ryan You are running out of pins for two of each. You could get an Arduino Mega although there is a price bump. Also for A/V make sure you get a large fan to keep the noise down, 120mm or bigger. As for the code you would just make another unique PID object and do the same thing, but with the right pins for the second fan. You could also use the rotary encoder to make a menu to select which fan you are adjusting. I put clicked! where the encoder will detect the push button. Do share if you make a double fan/sensor version!


  20. This is exactly what I have been looking for! However, my needs require two fans and two temp sensors. I am having a heat build up issues in my AV closet and I want to add one fan to draw in cool air in and one fan to push hot air out. I would like to have two sensors to measure the temp difference between near floor vs. near ceiling. I am a noob to Arduino, coding, and hardware; so any pointers on how to modify this project to meet my needs would be really appreciated. Worse case, I use this project as-is and have double the expense.


  21. Rectifier diode. The Bill of Materials has all the links you need http://www.jameco.com/webapp/wcs/stores/servlet/Product_10001_10001_36012_-1


  22. Hello Chris, really awesome! Thanks for Sharing your work.
    What Type of Diode have you used?


  23. @Mike It should be able to run two fans with some modification. You would repeat the part of the circuit that goes to the arduino pin and you could probably just set the two fans equal to one another. You’d have to tune the PID constants to make sense for your particular application. Per the noise. I did have some rattling at certain low RPM’s. You can figure out where that threshold is and tune the values so that it never happens. A touchscreen would be awesome! Good luck.


  24. Double check the link in Bill of Materials, but yeah silicon should be fine. That is a flyback diode. The print command you are asking about is a scaling constant. Assuming Output is between 0-255, multiplying by 4.7 gives us a rough estimation of the RPM. I got that number by doing a regression of known outputs and known temperatures over time.


  25. hi,,
    i want ask,,
    dioda silicon on the shematic.it’s negative route to Vin it’s right?
    and lcd.print((int)Output*4.7059);
    what the mean 4.7059?


  26. Anonymous June 26, 2012

    Ok I was just a little worried about 12v going through the vin, although it states from 7 to 20v. Have you experienced any noise issues or is evrything working well? I have been looking to do something like this in my server cabinet. The fans just run all the time. Would the same circuit handle two 120mm fans I think
    They pull .18 amps. It would be nice to use a touchscreen for the UI. But I haven’t been able to locate one that would work. Thanks replying.

    Mike


  27. Yup. You got it. That said, you don’t really have to pass the 12V through the VIN pin. In the demo I used a 9V battery connected directly to the molex pins of the fan.


  28. Anonymous June 25, 2012

    So if I understand correctly you are using 12V power supply into the arduino power pin and then using that 12v from the VIN pin to supply the fan? Awesome project.


  29. I didn’t! The RPM is an estimate. I did a regression between the arduino pwm value 0-255 and the max value of the fan according to the box. You could in theory read the RPM off the yellow wire though.


  30. Chris i am just wondering how did u measure the RPM of the fan?


  31. Obviously your display is not wired correctly. Make sure the pinout is correct. Datasheet is here: http://www.sparkfun.com/datasheets/LCD/GDM1602K.pdf Take a close look at my wiring diagram as well.


  32. Hi Chris,
    Could you help me with this please.
    I could successfully run the code successfully. But now when i upload this program on arduino microcontroller i see the fan running but no display on LCD.
    with thanks in advance.


  33. Yup. Make sure the library is in the libraries folder and is named OneWire. As I told flodini, if you are using a more recent version than 2.0 then try 2.0 since that is what I used. http://milesburton.com/Dallas_Temperature_Control_Library


  34. Hi, i need a help in this program.I get a compiling error no matching function for call to DallasTemperature::DallasTemperature sensors(OneWire); i guess this is because of dallas temperature library location.

    with thanks!


  35. There is no equation. That is actual data. Have the Serial.print() print out the current temperature every loop for a while and then copy and paste the terminal output into excel. You can then do a regression to get an approximate equation that fits your data. An equation is a model of your data not the other way around.


  36. Chris,
    What is the actual equation that your Temperature vs time graph is based on?


  37. Sure! Good luck. If it ends up in a project do share.


  38. Thanks a lot chris


  39. Flodini: I just updated the code section to be more readable if that makes a difference.


  40. Make sure you download the onewire library and put it in the libraries folder and name the folder OneWire. Downloads are here: http://milesburton.com/Dallas_Temperature_Control_Library I was using version 2.0, so if the latest version does not work then you might try 2.0.


  41. Chris,
    I was trying to compile your code but it came up with ‘OneWire’ does not name a type error. Also, DallasTemperature sensors(&oneWire); comes up with an error


  42. Glad it helped! That sounds like an awesome project. Smarter fan control = more efficient heater. If you write up the solar heater project link me up.


  43. A friend just gave me an Arduino uno the other day. Additionally, I am finishing up building my own solar heater for heating my house. This project is exactly what I am looking for to control the fans on my solar heater.

    Thanks!


  44. Happy Hacking, indeed! This is really great. Pretty clever stuff. Linda


  45. Thanks! I doubt it would be effected although I am not sure of that. Some fans are even designed to take a pwm signal. Not the one I was using though. So that is a definite probably-not. ha. The project was really fun!


  46. Cool project! One question: if the Arduino functions by cutting or giving power to the fan, will the life-span of the fan be reduced by all the stop/starts?

    Very interesting project and awesome work!