AVR microcontroller based PWM fan controllers

If you’d like a fan controller kit please email me at blog@zakkemble.co.uk
Kit: £10
Post: £2 if you’re in the UK, otherwise £4
Microcontroller will come programmed and ready to go.
Only available while stocks last!

So this is a bit of a continuation on my 555 timer based PWM controllers, but now using microcontrollers and MOSFETs instead of 555 ICs and transistors. I made 2 versions, one with switches for speeding up and down and the other with a potentiometer like the previous controllers. I used ATtiny25 controllers running at 31.25KHz (8MHz internal RC / 256 prescaler) with a 3.3V supply, the MOSFETs I used are STP36NF06L with 0.045Rds and 2.5Vgs max, perfect for 3.3V, the MOSFETs only generate ~180mW of heat at 2A ((0.045Rds * (2A * 2)) = 0.18W) so no heatsink needed, you can barely feel them getting warm.

In the schematics change R1 from 100R to 150R if you use a 5V supply to keep the current under 40mA (remember, MOSFET gates need to be charged and discharged and doing this without a resistor is going to send large currents though the uC), the zener diodes D1 and D2 are for ESD protection and need to be rated somewhere between a few volts above the uC supply voltage and below the max gate voltage for the MOSFET, usually 20V, I used 12V zeners, they can be removed if you think you don’t need them, some MOSFETs have them built in. D2 is not actually needed even if you do want ESD protection since we aren’t using any negative voltages at the MOSFET gate.
The STP36NF06L MOSFETs can easily switch ~8A as they are in the circuits, but some heatsinking will be needed and a 5V supply is recommended, wiring up 2 MOSFETs in parallel will reduce total heat generated (make sure they’re both on the same heatsink), but don’t forget appropriate gate resistors like a 56R which then splits to two 150R which go to the gates, max gate current will then be ~39mA. The potentiometer can be almost any value, but too high will cause the microcontroller ADC to return incorrect readings and too low will cause excessive current drain, I used 22K since it was on special offer for £0.17 instead of £0.43, but anywhere between 4.7K and 22K will be fine.

Update 2013-07-10
New SMD edition using an ATtiny5/10 microcontroller and DMG6968U MOSFET (has built-in zener diodes for ESD protection), no problem switching 2-3A.


fanController_20130710.zip (203 kB)
Source code, EAGLE schematic and board layout files
Downloaded 2426 times
MD5: 4C794E8C2CAB0CE65C79DDAF65E04CC2

fanController_20120803.zip (179.94 kB)
Source code, EAGLE schematic and board layout files
Downloaded 1146 times
MD5: A862B6D96A8FCF6A0CE9C9DF90B749EB

fanController_20120802.zip (179.69 kB)
Source code, EAGLE schematic and board layout files
Downloaded 708 times
MD5: 680379F31E75CB81A86E62E2B5727786

fanController_20120729.zip (179.02 kB)
Source code, EAGLE schematic and board layout files
Downloaded 712 times
MD5: C0BDAD5FBF993473E65380AFB7F87193


Skip to comment form

  1. Invalid data in file fanController_analogue.sch!
    Invalid data in file fanController_analogue.brd!

    Invalid data in file fanController_digital.sch!
    Invalid data in file fanController_digital.brd!

    I’m running Eagle Version 5.4.0 for Windows Professional Edition

    Any ideas why the files seem to be corrupt?

    1. Hey, the board and schematic were made in 6.2.0 Light Edition, 6 and newer save files in a different way which earlier versions don’t support.

    • serjio on March 5, 2013 at 12:07 am
    • Reply

    Could you please be more specific, what’s the rated voltage/current of the fans, and what’s the supply voltage of the device?

    1. Its designed for PC fans which are normally 12V, the current will depend on the fan, normal PC fans usually take less than 0.5A, but I was using a server fan taking up to 3A. The MOSFET should be able to switch 8A before it gets too hot without a heatsink. The minimum voltage for the controller part is 3.5V since it goes to a 3.3V LDO regulator.

    • Hadi on December 9, 2013 at 1:42 pm
    • Reply

    Thank you

    • Yogesh kumar on January 24, 2014 at 11:51 am
    • Reply

    hey….can you share the basic algorithm of pwm fan controller .

    It has temperature sensing or not …as i saw the schematic there is no sensor ..plz describe

    1. It’s manual control, turn the potentiometer to adjust fan speed. Algorithm is just set the PWM value to what the ADC reads from the potentiometer (a value 0 – 255).

    • Thomas Huber on February 17, 2014 at 2:32 pm
    • Reply

    I tried to make a PWM Digital Controller based on your design with following specs:
    PWM Frequency: 10Hz (or 1Hz, 2 Hz, 5Hz)
    Duty Cycle : 0 – 100% 12 Steps (0,10,20,30,40,50,60,70,75,80,90,100%)
    uP : ATTNY25, 8MHz Internal Clock
    Dev SW: Atmel Studio 6.1
    Dev Board: STK500

    My problems are:
    1. How and where to change the CPU Speed in your C Source that i can meet the abopve specs as well meet the duty cycles
    I will use the solution for controlling an SSR which drives an 50Hz Load . This should be an sinus-wave packet controller
    2. How to make the compiler the digital version or the analog versioin if needed

    Thanks for helping me

    1. Hi, config.h contains the settings for the CPU clock divider (CPU_DIV, change it to clock_div_1) and analog or digital mode (CFG_INPUT). To change F_CPU go to the Project properties > Toolchain > AVR/GNU C Compiler > Symbols and you should see an entry “F_CPU=31250” in Defined symbols, double click it and change it to “F_CPU=8000000UL”.

        • Thomas Huber on February 18, 2014 at 12:02 am
        • Reply

        I made following:
        I have load your HEX file which you have distributed (your last version). I tried with this file and had following results:
        On my oscilloscopei have a PWM Frequency of ~61 Hz. I can increase and decrease the Dutycycle as described. Power Off and Power on is functioning perfect (Data saved in EEPROM) .

        Now i have changed in config.h following:
        //#define F_CPU 31250 // If yo…………… (nothing changed)
        #define CPU_DIV clock_div_256 // 8MHz / 256 = 31.25KHz

        //#define CFG_INPUT MODE_ANALOGUE
        #define CFG_INPUT MODE_DIGITAL

        Set In AVR/GNU C>Symbols:

        Compile without any errors and load to CPU. Must be the same HEX File you have made.
        Result: No functioning HEX File
        No respond to keys or any PWM Signal

        What else could i have forgotten?
        How do you calculate the right PWM frequency with F_CPU, CPU_DIV
        I must have an PWM Frequency of 1Hz (or 2 resp 5Hz)

        Could you write this programm for me with the above mentioned specs. Will pay for it. I am lost

        1. Alright then, I’ve sent you an email.

    • Thomas Huber on February 18, 2014 at 11:51 pm
    • Reply

    Sorry the e-mail adress [removed] is wrong !!!!

    You must use instead : [removed]

    1. I’ve resent the email 🙂

        • Thomas Huber on February 21, 2014 at 9:14 pm
        • Reply

        Thank you for your e-mail.
        I have found following solution to get the right PWM frequency of (~2 Hz) which is ok.
        It uses Timer0 in PWM Mode. See code


        int main (void)
        // Use Timer0, Output on Pin PB0 (-> OC0A Pin for Timer0 tiny25)

        DDRB = (1<<DDB0) ;
        PORTB = (1< Fpwm=Fclk/(prescalefactor x 510)
        // 3 1 1 0 Fast PWM -> Fpwm=Fclk/(prescalefactor x 256)
        // 4 0 0 1 Reserved not usable
        // 5 1 0 1 PWM Phase Correct
        // 6 0 1 1 Reserved
        // 7 1 1 1 Fast PWM

        // Compare Match Output Modes: in Register TCCR0A
        // Mode COM0A0 COM0A1
        // 0 0 0 Normal Port Operation (OC0A/OC0B disabled
        // 1 1 0 Reserved
        // 2 0 1 Clear OC0A/OC0B on Compare Match (non inverting mode)
        // 3 1 1 Set OC0A/OC0B on Compare Match ( inverting mode)

        // Prescaler Setup CS00, CS01 CS02 in Register TCCR0B
        // Mode CS00 CS01 CS02 Factor
        // 0 1 0 0 No prescaling
        // 1 0 1 0 clk/8
        // 2 1 1 0 clk/64
        // 3 0 0 1 clk/256
        // 4* 1 0 1 clk/1024

        // Note: * = used in Example below

        TCCR0A= (1<<WGM00) | (0<<WGM01) | (1<<COM0A0) | (1<<COM0A1);

        TCCR0B=(0<<WGM02) | (1<<CS00) | (0<<CS01) | (1< +Duty = ~80%, With Mode 2 +Duty = ~20%


        return 1;
        Now we have to build the digital PWM version with this type of generating PWM

        The project i have mentioned to pay for will be extended . I have no Paypal account but we can setup an professional solution with some extended specification. I will contact you direct on your e-mail adress.

        Our contact is:

        Varionix GmbH
        Unterbrüglenweg 7
        CH-6340 Baar
        Phone +41 41 7200742
        e-mail: thomas.huber@varionix.ch

        Could you give us your direct e-mail or phone Nr so we can discuss the project .


    • FreshMan on December 2, 2014 at 2:39 pm
    • Reply

    Hi 🙂
    what program do you draw the diagram ?

    1. EAGLE CAD

    • Fred on May 17, 2018 at 10:44 pm
    • Reply


    Thank you for sharing your design. Excellent!

    Would you please advise how to set the output frequency to 100-500 Hz? I want to use this to dim an led driver which needs that range. With the current code I am reading 1-30KHz.

    Thank you very much for your consideration.

    1. Hey Fred, at the moment it runs at ~62Hz. To run at other frequencies you’ll need to change the CPU prescaler value (clock_prescale_set() function in init()) and the timer prescaler setting (TCCR0B register in init()). The code is pretty well commented so it should be pretty easy to see what everything does. The ADC prescaler might also have to be adjusted so it doesn’t run too fast if you increase the CPU speed.

Leave a Reply

Your email address will not be published.

Are you human? *