Skip to content

Arduino temperature controlled PC Fan.

BreadboardOscar Gonzalez gives us a simple tutorial for speed controlling a PC FAN and reading a LM35 temperature sensor with an Arduino microcontroller. He covers the use of an optocoupler, PWM (Pulse Width Modulation) and reading analog voltages with the Arduino. He even has a video showing the fan speed control in action.

This article was submitted by Oscar Gonzalez as part of the “Hobby parts for articles” program. Oscar receives a Arduino compatible Modern Device Company Bare Bones Kit for this great article.

Control a device that requires 12V from the Arduino without frying it. The Arduino is a 5V device and can not directly drive a 12V device such as a PC fan. There are many possible solutions but my approach is using the CNY75 optocoupler to separate the two voltages.



This devices is very simple. It consist of an phototransistor and a LED inside the same package. The phototransistor turns on or conducts current when the internal LED lights. The brighter the internal LED the more current can pass through the phototransistor. The LED and phototransistor are physically isolated from each other. This physical isolation protects the input side (the LED) from voltage spikes on the output side (phototransistor) and can provide the voltage translation needed for this project. When the LED is activated from the 5V Arduino the phototransistor will turn on and pass current for the 12VDC fan. The isolation provided by the optocoupler keeps the Arduino is safe from destruction.

The optocoupler’s internal transistor does not have sufficient current capacities to drive a DC motor (like our FAN) directly. To boost the current I used a BD137 transistor which can drive up to 1.5 Amperes. This power transistor is sufficient for controlling PC Fan motors. The PC Fan model I used runs needs about 300 mA.

Controlling the speed with PWM
To control the fan speed you could reduce the drive voltage to the motor. This would be harder to do and could reduce the motor torque. PWM (Pulse Width Modulation) is easier with the Arduino and is basically like turning the motor on and off very quickly. We are turning on and off the LED inside the optocoupler which is turning on and off the transistor in the optocoupler which is in turn controlling the power transistor which is turning on and off the Fan motor. The longer the motor is on, the fast it will spin. The cycle time (off to on) is very short, so short that you will not hear it occurring. Actually it occurs so fast that the fan averages the on and off times to run at a nearly constant speed.

Testing the speed control
I tested the speed control with the “LED Fade” Arduino example sketch. Connect the internal CNY75 LED trough a 1K resistor. The motor should go from quiet (slow) to full cooling (fast) progressively. You can modify the example program to change the slow to fast cycle.

Reading Analog Voltages with the Arduino
The Arduino has several analog inputs which are converted into a 10-bit digital number. You read the analog pin using the anologRead(X) function. The number will be 0 if the input voltage is 0 volts and will go up with voltage to 1024 when the input pin is at 5V. So to get the voltage at the analog input you would use the following formula. Use the correct analog input pin name in place of the ‘X’ for the analogRead(X) function call.

Voltage = analogRead(X)*5.0/1024.0; //Note that 5.0 is the A/D reference voltage.

LM35 temperature sensor:
The LM35 is a popular and inexpensive temperature sensor. It provides an output voltage of 10.0mV for each degree C of temperature from a reference voltage. We can read this voltage with one of the Arduino analog inputs. So the output pin would be at 0V when the temperature is 0 degrees C and would raise to 1000mV or 1.0V at 100 degrees C. So to get temperature you would multiply the voltage by 100. For example if you read 0.50V that would be 50 degrees C. The voltage and temperature conversion math can be combined to give the simple formula below.

temperature = ( 5.0 * analogRead(X) * 100.0) / 1024.0; /

You can test the LM35 connected by adding the conversion code and a Serial.Print() to output the temperature to the IDE serial console.

Temperature Control?
Now we can control the speed of our motor, and read the temperature. The next step is to can combine the temperature reading functions and the motor speed control to make a fan speed control that automatically adjust based on temperature. I have not done this part yet, let me know how you do it.

Here is a video showing the fan speed controller in action.

You can use the optocoupler method to control the speed of any motor, not just the PC Fan as I have done here. You can also use the temperature sensor for other projects. I hope this simple tutorial about optocouplers, PWM and the LM35 temperature sensor was helpful to you. Let us know what you make with this.

Posted in Arduino, Microcontroller, Projects.

15 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Floodo1 says

    the optocoupler is an elegant solution. you could use a transistor or some other non-isolated piece of silicon, but why? why not opt for the optocoupler and gain isolation?

  2. Offlinesurfer says

    Great article thanks, but is there a link to the code?

  3. Mr. Meval says

    A mosfet isn’t fully isolated I think. The CNY75 can take 600 volts between the diode side and the photo transistor side which is pretty good, there are ones rated higher. This is very good if you’re working with AC.

    If the motor is a brushed DC motor I think you can run it with an SCR? I’ve not tried it yet but intend to.

  4. Jason says

    Thank you for posting this on the net. I am building an external cooling fan unit for my new x-box 360 (notorious for overheating and dying). I plan on using the 5vdc output of the usb ports to turn the fans on and off with a 12vdc wall wart supplying the voltage for the fans. I was going to use a transistor and relay but a guy at work suggested an optocoupler instead so there are no transient spikes introduced into my x-box thru the usb port voltage. Your post was very helpful in designing my circuit. Thank you.

  5. muzhair khan says

    i am a student of engineering in university of central punjab and i am designing a project to control different devices of motor by pc . i have write the program but it is not working please give me advice to what to do about this.

  6. JennaSys says

    Thanks for posting this. I used it as a basis for my first try at using PWM on an atmega8.

  7. Mime says

    Good answer! 🙂 Could you use a MOSFET transistor in this circuit in place of the optocoupler? What are the advantages of each?

  8. pK says

    Because i whanted to show something about optocouplers 🙂

  9. Mime says

    Why the optocoupler instead of a straight MOSFET transistor?

  10. pK says

    Hello folks!
    Is nice to view my article here, also many thanks to dfowler for traducing quickly my bad english on the original article i have send to him 🙂

    Just for the missing part of controlling FAN upon temperature:
    I have not make this part because i whant people to get improve the basics on PWM and DC fan’s a do it yourself 🙂 With that we can learn about managing diferent voltages on a same board and maybe do some variation of this king of circuit.

    I hope you enjoy Arduino and PWM like me and see bricogeek dot com for more (in spanish)

    See you very soon and thanks to dfowler another time for posting my article!

    Oscar G.

  11. dfowler says


    Looking forward to it.

  12. dfowler says


    You are correct.. sorry about that. 10 bits gives 1024 posible values 0-1023.

  13. Sean Coates says

    This piece looks like a good companion to my Kegerator controller article which will hopefully be coming out (here), soon (-:

    Mine uses a thermistor and a voltage divider, and has some interesting Serial stuff, but the LM35 looks very interesting, too.


  14. Felixe says

    Good article. I think I’ll be using something similar really soon. One minor thing that I can point: the AnalogRead() function goes from 0 to 1023, just what you get when doing 2^n-1 when n=10.

  15. xSmurf says

    Nice write up! Indeed optocouplers are often left apart in the hobby world and yet they are very useful. 🙂