int pwmPin = 10; // fan PWM -> connected to digital pin 9 int pwmVal = 0; int DEBUG = 1; // DEBUG counter; if set to 1, will write values back via serial // 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() { pinMode(pwmPin, OUTPUT); // sets the pin as output if (DEBUG) { Serial.begin(9600); Serial.println('Serial Init'); } // 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 = 0; OCR1AL = 79; // 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); } // 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 } // Main program void loop() { analogWrite(pwmPin, pwmVal); if (DEBUG) { // If we want to read the output if (pwmVal < maxFanSpeed) { pwmVal += 2; Serial.println(pwmVal); // Print red value } else { pwmVal = 0; Serial.println('at max high'); // Print red value } } delay(1000); // Pause for 'wait' milliseconds before resuming the loop }