Home     Contact     Projects     Experiments     Circuits     Theory     BLOG     PIC Tutorials     Time for Science     RSS     Terms of services     Privacy policy  
 Home      Projects     Experiments     Circuits     Theory     BLOG     PIC Tutorials     Time for Science   

20 March 2010
Author: Giorgos Lazaridis
PWM 3-Wires Fan Controller with RPM feedback (Pulse Stretching Method)

The circuit on a breadboard for test

I made this circuit for my PC System Health Monitor project. I have 4 120mm fans in my PC cabinet, each one controlled separately from a dedicated PIC. The outlet fans, are 2 Coolermaster 1200rpm fans, that are controlled using this PIC 3-Wire Fan RPM Controller. The inlet fans are 2 Zalman 1800rpm, that unfortunately did not work as expected with the same circuit. I decided to give another try to these fans with a PWM averaging rpm controller. The results were as expected. I had clear readings from the tacho of the fans, yet i could not achieve low speeds without stalling the fan, nor had i an acceptable range of speed steps. Moreover, the fan stalled once in one month of test-operation, without any particular reason.

It was time to start thinking of another way to control these fans. I did not want to change them, as the summer is coming soon, and we have some hell of a hot summer here in Greece. I will need these 1800rpm fans to work overtimes. So, the third and last way to control these fans - and have also rpm feedback is the "Pulse Stretch method".

But first, let's see the circuit in action!

What is the Pulse Stretching?

A 3-wire PC fan is orientated to work either at full speed, or with a resistor in series to reduce the voltage and thus reduce the speed. The third wire will then provide pulses with 50% duty cycle from the internal tacho. From the pulses, someone can calculate the speed of rotation.

The problem begins when the fan is powered with PWM. The tacho is directly powered from the positive and negative wire of the fan. If the fan has no constant current - e.g. powered with PWM, the tacho will not operate correct. Every time that the PWM is LOW, the tacho will not have any power at all. The result is that the feedback wire of the fan will return the PWM pulses themselves, instead of the correct rpm pulses.

The "Pulse Stretching" method works as follows. The fan is driven with high frequency PWM pulses, above 20KHz to avoid acoustic noise. Occasionally, the PWM duty cycle is turned into 100% (constant power supply). During that time, the tacho will operate normally and will return the correct rpm pulses. The constant current is kept enough time to measure one complete period of one pulse. Then, the PWM duty cycle is changed to the value it was before.

Look at the following picture of the oscilloscope. The yellow channel is the 12V PWM supply of the fan. The green channel comes directly from the fan rpm feedback. The blue channel is only for synchronization, and indicates the time that the PWM duty cycle is 100%:

During the HIGH period of the blue channel, the power supply of the fan is 12V constant. At that time, you can see that the feedback pulses are clear and can be read without any problem.

The circuit

The heart of the circuit is the PIC 16F88. The chip generates the PWM to drive the mosfet that gives power to the fan. Also, it controls the LCD. The LCD is only to display the results. When i began designing this circuit, i used an 8-pin PIC and did not have any rpm display. After all, i use the oscilloscope for this reason. The LCD was a change of the last minute.

The LED shows the sampling rate. It reads the fan speed twice a second. A normal design would never require such a fast sampling rate. You may consider reducing the sampling rate to 1 read per 3 seconds.

Finally, i use the PIC built-in A/D converter to read the position of a potentiometer. The potentiometer is connected as a voltage divider. The PIC will change the PWM duty cycle according to the position of the potentiometer. There are 2 resistors taking place in this voltage divider along with the potentiomeeter, the R6 and the R7. These resistors are carefully chosen to adjust the range of the potentiometer. With these resistors, the PWM duty cycle can be adjusted from 6% when the potentiometer is completely turned left, up to 100% when the potentiometer is turned completely to the right. Someone would ask "Why didn't you adjust the range of the potentiometer in software?". Well, yes, i could do that of course. But, i wanted this circuit to be a little bit more flexible. For example, someone can completely remove the LCD screen. Then, he gets a PIC and uploads the firmware as is, in his local store. Finally, he makes his PCB. Now, by changing these two resistors, he can adjust the minimum and maximum duty cycle - in other words, the minimum and maximum rpm speed. And all this, without having to know ANY PIC programming.

So, here is the schematic diagram of the circuit.

The time that i keep the PWM at 100% duty cycle is not fixed. I keep it that way only as long as i need to get a full reading of a complete period of a pulse. This gives me two extra advantages. First of all, the speed of the fan will not change significantly. But more important, this way will prevent the fan from stalling. If the fan stalls - something that is NOT going to happen - it will stop sending pulses to the PIC. But the PIC will send constant current to the fan to read the pulses. It will keep sending constant current until it reads one pulse! It will just NOT stall. The following image shows that i turn the PWM back on again immediately when i finish reading the pulse.

Oh and something last. If you notice, the oscilloscope reading is 13.1 Hz. This number can be turned into rpm easily. Each rotation of the fan sends two pulses. Thus, you divide the frequency by 2 to get the rps, and then multiply by 60 to get the rpm:

rpm = 13.1 / 2 x 60 =. rpm = 393

I think it is quite good for the first time, isn't is?


Following i provide the files for the PIC firmware. First, i have the complete assembly listing to read, re-compile and upload.

 Pulse Stretching PWM fan controller - Assembly listing

If you don't know how to re-compile but you do want to upload the firmware, then download the hex listing bellow:

 Pulse Stretching PWM fan controller - Hex

A slight problem

Although i could not think of this problem, when i faced it it sounds normal. If you make a large change with the potentiometer, the rpm measurement may go a little nit crazy. For example, if you are at 350rpm and you turn the potentiometer full right, the rpm will start increasing rapidly, 500-800-1000-1150-1200. But sometimes, some crazy numbers appears, like 7000rpm, just for a blink, then it returns to normal. It does not happen always that way. And usually it happen when you go from max rpm to min rpm. You should consider enriching the firmware with software filters.

Bill Of Materials
R1Resistor 150 Ohm 1/4 Watt 5% Carbon Film 
R2Resistor 2.2 KOhm 1/4 Watt 5% Carbon Film 
R3Resistor 4.7 KOhm 1/4 Watt 5% Carbon Film 
R45 KOhm potentiometer
R52.2 KOhm potentiometer
R5Resistor 8.2 KOhm 1/4 Watt 5% Carbon Film
R5Resistor 330 Ohm 1/4 Watt 5% Carbon Film 
C11 uF 16 Volts electrolytic capacitor
D11N751 5.1V 400mW Zener Diode 
Q1IRF520 9.2A, 100V, 0.270 Ohm, N-Channel Power MOSFET 
IC1PIC16F88 Microcontroller 
LED1LED 3mm red 

Relative pages
  • Learn how dimmers work
  • Frequency measuring techniques
  • PWM signal theory
  • The voltage divider theory
  • Learn about the most popular PC Cooling methods
  • An intelligent self-tunned fan PWM controller
  • A 2-speed PWM temperature fan controller
  • How to make a PWM fan controller / LED dimmer using a 555
  • Create PWM pulses with variable duty cycle controlled by a DC voltage input
  • Dr.Calculus: Voltage divider calculator
  • Learning PICs @ PCB Heaven On-Line Book

  • Comments


      Email (shall not be published)


    Notify me of new posts via email

    Write your comments below:
    BEFORE you post a comment:You are welcome to comment for corrections and suggestions on this page. But if you have questions please use the forum instead to post it. Thank you.


  • At 28 May 2014, 8:24:16 user Angeltech wrote:   [reply @ Angeltech]
    • Hello Sir:

      Part number for R5 enter 3 times on part list "bill of material" while R6 and R7 was not indicated.



  • At 22 March 2014, 15:55:26 user Giorgos Lazaridis wrote:   [reply @ Giorgos Lazaridis]
    • @Tom Oh i see. No it will not. Your PIC must get the RPM signal once or twice per second and translate it into the typical frequency of the fan signal to feed to the mobo.

  • At 7 March 2014, 17:10:09 user Virinom wrote:   [reply @ Virinom]
    • @Giorgos Lazaridis I really need this circuits non lcd version programmed on 8 pin pic.Can you send it to me.I didn't know enough assembly to edit source.
      Thanks a lot

  • At 8 February 2014, 17:07:42 user Tom wrote:   [reply @ Tom]
    • The RPM signal is clear only 2 times per second will the MoBo be able to recognize it?
      Because of this project I've started learning PIC programming, thank You for inspiring me :)

  • At 2 February 2014, 9:32:58 user Giorgos Lazaridis wrote:   [reply @ Giorgos Lazaridis]
    • @Tom Sure, just pull down the tacho line of the MoBo

  • At 31 January 2014, 9:27:23 user Tom wrote:   [reply @ Tom]
    • Is it posible to get RPM signal from this PIC to PC motherboard?

  • At 24 July 2013, 15:48:17 user Giorgos Lazaridis wrote:   [reply @ Giorgos Lazaridis]
    • @Suresh Nope

  • At 24 July 2013, 14:41:39 user Suresh wrote:   [reply @ Suresh]
    • Hi

      Is this 3 phase BLDC motor?


  • At 24 July 2013, 8:46:35 user Chris wrote:   [reply @ Chris]
    • I haven't used the fan in years so it could be broken.

      I do have a scope but I'm not set up to check right now. I think I did have a look before but don't recall what it was doing now as that was a couple weeks ago.

      I'll have to hook it up on my bread board with a resistor and see what up. I seem to recall that just applying 12V to the 2 power pins didn't work even - so that probably means it's bad.


  • At 24 July 2013, 8:00:05 user Giorgos Lazaridis wrote:   [reply @ Giorgos Lazaridis]
    • @Chris I have exactly the same P4 fan and works just perfect! Do you have an oscilloscope to see the results? It should work.

  • At 24 July 2013, 7:34:22 user Chris wrote:   [reply @ Chris]
    • Thanks Giorgos.

      I figured out why it was acting so weird.

      Turns out some of these cheap Chinese 3 pin fans are actually 2 pin fans pretending to be 3 pins by attaching the 3rd pin to the input pin. So you get a full 12V power signal back on the tach line. When that hit my tach input resistor it caused major kniptions and it's a bit surprising the PIC didn't pffft given how many times I tried before figuring this out. Once I disconnected the tach output the fan worked fine under PWN control.

      Now from reading your info here I gather that the correct tach output is actually a grounding action so that if I have a PIC lined pulled high then the tach should pull it low. Weird thing is I actually tried an old Intel P4 CPU fan I have and it doesn't work either. So now I'm wondering just how I tell if a fan is suitable for use with tach feedback. The crappy fans I bought have a small PCB inside but no parts mounted. eg. a spot for a diode but no diode etc.

      So for others out there who get fans from your local parts bin type shop, beware that some fans fake their true functionality to look like a good deal.


  • At 24 July 2013, 7:12:49 user Giorgos Lazaridis wrote:   [reply @ Giorgos Lazaridis]
    • @Chris Sounds like brown out or noise on the supply. Probe the supply and see what is the problem. A few capacitors across the supply might work.

  • At 12 July 2013, 11:15:34 user Chris wrote:   [reply @ Chris]
    • Hi,
      I tried using this PWM technique with several 3 pin CPU fans I picked up. None of them work. I'm using a PIC and FET switch just as yours but every time I try to use PWM it just reboots the PIC as if it's shorting out or something. If I set it for 100%, alwyas on, then it works fine but of course with no speed control.

      Any ideas about this? Are there only some fans that work with PWM even though they have 3 pins. I can tap a 12V lead on the fan connector and pulse the speed very roughly but it seems like higher frequencies don't work. I tried very high like 46kHz and low like 700 Hz. Same result. Changing the PWM duty even 1 bit off 255 (max) causes shutdowns. I tried adding a resistor to GND on the PIC output to make sure it grounds when off, didn't help.

      Please, it's kind of important I get this to work but I'm stuck.

  • At 6 January 2012, 19:27:51 user Kammenos wrote:   [reply @ Kammenos]
    • @Chris well, as a matter of fact, the zener is not needed. What you need is to make sure that your output can sing the current of the motor (not the motor power but the motor tacho, which is a few miliamps maximum. You can put a small R2 (just to be safe) and R3 can be some 1K. Check pike\'s version:

      Look for R11-R12.

  • At 3 January 2012, 8:09:40 user Chris wrote:   [reply @ Chris]
    • This looks great except I'm wanting to use it with an FPGA I have that runs at 3.3V. I'm sure the R3 and R2 values need a slight adjustment but I'm unsure how to calculate it, ie. the reasoning. I assume replacing the 5.1V zener with a 3.3V one is needed. Is it possible to explain how 4.7K and 2.2K are determined?

  • At 15 December 2011, 16:15:52 user Kammenos wrote:   [reply @ Kammenos]
    • @bugssoren the problem is not caused by the potentiometer, since the pot is connected to the pic directly. Any spike would cause a bad reading from the PIC, but not a bad reading from the fan. It needs some software filters to avoid this problem. It is nothing special. A good quality fan may not produce error pulses.
      The pot cannot be connected as a rheostat, since the PIC reads voltage and not current (A/D converter).
      As for the speed set, there is absolutely no need for something more sophisticated than this. You may need to use PID if you put some other kind of input, for example a temperature sensor.

  • At 15 December 2011, 15:20:42 user bugssoren wrote:   [reply @ bugssoren]
    • Your \"slight problem\" is most probably caused by potentiometer wiper noise. Which is caused by mechanical bouncing over bumps in the resistance material. A small 0.01 or 0.1 uF capacitor from wiper to ground will usually take care of this.

      While I have not looked at your code, I assume intended or not, you use a bang-bang type control algorithm. Which usually behaves badly in response to large changes in commanded speed. Typically will overshoot and hunt several cycles before settling out. In extreme case can oscillate between zero and full speed, never settling out. A bit of potentiometer noise could be seen as a large command change.

      There are better algorithms like variants of a PID, which are more tolerant. But those would also require tuning to the individual characteristics of a fan model. Wouldn\'t be as universal without mods to the software for each fan.

      Another good engineering practice, is to connect the potentiometer wiper to one end of the potentiometer. Use the potentiometer in the variable resistor mode rather than voltage divider mode. Preferably connect wiper at the junction of R7 and R4. This way if the wiper should loose contact, it will failsafe to the lowest speed setting. Of course R6 and R7 have to be tweaked to get the proper range again.

  • At 29 January 2011, 23:21:53 user ToMikaa wrote:   [reply @ ToMikaa]
    • Dear Kammenos,

      I didn\'t know that a fan that doesn\'t send 50% duty cycle tachometer signal is exists. I am lucky because all my fans in my PC is using \'normal\' tacho signals so I can measure the speed without changing the PWM.

      Anyway, your circuit (and my poorly designed motherboard) inspired me to make my automatic fan controller with DS18B20 thermometers and 5 PWM controlled fans with tachometer reading.

  • At 29 January 2011, 21:16:34 user Kammenos wrote:   [reply @ Kammenos]
    • ToMikaa you are right of course, but that is not a general rule. This applies only in the case that the feedback of the fan is 50% duty cycle. This is most of the times true. As a matter of fact, i have 2 fans running this method, and i measure only half as well, but i was first sure that the above rule of the 50% applies. But to avoid misunderstandings, i had to measure a whole period for the circuit that i present in my site.
      As always, the circuits are open for anyone (like you) to make better. That is my goal after all. I always be happy to hear that someone was based on my circuit to make something better.

  • At 29 January 2011, 19:04:41 user ToMikaa wrote:   [reply @ ToMikaa]
    • Hi!

      At first, thank you for your schematics and the idea how to measure the speed of a 3-wire fan. I have built the circuit and tested it with several fans. It worked fine, but the speed fluctuation caused by the pulse stretching was very annoying so I have modified the measuring algorithm.

      Basically, you don't have to measure the whole tacho signal, just a half. You should measure the length of the high level and leave the PWM noisy low level alone. This half of the signal is clean because of the pull-up resistor and it's not affected by the PWM signal. The algorithm 'searches' this high level pulse and measures its length with a timer. With this value you can easily calculate the RPM of the fan without midifying the PWM and the speed of the fan. It works from at least 50 RPM.

  • At 29 January 2011, 8:19:25 user Pat Schram wrote:   [reply @ Pat Schram]
    • Thanks for the speedy reply and for clearing that up for me. Without that bit of info I probably would've been beating myself in the head wondering why I wasn't getting any output ;)

  • At 29 January 2011, 7:04:57 user Kammenos wrote:   [reply @ Kammenos]
    • Hi Pat. First of all, the articles do not expire ;) Kidding.
      So, R3 is the pull-up resistor for the fan's internal switching transistor (mosfet). Usually fans do not have a pull-up resistors and this is required by the motherboard (or your project). If you do not put this, the fan will never produce pulses.
      I've been using this method since i first post it for my PC fans, and works sweet!

  • At 29 January 2011, 5:43:56 user Pat Schram wrote:   [reply @ Pat Schram]
    • It's been a while since this was written so lets see if we get a response :P. I'm in the process of using an Atmel atmega328p to implement pulse stretching to control fans (why else would I be here). Judging from the schematic I'm guessing that R2 and D1 are used to create a voltage regulator as the voltage of the reverse biased zener will stay at 5.1V which is roughly TTL. I'm curious as to what R3 and the 12V hookup does. I would've thought that just having the zener/resistor regulator would be enough so what does R3 and the 12V hookup serve?


  • At 21 April 2010, 14:15:02 user Kammenos wrote:   [reply @ Kammenos]
    • Exactly Tom! The RPM feedback is there just to justify the goal that i get rpm feedback from a 3-wire PWM powered fan. I tested several methods and wrote a BLOG with all tests i made (http://pcbheaven.com/blogpages/PC_Fan_Controlling_Methods), yet the pulse stretching method is the most reliable and flexible one.

      As for the automatic regulation, i have already implement one circuit with this method (http://pcbheaven.com/circuitpages/PIC_3-Wire_Fan_RPM_Controller/). This is the one we had discuss some months ago. Yet, instead of a potentiometer i used 5 fixed speeds. I had 2 steps to change speed, fast change and slow change, depending on the offset i had from the requested speed. The sampling rate i found to be good is around 1 sample per second. Faster sampling will cause long overspeed and will need many cycles to set to center. Slower will take an age to set. In large changes i do have some overspeed, yet it is normal for an automatic controller circuit with such a slow response to duty cycle change.

      When i finish my new 4-channel DC controlled dimmer, i will make the system you just described. This is the last piece of my "DC motor controllers" collection. Then, i will go on with lighting and temperature (i am waiting some very interesting chips for thermocouple ice junction compensation - i have already post the thermocouple theory of operation).

      Oh, as for the display, the one you see is .... half fried. The black boxes on the display demonstrates just how the destruction evolved... I am waiting the new ones. I am not sure if i will include a display in the construction. And if i do, it will be a simple screen with the current and selected rpm speed.

  • At 21 April 2010, 6:38:39 user Tom Hargrave wrote:   [reply @ Tom Hargrave]
    • Now I understand more. The RPM feedback is only there to measure and display the speed of the fan and not for speed regulation. And this means that the pot setting really does not represent actual speed because actual speed is determined by the pot setting, fan model and loading on the fan blades. We already know that the fans tend to slow down as the blades get dusty which means you would need to manually adjust the pot to keep the fan speed constant.

      You are very close to RPM feedback regulation. All that's left is to do is to convert the tach measurement into a value that can be scaled and compared to the A/D value. Then you would increment or decrement the value written to the PWM register each measurement cycle depending on if the tach value were higher or lower than the A/D value and depending on how much difference.

      So, understanding that motors don't change speed instantly, you could scale what is written to the PWM so that huge RPM changes take several cycles to complete. The trick would be to change speeds at a reasonable rate without causing RPM over-run or hunting

      For example, if the difference were 5 or less you might update the PWM by the actual difference. But maybe more than 5 difference you might update the PWM by 5 plus a percent of the remaining difference with each measurement cycle. The percent you choose depends on how fast you want to ramp the motor speed up or down.

      When done, the pot position would actually represent the motor speed. You could set the motor to 1400 RPM and it would stay there, then you could set is down to 300 RPM and it would stay there!

      The final step would be to convert the pot A/D value to a RPM value that's displayed on the LCD beside the actual RPM. This way you could use the display feedback to change the pot setting to the speed you want then watch the motor speed change to that value.

      The second row of the display would show something like this if the pot were set to 800 RPM.
      Set:0800 Actual:0780

      Then if you were to change the pot to a higher input voltage that represented 1600 RPM the display would immediately show.
      Set:1600 Actual:0850

      The Actual would start moving up as the motor speed increased to catch up with the pot setting.
      Set:1600 Actual:0940
      Set:1600 Actual:1030
      Set:1600 Actual:1200
      Set:1600 Actual:1300
      Set:1600 Actual:1400
      Set:1600 Actual:1500
      Set:1600 Actual:1620
      Set:1600 Actual:1580
      Set:1600 Actual:1600

  • At 21 April 2010, 4:46:15 user Kammenos wrote:   [reply @ Kammenos]
    • no Tom, you are not missing something! The A/D value from the pot is transfered directly to the PWM register of the PIC (movf adresh,w
      | movwf ccpr1l). So the pot will change actually the duty cycle. As the 2 resistors sets actually the min and max voltage of the divider, they set the min and max duty cycle as well. But the min and max duty cycle will actually set the min and max rpm.
      One point: This circuit does not have a feedback rpm regulation. The duty cycle is not changed automatically. I plan to make one circuit like this in the near future though.

  • At 21 April 2010, 0:56:06 user Tom Hargrave wrote:   [reply @ Tom Hargrave]
    • I'm curious about your answer to Jared's comment. You state that you choose the resistors to set the min and max duty cycle.

      This isn't logical to me. It makes more since that the two resistors plus the pot would set the target RPM and feedback regulation would actually change the duty cycle to reach this target RPM. In this case, the 2 resistors would set the maximum and minumum RPM the motor could be set to.

      Maybe I'm missing something here?

  • At 20 April 2010, 18:28:52 user Kammenos wrote:   [reply @ Kammenos]
    • Hi Jared. First of all, i moved your comment to the correct page where it belongs.
      R6 and R7 can be totally omitted! I have put them to adjust the lower and higher voltage, so that the min and max duty cycle will be from 6 to 100%. I explain about them in the 3rd paragraph of the section "The circuit".

  • At 20 April 2010, 17:09:11 user jared wrote:   [reply @ jared]
    • So I\'m looking at the circuit. You mentioned that the circuit will read the voltage from 0-5v and convert that voltage to PWM.

      In the circuit I see you have a voltage divider going into RA1 R6@8.2k on the + and R7@330 on the -, wouldn\'t this drop the voltage down to 0.193V entering R4 the 5 KOhm potentiometer which would decrease that voltage even more?

      I\'m just wondering because if I put my voltage divider onto RA1 and send it 0-5V for control I don\'t want the magic smoke to come out haha.

      Sorry for all the questions I\'m still pretty new to this and just need to try and understand.

  • At 8 April 2010, 1:24:12 user Tom Hargrave wrote:   [reply @ Tom Hargrave]
    • I showed this circuit to a friend who's also a digital designer and he's going to use your concept for a PWM motor controller. But he wants to improve on the circuit and the software. With his permission, I'll let you know what he comes up with.

  • At 25 March 2010, 22:39:23 user Tom Hargrave wrote:   [reply @ Tom Hargrave]
    • I see parts for sale like PIC16F883-I/SP. Not being a PIC programmer, I need to know if your software will load & run on one of these. If so then I'll buy a few parts and experiment.

    reddit this Reddit this

     HOT in heaven!

    NEW in heaven!

    New Theory: AC electric motor working principle

     Contact     Forum     Projects     Experiments     Circuits     Theory     BLOG     PIC Tutorials     Time for Science     RSS   

    Site design: Giorgos Lazaridis
    © Copyright 2008
    Please read the Terms of services and the Privacy policy