1

So lately I've been trying to control the speed of a 120mm 4-pin computer fan using PWM. This is what I've got so far, with the part above void loop() being from this thread

// Definition of Arduino type
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define  IS_MEGA  (1)
#define  IS_UNO   (0)
#else
#define  IS_MEGA  (0)
#define  IS_UNO   (1)
#endif

// Analog output (i.e PWM) pins. These must be chosen so that we can change the PWM frequency without affecting the millis()
// function or the MsTimer2 library. So don't use timer/counter 1 or 2. See comment in setup() function.
// THESE PIN NUMBERS MUST NOT BE CHANGED UNLESS THE CODE IN setup(), setTransistorFanSpeed() AND setDiodeFanSpeed() IS CHANGED TO MATCH!
#if IS_UNO
// On the Uno we can only use the OC1B pin, so these pin numbers are both 10
const int transistorFanPin = 10;     // OC1B
const int diodeFanPin = 10;          // OC1B
#else
// On the Mega we use OC1B and OC1C
const int transistorFanPin = 12;     // OC1B
const int diodeFanPin = 13;          // OC1C
#endif

// Definitions for PWM fan control
const unsigned char maxFanSpeed = 80;   // this is calculated as 16MHz divided by 8 (prescaler), divided by 25KHz (target PWM frequency from Intel specification) 

void setup()
{
  // Set up the PWM pins for a PWM frequency close to the recommended 25KHz for the Intel fan spec.
  // We can't get this frequency using the default TOP count of 255, so we have to use a custom TOP value.

#if IS_UNO

  // Only timer/counter 1 is free because TC0 is used for system timekeeping (i.e. millis() function),
  // and TC2 is used for our 1-millisecond tick. TC1 controls the PWM on Arduino pins 9 and 10.
  // However, we can only get PWM on pin 10 (controlled by OCR1B) because we are using OCR1A to define the TOP value.
  // Using a prescaler of 8 and a TOP value of 80 gives us a frequency of 16000/(8 * 80) = 25KHz exactly.
  TCCR1A = (1 << COM1B1) | (1 << COM1B0) | (1 << WGM11) | (1 << WGM10);  // OC1A (pin 9) disconnected, OC1B (pin 10) = inverted fast PWM  
 #ifdef FAN_AUDIO_TEST
  // test code to get 440Hz output (= concert A) to test the logic 
  OCR1AH = 0;
  OCR1BL = 71;  // 50% duty cycle 
  TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12);  // TOP = OCRA, prescaler = 256

  OCR1AL = 141; // TOP = 141, 16000000 / (256 * 142) = 440.014
  OCR1BH = 0;
 #else
  OCR1AH = 79;
  OCR1AL = 0;  // TOP = 79
  TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);  // TOP = OCR0A, prescaler = 8

  OCR1BH = 0;
  OCR1BL = maxFanSpeed;  // max fan speed (i.e. pin 5 initially low all the time)  
 #endif

  TCNT1H = 0;
  TCNT1L = 0; 
#else

  // On the Mega we use TC1 and OCR1B, OCR1C
  TCCR1A = (1 << COM1B1) | (1 << COM1B0) | (1 << COM1C1) | (1 << COM1C1) | (1 << WGM11) | (1 << WGM10);  // OC1A disconnected, OC1B = OC1C inverted fast PWM  
  TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);  // TOP = OCR1A, prescaler = 8
  TCCR1C = 0;
  OCR1AH = 0;
  OCR1AL = 79;  // TOP = 79

  OCR1BH = 0;
  OCR1BL = maxFanSpeed;
  OCR1CH = 0;
  OCR1CL = maxFanSpeed;

  TCNT1H = 0;
  TCNT1L = 0;
#endif

  // We have to enable the ports as outputs before PWM will work.
  pinMode(transistorFanPin, OUTPUT);
  pinMode(diodeFanPin, OUTPUT);
  pinMode(A0, INPUT);
  Serial.begin(9600);
}

// Set the transistor fan speed, where 0 <= fanSpeed <= maxFanSpeed
void setTransistorFanSpeed(unsigned char fanSpeed)
{
  OCR1BH = 0;
  OCR1BL = fanSpeed;
}

// Set the diode fan speed, where 0 <= fanSpeed <= maxFanSpeed
void setDiodeFanSpeed(unsigned char fanSpeed)
{
#if IS_UNO
  OCR1BH = 0;
  OCR1BL = fanSpeed;
#else
  OCR1CH = 0;
  OCR1CL = fanSpeed;
#endif
}

void loop() {
  if (analogRead(A0) >= 800) {
    setTransistorFanSpeed(80);
    Serial.println("HIGH");
    Serial.println(analogRead(A5));
  } else {
    setTransistorFanSpeed(0);
    Serial.println("LOW");
    Serial.println(analogRead(A5));
  }
  delay(100);
  Serial.println("I'm running.");
}

In the serial monitor I'm getting the output I'm expecting ("HIGH" and 1023 when I've bridged the arduinos 5V pin to A0), but the signal doesn't seem to have any effect on the fan at all. In the thread linked above there's talk about this being an inverted fast PWM signal, and that it's assumed I'm using an opto isolator. Could this be why the signal doesn't have an effect on the fan? If anyone out there has any experience on this and are able to help me, that would be greatly appreciated.. :)

  • How did you connect the fan? What does "no effect" mean? Is the fan not running, or doesn't it run slower than usual? More info on these kinds of fans – Gerben Jul 4 '14 at 13:04
  • The fan runs at full speed with and without a PWM signal. – Pebbe Jul 4 '14 at 14:58
  • @Gerben also, I connected the fan correctly according to the article you linked. Negative and positive power directly connected to a 12V power supply, and the 4th pin (PWM) to the arduino. – Pebbe Jul 4 '14 at 15:03
  • 1
    Did you connect the ground of the fan (/12volt powersupply) to the ground of the arduino? If you don't connect the grounds, there is no path for electrons to flow. – Gerben Jul 4 '14 at 19:13
  • 1
    @Gerben thanks, this solved it for me. :) – Pebbe Jul 5 '14 at 15:50
3

You need to connect the ground of the fan (/12volt power-supply) to the ground of the Arduino. If you don't connect the grounds, there is no path for electrons to flow.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.