How to Control Computer Fan with RPM input #CHEMISTRY

Hi, I am a Chemistry student working on building a program that controls a computer fan based on RPM input. Currently, the user has to modify the duty cycle. For instance, the user has to enter a range from 0-255 to set the max speed of the computer fan using Arduino’s analogwrite function

Currently, I have a touch interface, is there a formula that converts the rpm input into the appropriate analogwrite duty cycle?

Here is my source code:

#include <SPI.h>
#include <TFTv2.h>
#include <stdint.h>
#include <elapsedMillis.h>
#include <SeeedTouchScreen.h>
#define RAMP 5 // default ramp
#define SPEED 255 // default RPM
#define INTERVAL 30 // default time interval (secs)
#define MAX_RAMP 25 // max amount of ramp up
#define MIN_RPM 5 // duty cycle
#define BUFF 5 // size of num display
#define DELAY 450 // 300 milisecs

elapsedMillis timeElapsed; //declare global if you don’t want it reset every time loop runs

// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// The 2.8" TFT Touch shield has 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM); //init TouchScreen port pins
int ramp = RAMP;
int rpm = SPEED;
int interval = INTERVAL;
char rampBuf[BUFF];
char rpmBuf[BUFF];
char intvlBuf[BUFF];
int pwmPin = 13;
int control = 7;

// rpm/pulse read
int fanPulse = 0;
unsigned long pulseDuration;

// timer stats
int initial_t = 0;
int final_t = 0;
int bfRamp_t = 0;
int afRamp_t = 0;

void setup()
{
//turn on the background light
TFT_BL_ON;

pinMode(control, OUTPUT); // set pin to input
digitalWrite(control, LOW); // turn on pullup resistors

Serial.begin(115200);
Serial.print(“Start”);
initial_t = timeElapsed;
Serial.println(timeElapsed);

//init TFT library
Tft.TFTinit();

/* Demo of draw circle’s API
drawCircle(int poX, int poY, int r,INT16U color);
fillCircle(int poX, int poY, int r,INT16U color);
*/

// button 1
Tft.fillCircle(40, 40, 30,RED);
Tft.drawString(“R”,80,30,3,CYAN);
Tft.drawString(“5”,130,30,3,CYAN); // display default ramp rmp

// button 2
Tft.drawString(“S”,80,101,3,CYAN);
Tft.fillCircle(40, 110, 30,GREEN);
Tft.drawString(“255”,130,101,3,CYAN); // display default rmp

// button 3
Tft.drawString(“I”,80,170,3,CYAN);
Tft.fillCircle(40, 180, 30,BLUE);
Tft.drawString(“30”,130,170,3,CYAN);

// reset
Tft.fillRectangle(90,230,60,60,YELLOW);
Tft.drawString(“Reset”,90,300,2,RED);

// play/start
Tft.fillRectangle(170,230,60,60,CYAN);
Tft.drawString(“Start”,170,300,2,RED);

Tft.drawString(“R:Ramp”,4,230,2,RED);
Tft.drawString(“S:RPM”,4,250,2,RED);
Tft.drawString(“I:Time”,4,270,2,RED);

// fade in from min to max in increments of 5 points:
for(int fadeValue = 0; fadeValue <= 255; fadeValue += 5)
{
// sets the value (range from 0 to 255):
analogWrite(pwmPin, fadeValue);
// wait for 30 milliseconds to see the dimming effect
delay(30);
}

// fade out from max to min in increments of 5 points:
for(int fadeValue = 255; fadeValue >= 0; fadeValue -= 5)
{
// sets the value (range from 0 to 255):
analogWrite(pwmPin, fadeValue);
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
}

void loop()
{
// a point object holds x y and z coordinates
Point p = ts.getPoint();

// long map(long x, long in_min, long in_max, long out_min, long out_max)
p.x = map(p.x, TS_MINX, TS_MAXX, 240, 0);
p.y = map(p.y, TS_MINY, TS_MAXY, 320, 0);

// we have some minimum pressure we consider ‘valid’
// pressure of 0 means no pressing!
if(p.z > __PRESURE)
{
// ramp
if(p.y > 260 && p.y < 290 && p.x > 180)
{
ramp_action();
}

// rpm
if(p.y > 200 && p.y < 230 && p.x > 180)
{
rpm_action();
}

// interval
if(p.y > 140 && p.y < 170 && p.x > 180)
{
interval_action();
}

// reset
if(p.y > 30 && p.y < 100 && p.x > 100 && p.x < 160)
{
// test
Tft.fillRectangle(90,230,60,60,BLUE);
reset();
}

// start
if(p.y > 30 && p.y < 100 && p.x < 70)
{
// start the fan!
digitalWrite(control, HIGH); // turn on pullup resistors
Tft.fillRectangle(170,230,60,60,BLUE);
bfRamp_t = timeElapsed;
Serial.println(“Before Ramp”);
Serial.println(timeElapsed);
ramp_up();
bfRamp_t = timeElapsed;
Serial.println(“After Ramp”);
Serial.println(timeElapsed);
timeElapsed = 0;

// milliseconds = seconds x 1,000
int newInterval = interval * 1000;
// while(timeElapsed < 30)
// {
// runner();
// }
Serial.println(“Done”);
Serial.println(timeElapsed);
digitalWrite(control, LOW); // turn on pullup resistors
}
}

Tft.drawString(rampBuf,130,30,3,CYAN);
Tft.drawString(rpmBuf,130,101,3,CYAN);
Tft.drawString(intvlBuf,130,170,3,CYAN);
}

void ramp_action()
{
int increment = 5;
ramp+=increment;
if(ramp > MAX_RAMP)
{
// do not allow it to exceed more than 25
ramp = MAX_RAMP;
}
String num = String(ramp);
num.toCharArray(rampBuf, BUFF);
Tft.drawString(rampBuf,130,30,3,CYAN);
delay(DELAY);
Tft.fillRectangle(130,30,90,30,BLACK);
}

void rpm_action()
{
int decrement = 25;
rpm-=decrement;
if(rpm <= 5)
{
// do not allow the duty cycle to be negative!
rpm = MIN_RPM;
}
Serial.print(rpm);
String num = String(rpm);
num.toCharArray(rpmBuf, BUFF);
Tft.drawString(rpmBuf,130,101,3,CYAN);
delay(DELAY); // wait a little before you erase the text
Tft.fillRectangle(130,100,90,30,BLACK);
}

void interval_action()
{
int increment = 15;
interval+=increment;
String num = String(interval);
num.toCharArray(intvlBuf, BUFF);
Tft.drawString(intvlBuf,130,170,3,CYAN);
delay(DELAY);
Tft.fillRectangle(130,170,90,30,BLACK);
}

void reset()
{
// reset all default values
ramp = RAMP;
rpm = SPEED;
interval = INTERVAL;
Tft.fillCircle(40, 40, 30,BLUE);
Tft.fillCircle(40, 110, 30,RED);
Tft.fillCircle(40, 180, 30,GREEN);
Tft.fillRectangle(170,230,60,60,YELLOW);
Tft.fillRectangle(90,230,60,60,CYAN);
String reset = “”;
reset.toCharArray(rampBuf, BUFF);
reset.toCharArray(rpmBuf, BUFF);
reset.toCharArray(intvlBuf, BUFF);
Tft.fillRectangle(130,30,90,30,BLACK);
Tft.fillRectangle(130,100,90,30,BLACK);
Tft.fillRectangle(130,170,90,30,BLACK);
Tft.drawString(“5”,130,30,3,CYAN);
Tft.drawString(“255”,130,101,3,CYAN);
Tft.drawString(“30”,130,170,3,CYAN);
digitalWrite(control, LOW); // turn on pullup resistors
}

void ramp_up()
{
analogWrite(pwmPin, 255);
delay(500); // 500 mili secs = .5 secs
delay(500);
delay(500);
delay(500);

// fade out from max to min in increments of 5 points:
for(int fadeValue = rpm; fadeValue >= 0; fadeValue -=ramp)
{
// sets the value (range from 0 to 255):
analogWrite(pwmPin, fadeValue);
// wait for 500 milliseconds to see the dimming effect
delay(1000); delay(1000);
}
}

void runner()
{
analogWrite(pwmPin, rpm);
}

// void readPulse()
// {
// pulseDuration = pulseIn(fanPulse, LOW);
// double frequency = 1000000/pulseDuration;

// Serial.print(“pulse duration:”);
// Serial.println(pulseDuration);
// Serial.print(“time for full rev. (microsec.):”);
// Serial.println(pulseDuration2);
// Serial.print(“freq. (Hz):”);
// Serial.println(frequency/2);
// Serial.print(“RPM:”);
// Serial.println(frequency/2
60);
// }

Thanks for your help in advance :grin:

Sorry I don't have all of Sunday to read that kilometre of code... (which incidentally ought to be in tags)

But look at map(). I don't know if the PWM to RPM is actually linear, which is what map() would do.

I vaguely recall seeing non-linear mapping functions in the Playground: go have a dig there.

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png or pdf?

Can you please post a copy of your sketch, using code tags? Please use code tags.. See section 7 http://forum.arduino.cc/index.php/topic,148850.0.html

If it is too big to post in code tags use the attachment facility to attach your sketch. (you will have to use REPLY rather than QUICK REPLY to use the attachment) Also what is the hardware, UNO,Mega???? the TFT ????? Fan(two,three or four wire?)

Tom..... :)