Controlling Speed of PWM Fan

Hi there,

So I'm working in a project where I need to vary the speed of a PWM fan using an Arduino. Later on, I'll want to measure the wind speed using hot-wire wind sensor.

I'm currently using a slightly modified code from this video: DIY Arduino PWM PC Fan Controller (Part 2) [Serial Control for Tuning] #0001 - YouTube

Here's the original code used in the video: arduino-pwm-fan-serial-control--for-tuning-/fan_serial_commander.ino at master · catalystoftechnology/arduino-pwm-fan-serial-control--for-tuning- · GitHub

All I changed from the original, was set the code such that I'm only controlling one fan instead of 5 different ones. I expected it to be a simply task but unfortunately I'm having a lot of trouble with this and I'm out of ideas.

Basically, when I upload the code into the board and open the serial monitor, the page starts getting rapidly filled with the message "Front:0". I'm also unable to change the fan speed at all, I'm able to input values for fan speed but nothing changes.

Here is the code that I'm using:

// variable declarations
int fanSpeed = 0;
String command;
char werd;
int currentFan = 0;
int front_a = 5;
int frontSpeed = 0;
int commandCheck;
String frontMarker = "-> ";
void setup() {
pinMode(2, OUTPUT);
digitalWrite(2, HIGH);
pinMode(4, INPUT);

// fans
pinMode(5, OUTPUT);//front 140mm
analogWrite(5,0);
Serial.println();
}

void loop(){
// this is what reads your serial commands
while ( Serial.available() > 0 ) {
// small delay because it can only deliver the bytes so quickly
delay(5);
// you have to read one byte (one character) at a time
werd = Serial.read();
// append the character to our "command" string
command += werd;
}
// clear serial so it's ready for your next command
Serial.flush();
if ( command.length() > 0 ) {
commandCheck = 0;
if ( command == "front" ) {
currentFan = 0;
frontMarker = "-> ";
} else {
// flag so we know it wasn't a change fan command
commandCheck = 1;
}
if ( commandCheck == 1 ) {
// the ".toInt()" appended to the command variable is to convert
// the user entered "command" from a string into an integer so
// that we can use it to set the pin's PWM pulse width
// (it'll error if you send an integer in string format)
if ( currentFan == 0 ) {
//front
analogWrite(front_a, command.toInt());
frontSpeed = command.toInt();
} else if ( currentFan == 1 ) {
} else {
//unknown command
}
}
command = "";
Serial.print(frontMarker);
Serial.print("Front: ");
Serial.println(frontSpeed);
// this function (below) is just to print a ton of empty lines so that the UI "appears" to be refreshing like a screen.
// you'll have to set your serial monitor to a certain width to get that effect to work correctly, of course
clear();
}
}

void clear() {
Serial.println();Serial.println();Serial.println();Serial.println();Serial.println();Serial.println();Serial.println();Serial.println();Serial.println();Serial.println();Serial.println();
Serial.println();Serial.println();Serial.println();Serial.println();Serial.println();Serial.println();Serial.println();Serial.println();
Serial.println();Serial.println();Serial.println();Serial.println();Serial.println();
}

My current setup has the blue wire from the fan connected to the 5th PWM pin in the Arduino. The GND and 12V wires are not connected to the Arduino directly, instead, I have a PSU hooked directly to the fan to power it up. Lastly, the green fan wire is not connected to the board. I know it's supposed to work as a tachometer, but I'm not sure where to plug it in based on the provided code.

Lastly, I'm using a 12V 120mm Noctua PWM fan and an Arduino UNO as my board.

Any help and suggestions are greatly appreciated!

Read the rules. Post your code correctly.
Post all your code not just part of it like you have done.
Provide links to your fan type and post a schematic of your wiring.

I must say the clear function is one of the more stupid functions I have ever seen. Use a for loop for god sake.

Total newb here, also looking into a fan control project.

The fan and the arduino probably need to share a common ground, otherwise 5v from the arduinos point of view on the PWM line may look like who knows what to the fan.

I've seen that video and wondered how it worked. By default I thought Arduino generated PWM at 490Hz but fan control operates at 25KHz.

You might be interested in this...
http://forum.arduino.cc/index.php?topic=117425.0

Hi,

I've seen that video and wondered how it worked. By default I thought Arduino generated PWM at 490Hz but fan control operates at 25KHz.

You are not directly controlling the current to the motor windings.
The control circuit inside the fan, interprets the PWM duty and then converts that to a speed level.
This level is then used as the setpoint speed for the phase control circuitry.

Tom..... :slight_smile:

Maybe I should clarify that earlier comment, it has nothing to do with power delivery. I'm referring to the documentation for the analogWrite() function.

Writes an analog value (PWM wave) to a pin. Can be used to light a LED at varying brightnesses or drive a motor at various speeds. After a call to analogWrite(), the pin will generate a steady square wave of the specified duty cycle until the next call to analogWrite() (or a call to digitalRead() or digitalWrite() on the same pin). The frequency of the PWM signal on most pins is approximately 490 Hz. On the Uno and similar boards, pins 5 and 6 have a frequency of approximately 980 Hz. Pins 3 and 11 on the Leonardo also run at 980 Hz.

analogWrite() - Arduino Reference

The code posted in the original post is calling analogWrite(duty_cycle) which, according to those docs, will put a 490Hz PWM signal on on the pin with the requested duty_cycle. Yet, the carrier frequency that should be used for the PWM fan control signal is 25KHz. Here's a link to a spec for how 4pin fan control is supposed to work.

http://www.formfactors.org/developer\specs\4_Wire_PWM_Spec.pdf