In dit project wordt de koelpaat temperatuur van een inverter gecontroleerd en via ventilatoren gekoeld om de temperatuur constant te houden.
In deze code is de berekening van een NTC weerstand gebruikt om de juiste temperatuur te bepalen en worden de ventilatoren geregeld via een PID controller op een PWM frequentie van 16KHz.
De NTC wordt gemeten dmv een analoge ingang op de arduino en met de gemiddelde waarde worden eventuele onregelmatigeheden weg gewerkt. De ventilatoren starten op een PWM van 50% en stoppen op 40%, met een start setpunt van 30°C. De output van de analoge waarde kan via de serieele monitor nagezien worden om eventuele P/I/D parrameters aan te passen op basis van de soorten ventilatoren en de snelheid waarop het systeem reageert.
Voor de tuning van de parrameters zie https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method
of de “trial and error” methode is ook een optie gezien dit geen kritische regeling is.
onderstaand de code voor het project.
/*
1 mf 52at sensor ntc 5v and serial resistor gnd
Beta=(t1*t2/t2-t1)*ln(r1/r2)
T=1/(1/T25+1/beta*ln(rt/r25)) in kelvin in arduino is ln=log
temp =(1/((1/t25)+(1/beta)*log(rtemp/rt25)))-273.15
v015-260223 new PID controller (tested)
final version
pid code
error = desired_value – actual_value
integral = integral_prior + error * iteration_time
derivative = (error – error_prior) / iteration_time
output = KP*error + KI*integral + KD*derivative + bias
error_prior = error
integral_prior = integral
sleep(iteration_time)
*/
//io setup
int sensor=A0;//analog input
int fanmotor=9;// motor pwm 16khz
int led=13;//control led
//var
float biasval=40,setpoint=35,kp=10,ki=4,kd=10,sampletime=1,stoptemp=30;// fixed values sampletime=1000ms= looptime
//float pwmrate=255;//comment on 16khz, uncomment = test 255 with unoardusim
float pwmrate=1000;//uncomment in use 16khz, comment =test 255 with unoardusim
float derivative=0,errorval=0,pidoutput=0;
float kpval=0,kival=0,kdval=0,pidval=0,olderror=0;
float sensval=0,integral=0;
int anval=0,fanmode=0,counttime=0;
void setup()
{
//pwm 16khz pin 9 and pin 10
pinMode(fanmotor,OUTPUT); //pwm controller to fan
pinMode(10,OUTPUT);
//unmark to set 16khz pwm
///*
TCCR1A = (1 << COM1A1) |(1 << COM1B1) | (1 << WGM11); // Enable Fast PWM on OC1A (Pin 9) and in OC1B (Pin 10)
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); // eneble Mode 14 Fast PWM/ (TOP = ICR1), pre-scale = 1
ICR1 = 1000; //Set the TOP value for 12-bit PWM 16MHz/16KHZ (deze waarde bepaald de pwm frequentie)
OCR1A = 0; //Set the PWM output to full off.
OCR1B= 0; //Set the PWM output to full off.
//*/
Serial.begin(9600);
pinMode(led, OUTPUT);
pinMode(sensor, INPUT);
digitalWrite(led,0);
meetsensor();
}
void loop()
{
meetsensor();
fanrun();
}
void meetsensor(){
digitalWrite(led,1);
sensval=adc();//500ms
digitalWrite(led,0);
delay(500);//total sampletime = 1000ms
}
float adc(){
//beta value B25/100 for ntc,serial resistor gnd
//rt25=res 25C and t25=273.15+25C kelvin =298.15
float temp=0,rawval=0,raw1=0,voltage=0,rsensor=0,current=0;
//ntc vars
float rt25=10,beta=3950,rserie=8.2,t25=298.15;
rawval=0;
raw1=0.0;
for (int i=0; i<20; i++){
rawval=analogRead(sensor);
delay(25);
raw1=raw1+rawval;
}
rawval=raw1/20;
voltage=(rawval/1023)*5;//calc voltage
current=voltage/rserie;//calc current
rsensor=(5-voltage)/current;//resistance ntc
temp=(1/((1/t25)+(1/beta)*log(rsensor/rt25)))-273.15;//temp in celcius
return temp;
}
float pidcalc(){
//pid calc 0-100%, sampletime= looptime= 5sec
errorval=sensval-setpoint;
kpval=kp*errorval;
derivative=(errorval-olderror)/sampletime;
kdval=kd*derivative;//delta temp in looptime
//integrate only when output < 100%
if (pidoutput<100 && pidoutput > biasval){
integral+=errorval*sampletime;
}
kival=ki*integral;
//integral value >=0
if (kival <0){
integral=0;
kival=0;
}
olderror=errorval;
pidval=kpval+kival+kdval;
if (pidval>100){
pidval= 100;
}
if(pidval<=biasval){
pidval=biasval;
}
return pidval;
}
void fanrun(){
pidoutput=pidcalc();
//stop conditions after 3min
if (pidoutput<=biasval && sensval<=stoptemp){
fanmode=0;
integral=0;
anval=0;
}
//start conditions
// start at kpval=0 Kival=biasval+10 kdval=0 output @ 50%
if (sensval > setpoint && fanmode == 0){
fanmode=1;
integral=(biasval+10)/ki;
pidoutput=pidcalc();
}
if(fanmode == 1){
anval=int(pwmrate-((pidoutput/100)*pwmrate));
//check max and min pwm rate
if(anval>pwmrate){
anval=pwmrate;
}
if(anval<0){
anval=0;
}
analogWrite(fanmotor,anval);
}
//stop fan output
if(fanmode==0){
anval=0;
pidoutput=0;
analogWrite(fanmotor,pwmrate-anval);//output = max (inverted)
}
datalog();
}
void datalog(){
Serial.print(sensval);
Serial.print(", ");
Serial.print(pidoutput);
Serial.print(", ");
Serial.print(fanmode);
Serial.print(", ");
Serial.print(kpval);
Serial.print(", ");
Serial.print(kival);
Serial.print(", ");
Serial.print(kdval);
Serial.print(", ");
Serial.println(counttime);
}
One thought on “16KHz PWM Fan controller Arduino”
Hello there, just became alert to your blog through Google, and found that it’s really informative.
I’m gonna watch out for brussels. I’ll appreciate if
you continue this in future. Numerous people will be benefited from your writing.
Cheers! Najlepsze escape roomy