This project is about driving 2x120mm brush less Fans using Arduino Nano, 12 bit PWM module PCA9685, LCD HD44780+I2C module, 2 Rotary Encoders, Temperature Sensor NTC MF 52-103 and optocouplers.
The Fans (Front and Rear Chassis) from Delta FFB1212EH (4000 RPM max)
It is 4 pin PWM controlled Fans.
- Pin1 - GND
- Pin2 - VCC (12V+)
- Pin3 - FG (RPM signal)
- Pin4 - PWM
To driving Fan I used 12 bit resolution PWM module PCA9685. Connected it over I2C port to Nano. To read the RPM of Fans I isolated the inputs with PC817 Optocouplers. The FG signal provides 2 pulses every 1 period.
Encoders using only manually increase and decrease the speeds of Fan (0-4000). The Encoders switch I used to select of increasing/decreasing amount of speed. It`s 1, 10 and 100. To save calculated Integer value from Encoders, I used 2 byte of EEPROM memory for each. In code you can find how to use it
Besides it I used SPDT switch to select Manual or Temperature controlling. Connected NTC MF 52-103 type temperature sensor to A0 of Nano using Voltage divider method. Connected 10k potentiometer to A1 and mapped it between 20 - 40 degrees Celsius. So calculating automatically and mapping selected Temperature Set value and Temperature Sensor to driving the Fans.
Used https://www.desmos.com/calculator to make a graphic function
LCD Display HD44780 displaying what`s going on
#include <Adafruit_PWMServoDriver.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
//#include "writeAnything.h"
/*
-VCC-5V
|
NTC - Vout
|
R(fixed)
|
GND
----Scaling Formula----
Reference Point ADC Reading
=========== ==========
x1(min) a1(min)
x2(max) a2(max)
X - x1 A - a1
--------- = -----------
x2 - x1 a2 - a1
==> X = (x2 - x1)*(A - a1)/(a2 - a1) + x1
temp = ((110 - 0)*(average_sensor - 498))/191;
*/
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define ledPin 13
LiquidCrystal_I2C lcd(0x3C,16,2); //sometimes the adress is not 0x3f. Change to 0x27 if it dosn't work.//0x3C is that A0 and A1 are shorted
short ThermistorPin = 0;// Analog input pin for thermistor voltage
short Temp_Pot = 1; //Temperature Potentiometer PIN
boolean f_encoder_a;
boolean f_encoder_b;
boolean r_encoder_a;
boolean r_encoder_b;
boolean f_encoder_sw;
boolean r_encoder_sw;
uint8_t f_pwmnum= 0;
uint8_t r_pwmnum= 1;
boolean switch_temp;
int Vo;// Integer value of voltage reading
float R = 9870.0;// Fixed resistance in the voltage divider
float logRt,Rt,T;
float c1 = 2.108508173e-03, c2 = 0.7979204727e-04, c3 = 6.535076315e-07;//Water Sersor R=10kOhm-25 degree Celcius. B=3435
int pot_raw;
float pot_map;
boolean f_encoder_a_prev;
boolean r_encoder_a_prev;
boolean f_encoder_sw_prev;
boolean r_encoder_sw_prev;
boolean f_fan_raw;
boolean r_fan_raw;
boolean trig_a;
boolean trig_b;
unsigned int f_counter;
unsigned int r_counter;
unsigned int f_counter_temp;
unsigned int r_counter_temp;
unsigned int amount[3];
unsigned short f_rpm_amount;
unsigned short r_rpm_amount;
unsigned short f_encoder_sw_counter;
unsigned short r_encoder_sw_counter;
unsigned short f_counter_th;
unsigned short f_counter_hu;
unsigned short f_counter_te;
unsigned short f_counter_de;
unsigned short f_counter_12;
unsigned short f_counter_34;
int f_c;
int r_c;
//RPMreading//
int f_frequency;
int r_frequency;
int f_freq_counter;
int r_freq_counter;
unsigned long currentMicros;
unsigned long previousMicros = 0;
const long interval = 1000000;
void setup() {
pwm.begin();
pwm.setPWMFreq(1600); // This is the maximum PWM frequency
Wire.setClock(300000); //I2C clock frequency 300kHz
Serial.begin(9600);
f_counter = EEPROM_int_read(0);
r_counter = EEPROM_int_read2(10);
lcd.init(); // Initializing LCD
lcd.begin(16, 2);
lcd.backlight(); //lcd backlight o
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(4, INPUT);
pinMode(5, INPUT);
pinMode(6, INPUT);
pinMode(7, INPUT); //Front Fan RPM input
pinMode(8, INPUT); //Rear Fan RPM input
pinMode(11, INPUT); //Front Encoder Switch
pinMode(12, INPUT); //Rear Encoder Switch
amount[0] = 1;
amount[1] = 10;
amount[2] = 100;
}
void loop() {
temp_reading();
rpm_reading();
switch_temp = digitalRead(2);
f_encoder_a = digitalRead(3);
f_encoder_b = digitalRead(4);
r_encoder_a = digitalRead(5);
r_encoder_b = digitalRead(6);
f_encoder_sw = digitalRead(11);
r_encoder_sw = digitalRead(12);
encoder_switch();
encoder_reading();
pwm_out();
/*
Serial.print(f_counter);
Serial.print(" ");
Serial.print(f_frequency_out);
Serial.println();
*/
}
void temp_reading()
{
Vo = analogRead(ThermistorPin);
Rt = R*( (1023.0 / (float)Vo) - 1.0 );
logRt = log(Rt);
T = ( 1.0 / (c1 + c2*logRt + c3*logRt*logRt*logRt ) ) - 273.15;
pot_raw = analogRead(Temp_Pot);
pot_map = ((40.0 - 20.0)*(float(pot_raw) - 0.0))/(1023.0 - 0.0)+20.0;
if(f_counter_temp<4096)
{
f_counter_temp = sqrt((T-pot_map))*550+500;
r_counter_temp = sqrt((T-pot_map))*550+250;//Rear RPM less than Front
}
} //end temp_reading
/***************************************************************************************/
void rpm_reading()
{
//FRONT FAN RPM//
f_fan_raw = digitalRead(7);
if(f_fan_raw==false&&trig_a==false)
{
f_freq_counter++;
trig_a = true;
}
if(f_fan_raw==true&&trig_a==true)
{
trig_a = false;
}
//REAR FAN RPM//
r_fan_raw = digitalRead(8);
if(r_fan_raw==false&&trig_b==false)
{
r_freq_counter++;
trig_b = true;
}
if(r_fan_raw==true&&trig_b==true)
{
trig_b = false;
}
currentMicros = micros();
if(currentMicros<previousMicros){previousMicros = currentMicros;}
if(currentMicros-previousMicros>=interval)
{
f_frequency = f_freq_counter * 60;
f_frequency=f_frequency/2;
r_frequency = r_freq_counter * 60;
r_frequency=r_frequency/2;
Serial.print(f_counter);
Serial.print(" ");
Serial.print(f_frequency);
Serial.println();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(f_counter);
lcd.setCursor(0, 1);
lcd.print(f_frequency);
lcd.setCursor(5, 0);
lcd.print(r_counter);
lcd.setCursor(5, 1);
lcd.print(r_frequency);
lcd.setCursor(10, 0);
lcd.print(T);
lcd.setCursor(15, 0);
lcd.print("C");
lcd.setCursor(10, 1);
lcd.print("S:");
lcd.setCursor(12, 1);
lcd.print(pot_map);
f_freq_counter = 0;
r_freq_counter = 0;
previousMicros = currentMicros;
}
}//end rpm_reading
void encoder_switch()
{
//FRONT//
if(f_encoder_sw==false){f_encoder_sw_prev = f_encoder_sw;}
if(f_encoder_sw==true&&f_encoder_sw_prev==false)
{
f_encoder_sw_counter++;
if(f_encoder_sw_counter>2){f_encoder_sw_counter = 0;}
f_encoder_sw_prev = f_encoder_sw;
}
switch (f_encoder_sw_counter)
{
case 0:
f_rpm_amount = amount[0];
break;
case 1:
f_rpm_amount = amount[1];
break;
case 2:
f_rpm_amount = amount[2];
break;
}
//REAR//
if(r_encoder_sw==false){r_encoder_sw_prev = r_encoder_sw;}
if(r_encoder_sw==true&&r_encoder_sw_prev==false)
{
r_encoder_sw_counter++;
if(r_encoder_sw_counter>2){r_encoder_sw_counter = 0;}
r_encoder_sw_prev = r_encoder_sw;
}
switch (r_encoder_sw_counter)
{
case 0:
r_rpm_amount = amount[0];
break;
case 1:
r_rpm_amount = amount[1];
break;
case 2:
r_rpm_amount = amount[2];
break;
}
}//end encoder_switch
/***************************************************************************/
// reading FRONT Fan conrolling value to EEPROM using 2bytes
int EEPROM_int_read(int addr) {
byte raw[2];
for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i);
int &f_c = (int&)raw;
return f_c;
}
// writing FRONT Fan conrolling value to EEPROM using 2bytes
void EEPROM_int_write(int addr, int f_c) {
if (EEPROM_int_read(addr)!= f_c){//если сохраняемое отличается
byte raw[2];
(int&)raw = f_c;
for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]);
}
}
// reading REAR Fan conrolling value to EEPROM using 2bytes
int EEPROM_int_read2(int addr) {
byte raw[2];
for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i);
int &num = (int&)raw;
return num;
}
// writing REAR Fan conrolling value to EEPROM using 2bytes
void EEPROM_int_write2(int addr, int num) {
if (EEPROM_int_read2(addr)!= num){//если сохраняемое отличается
byte raw[2];
(int&)raw = num;
for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]);
}
}
void encoder_reading()
{
//FRONT//
if(f_encoder_a != f_encoder_a_prev) //Increasing
{
if(f_encoder_b != f_encoder_a)
{
if(f_encoder_a_prev==true)
{
if((f_counter+f_rpm_amount)<4096)
{
f_counter = f_counter + f_rpm_amount;
EEPROM_int_write(0, f_counter);
}
}
f_encoder_a_prev = f_encoder_a;
}
else //Decreasing
{
if(f_encoder_a_prev==true)
{
if(f_counter>200)
{
f_counter = f_counter - f_rpm_amount;
EEPROM_int_write(0, f_counter);
}
}
f_encoder_a_prev = f_encoder_a;
}
}
//REAR//
if(r_encoder_a != r_encoder_a_prev) //Increasing
{
if(r_encoder_b != r_encoder_a)
{
if(r_encoder_a_prev==true)
{
if((r_counter+r_rpm_amount)<4096)
{
r_counter = r_counter + r_rpm_amount;
EEPROM_int_write2(10, r_counter);
}
}
r_encoder_a_prev = r_encoder_a;
}
else //Decreasing
{
if(r_encoder_a_prev==true)
{
if(r_counter>200)
{
r_counter = r_counter - r_rpm_amount;
EEPROM_int_write2(10, r_counter);
}
}
r_encoder_a_prev = r_encoder_a;
}
}
}//end encoder_reading
void pwm_out()
{
if(switch_temp==true)
{
pwm.setPWM(f_pwmnum, 0, f_counter % 4096 );
pwm.setPWM(r_pwmnum, 0, r_counter % 4096 );
}else
{
pwm.setPWM(f_pwmnum, 0, f_counter_temp % 4096 );
pwm.setPWM(r_pwmnum, 0, r_counter_temp % 4096 );
}
}
Comments