#include <PWMFrequency.h>
#include <SimpleTimer.h>
// NUMBER OF FAN NPUTS
#define FAN_COUNT 2
// The Pins For Fan Input
const byte FAN_RPM_PIN[] = { 0, 1 };
// Interrupts that fans are attached to.
#define FAN1_INTERRUPT 2
#define FAN2_INTERRUPT 3
// Time between controlling the Fans
#define FAN_CONTROL_PERIOD 5000
// Number of Output Fan Control PWM's
#define FAN_CONTROL_COUNT 1
// PWM Fan Speed Voltage OUTPUT
const byte FAN_CONTROL_PWM[] = { 9 } ;
// Prescale Values for controlling PWM
const int FAN_CONTROL_PWM_PRESCALE[] = {1};
// Values in RPM
#define OFF_FAN_VALUE 100
#define MIN_FAN_VALUE 1200
#define MAX_FAN_VALUE 5000
// A general purpose timer, and some misc constants
SimpleTimer timer = SimpleTimer();
//
// ========================================
// MAIN ARDUINO SETUP (1x during startup)
// ========================================
//
void setup () {
setFanContolTarget(2100); // Set the RPM Value
}
//
// ========================================
// MAIN ARDUINO LOOP (Called Repeatidly)
// ========================================
//
void loop () {
timer.run();
}
//
// ----------
// RPM INPUTS
// ----------
//
volatile long fanRotationCount[FAN_COUNT];
unsigned long fanTimeStart[FAN_COUNT];
void interruptFan1() {
fanRotationCount[0]++;
}
void interruptFan2() {
fanRotationCount[1] ++;
}
void interruptFan3() {
fanRotationCount[2] ++;
}
int getFanRPM( byte fan ) {
static boolean started = false;
if (!started) {
started = true;
for ( byte fan=0; fan<FAN_COUNT; fan++ ) {
// Start Up the RPM by setting PIN
pinMode(FAN_RPM_PIN[fan],INPUT_PULLUP);
}
//and attaching interrupt
#ifdef FAN1_INTERRUPT
attachInterrupt(FAN1_INTERRUPT,interruptFan1,FALLING);
#endif
#ifdef FAN2_INTERRUPT
attachInterrupt(FAN2_INTERRUPT,interruptFan2,FALLING);
#endif
#ifdef FAN3_INTERRUPT
attachInterrupt(FAN3_INTERRUPT,interruptFan3,FALLING);
#endif
}
// pulses counted; /2 pulses per rotation; *60000 milliseconds per minute; /millis elapsed
double ret = fanRotationCount[fan] /2L *60000L / ( millis() - fanTimeStart[fan] );
fanRotationCount[fan] = 0;
fanTimeStart[fan] = millis();
return ret;
}
//
// --------------------------
// Fan Output Control
// --------------------------
//
// The output Fan RPM (or mVolts for LM317) we desire
int targetFanValue = MIN_FAN_VALUE;
// Set the Target Fan RPM ( cVolt LM317) for a specified Fan
// this can be used for independant Fan Control.
// Legacy Mode only support a singe (0) target
void setFanContolTarget(int value) {
// set the target voltage
targetFanValue = value;
// init the controller
initFanController();
}
boolean debugFans = true;
int fanControlTimer = -1; // timer that controls fan voltages
void initFanController() {
if (fanControlTimer>=0) return;
// set up the three PWM outputs
for ( byte fan=0; fan<FAN_CONTROL_COUNT; fan++ ) {
digitalWrite(FAN_CONTROL_PWM[fan],HIGH); // ensures minimum voltage
pinMode(FAN_CONTROL_PWM[fan],OUTPUT); // PWM Output Pin For Fan
setPWMPrescaler(FAN_CONTROL_PWM[fan],FAN_CONTROL_PWM_PRESCALE[fan]); // Sets 31.25KHz / 256 = 122Hz Frequency
}
// setup a timer that runs every 50 ms - To Set Fan Speed
fanControlTimer = timer.setInterval(FAN_CONTROL_PERIOD,readInputSetFanPWM);
}
// Just Default Mid Range PWM Values
byte currentPWM[] = { 30, 30, 30 };
byte getCurrentPWM(byte fan) {
return currentPWM[fan];
}
void readInputSetFanPWM() {
// Average to the Two Fans RPMS Speeds
int currentFanValue = ( getFanRPM(0) + getFanRPM(1) ) / 2;
//byte factor = 1;
byte factor = compareCurrentAndTarget(currentFanValue,targetFanValue);
if ( currentFanValue > targetFanValue ) {
// Slow fans down slowely, rather than hard off.
// increasing PWM duty, lowers the voltage
currentPWM[0] = currentPWM[0]<=(255-factor) ? currentPWM[0]+factor : 255;
} else if ( currentFanValue < targetFanValue ) {
// Slowly ramp up the fan speed, rather than hard on.
// decreasing PWM duty, increases the voltage
currentPWM[0] = currentPWM[0]>=factor ? currentPWM[0]-factor : 0;
}
if ( debugFans ) {
Serial.print(factor);
Serial.print(F("\t"));
Serial.print(targetFanValue);
Serial.print(F("\t"));
Serial.print(currentFanValue);
Serial.print(F("\t"));
Serial.print(currentPWM[0]); // Current PWM
Serial.println();
}
// write the PWM
analogWrite(FAN_CONTROL_PWM[0],currentPWM[0]);
}
// <5% - then 0
// <10% - then just inc / dec by 1
// <20% - 3
// <50% - 5
// >50% - 10
byte compareCurrentAndTarget(int current, int target) {
int diff = current-target;
if (diff < 0) diff = diff * -1;
byte percent = 100.0f* (float)diff / (float)target;
if (percent<5) {
return 0;
} else if (percent <20) {
return 1;
} else if (percent <30) {
return 2;
} else if (percent <40) {
return 3;
} else if (percent <50) {
return 4;
}
return 5;
}