mariuste / Fan_Temp_Control

Temperature Controlled 4-Pin Fan /w Arduino Nano
45 stars 4 forks source link

Possibility to integrate another Temperature Sensor to PWM control a different fan #2

Closed rohanpp02 closed 1 year ago

rohanpp02 commented 1 year ago

I know this is not an issue but I wanted to ask this question to the creator. I wish to add another temperature sensor which will PWM control another fan.

Would it be possible to possible to accomplish this task on a single Nano?

mariuste commented 1 year ago

Hi there,

yes this is definitively possible - at least 5 fans and a lot more than 5 temperature sensors should be possible with not too much effort (I have used more than 10 in the past). With some clever coding a even more fans than just 5 should be possible (soft PWM).

The temperature sensors can be operated in parallel via 1-Wire. Here is an example for addressing multiple sensors over the same pin: https://lastminuteengineers.com/multiple-ds18b20-arduino-tutorial/

The fans need one timer and additionally one PWM output counter each (e.g. OC1A and OC1B for Timer1). I currently use Timer1 to generate the 25kHz base-PWM signal and the counter OCR1B value to control pin D10. By adjusting the value OC1A and OC1B the PWM output of pins D9 and D10 can be controlled (OCR1A is therefore still available).

You can try to adjust the code accordingly - I will gladly try to help when you encounter some errors.

I will be out of town for a few days; next weekend I should have time to answer your questions when you have any and maybe help with the code.

rohanpp02 commented 1 year ago

Thanks for your support. Really appreciate it! Let me try to finish the program by next week and I will get in touch with you for any queries or errors.

Just a small question - my application would involve 4 fans in total - 1 bank of 2 fans PWM controlled by the first temperature sensor and another bank of the remaining 2 fans controlled by the second temperature sensor.

Is it ok to PWM control 2 fans from a single output pin of the Nano? I plan to connect them together with the Noctua Y splitter.

mariuste commented 1 year ago

Just a small question - my application would involve 4 fans in total - 1 bank of 2 fans PWM controlled by the first temperature sensor and another bank of the remaining 2 fans controlled by the second temperature sensor. Is it ok to PWM control 2 fans from a single output pin of the Nano? I plan to connect them together with the Noctua Y splitter.

Yes, you can use a y-splitter and use the same PWM control signal for two fans

rohanpp02 commented 1 year ago

Thanks @mariuste for all your help. I managed to do it. Would not have been possible without you!

Leaving the code below for anyone else who might be interested!

``

`// Fan_Temp_Control.ino ############################################## / This code was written to control the temperature inside a server cabinet by measuring the temperature with a DS18b20 Temperature probe and outputting a PWM signal with the Arduino Nano to control a 4-Pin fan. Unlike the cheap control boards from Amazon or Ebay this code switches the fan off when the temperature is low enough. /

/*

The following constants should be changed according to the use case:

constant (default value) - description

tempLow (35) - Below this temperature (minus half hysteresis) the fan shuts off. It shuts on again at this temperature plus half hysteresis

tempHigh (50) - At and above this temperature the fan is at maximum speed

hyteresis (5) - Hysteresis to prevent frequent on/off switching at the threshold

minDuty (10) - Minimum fan speed to prevent stalling maxDuty (100) - Maximum fan speed to limit noise

*/

include

include

// Digital pin of temperature sensor

define ONE_WIRE_BUS 12

// Setup a oneWire instance OneWire oneWire(ONE_WIRE_BUS);

// Setup temperature sensor library DallasTemperature sensors(&oneWire);

// PWM output pin const byte OC1B_PIN = 10; const byte OC1A_PIN = 9;

// Digital pin for controlliing optional high side switch // const byte HS_SWITCH = 9;

// how frequently the main loop runs const int tempSetInterval = 5000;

// temperatur settings const float tempLow = 35; const float tempHigh = 55; const float hyteresis = 5; const int minDuty = 10; const int maxDuty = 100;

// state on/off of Fan 1 bool fanState1 = HIGH; // state on/off of Fan 2 bool fanState2 = HIGH;

// current duty cycle of Fan 1 byte duty1 = 100; // current duty cycle of Fan 2 byte duty2 = 100;

// new duty cycle of Fan 1 byte newDuty1 = 100; // new duty cycle of Fan 2 byte newDuty2 = 100;

//tempertature 1 (1m) sensor address uint8_t sensor1[8] = { 0x28, 0x50, 0x3A, 0x81, 0xE3, 0xC8, 0x3C, 0xA3 }; //tempertature 2 (3m) sensor address uint8_t sensor2[8] = { 0x28, 0x66, 0xD5, 0x76, 0xE0, 0x01, 0x3C, 0x5C };

void setup() { //enable output for Timer 1 pinMode(OC1B_PIN, OUTPUT); pinMode(OC1A_PIN, OUTPUT);
setupTimer1();

// configure High-Side Switch //pinMode(HS_SWITCH, OUTPUT); //digitalWrite(HS_SWITCH, HIGH); // default: Fan on

// start serial port Serial.begin(9600);

// Start up the temperature library sensors.begin(); sensors.requestTemperatures();

// welcome message Serial.println("## Start of Program ##"); Serial.println();

Serial.println("# Connections #");

Serial.println(" Temperature Sensor (VCC, Data, GND)"); Serial.print(" Arduino: 3V3, D"); Serial.print(ONE_WIRE_BUS); Serial.println(" , GND"); Serial.println(" *additionally 4k7 pullup between VCC and Data"); Serial.println();

Serial.println(" 4-Pin Fan (GND, VCC, Sense, Control)"); Serial.print(" Arduino: GND, 12V, n/C , D"); Serial.println(OC1B_PIN); Serial.println();

Serial.println(" 4-Pin Fan (GND, VCC, Sense, Control)"); Serial.print(" Arduino: GND, 12V, n/C , D"); Serial.println(OC1A_PIN); Serial.println();

// Serial.println(" Optional High-Side Switch"); // Serial.print(" Arduino: D"); // Serial.println(HS_SWITCH); // Serial.println();

Serial.println("# Settings #"); Serial.println(" Below this temperature (minus half hysteresis) the fan"); Serial.println(" shuts off. It enables again at this temperature plus half hysteresis:"); Serial.print(" tempLow: "); Serial.print(tempLow); Serial.println("°C");

Serial.println(" At and above this temperature the fan is at maximum speed: "); Serial.print(" tempHigh: "); Serial.print(tempHigh); Serial.println("°C"); Serial.println();

Serial.println(" Between these two temperatures the fan is regulated from"); Serial.println(" the minimum fan speed to maximum fan speed"); Serial.println();

Serial.println(" Hysteresis to prevent frequent on/off switching at the threshold"); Serial.print(" hyteresis: "); Serial.print(hyteresis); Serial.println("°C"); Serial.println();

Serial.println(" Minimum fan speed to prevent stalling"); Serial.print(" minDuty: "); Serial.print(minDuty); Serial.println(" %"); Serial.println();

Serial.println(" Maximum fan speed to limit noise"); Serial.print(" maxDuty: "); Serial.print(maxDuty); Serial.println(" %"); Serial.println();

Serial.println(" The fan speed is adjusted at the following interval:"); Serial.print(" tempSetInterval: "); Serial.print(tempSetInterval); Serial.println(" ms");

Serial.println(); delay(100); Serial.println(); delay(100); Serial.println(); delay(100); Serial.println(); delay(100); Serial.println(); delay(100); Serial.println(); delay(100); Serial.println(); delay(100);

Serial.println("# Main Loop"); Serial.println("(sr.no, temperature, state, Duty Cycle, Fan On/Off)"); Serial.println(); }

// main loop ############################################## void loop() { // measure temperature, calculate Duty cycle, set PWM tempToPwmDuty(); // wait for a bit delay(tempSetInterval); }

// setting PWM ############################################ void setPwmDuty() { if (duty1 == 0) { fanState1 = LOW; // Disable high side switch //digitalWrite(HS_SWITCH, LOW); } else if (duty1 > 0) { fanState1 = HIGH; // Enable high side switch //digitalWrite(HS_SWITCH, HIGH); } if (duty2 == 0) { fanState2 = LOW; // Disable high side switch //digitalWrite(HS_SWITCH, LOW); } else if (duty2 > 0) { fanState2 = HIGH; // Enable high side switch //digitalWrite(HS_SWITCH, HIGH); } setFan(duty1, duty2); }

// calculate new PWM ###################################### void tempToPwmDuty() {

sensors.requestTemperatures();

float temp1 = sensors.getTempC(sensor1); float temp2 = sensors.getTempC(sensor2);

Serial.print("#1, "); Serial.print(temp1); Serial.print("°C, ");

if (temp1 < tempLow) { // distinguish two cases to consider hyteresis if (fanState1 == HIGH) { if (temp1 < tempLow - (hyteresis / 2)) { // fan is on, temp below threshold minus hysteresis -> switch off Serial.print("a, "); newDuty1 = 0; } else { // fan is on, temp not below threshold minus hysteresis -> keep minimum speed Serial.print("b, "); newDuty1 = minDuty; } } else if (fanState1 == LOW) { // fan is off, temp below threshold -> keep off Serial.print("c, "); newDuty1 = 0; }

} else if (temp1 < tempHigh) { // distinguish two cases to consider hyteresis if (fanState1 == HIGH) { // fan is on, temp above threshold > control fan speed Serial.print("d, "); newDuty1 = map(temp1, tempLow, tempHigh, minDuty, maxDuty); } else if (fanState1 == LOW) { if (temp1 > tempLow + (hyteresis / 2)) { // fan is off, temp above threshold plus hysteresis -> switch on Serial.print("e, "); newDuty1 = minDuty; } else { // fan is on, temp not above threshold plus hysteresis -> keep off Serial.print("f, "); newDuty1 = 0; } } } else if (temp1 >= tempHigh) { // fan is on, temp above maximum temperature -> maximum speed Serial.print("g, "); newDuty1 = maxDuty; } else { // any other temperature -> maximum speed (this case should never occur) Serial.print("h, "); newDuty1 = maxDuty; }

//set new duty duty1 = newDuty1;

Serial.print(duty1); Serial.print("%, ");

if (fanState1 == 0) { Serial.println("OFF"); } else { Serial.println("ON"); }

Serial.print("#2, "); Serial.print(temp2); Serial.print("°C, ");

if (temp2 < tempLow) { // distinguish two cases to consider hyteresis if (fanState2 == HIGH) { if (temp2 < tempLow - (hyteresis / 2)) { // fan is on, temp below threshold minus hysteresis -> switch off Serial.print("a, "); newDuty2 = 0; } else { // fan is on, temp not below threshold minus hysteresis -> keep minimum speed Serial.print("b, "); newDuty2 = minDuty; } } else if (fanState2 == LOW) { // fan is off, temp below threshold -> keep off Serial.print("c, "); newDuty2 = 0; }

} else if (temp2 < tempHigh) { // distinguish two cases to consider hyteresis if (fanState2 == HIGH) { // fan is on, temp above threshold > control fan speed Serial.print("d, "); newDuty2 = map(temp2, tempLow, tempHigh, minDuty, maxDuty); } else if (fanState2 == LOW) { if (temp2 > tempLow + (hyteresis / 2)) { // fan is off, temp above threshold plus hysteresis -> switch on Serial.print("e, "); newDuty2 = minDuty; } else { // fan is on, temp not above threshold plus hysteresis -> keep off Serial.print("f, "); newDuty2 = 0; } } } else if (temp2 >= tempHigh) { // fan is on, temp above maximum temperature -> maximum speed Serial.print("g, "); newDuty2 = maxDuty; } else { // any other temperature -> maximum speed (this case should never occur) Serial.print("h, "); newDuty2 = maxDuty; }

//set new duty duty2 = newDuty2;

Serial.print(duty2); Serial.print("%, ");

if (fanState2 == 0) { Serial.println("OFF"); } else { Serial.println("ON"); }

setPwmDuty(); }

// Setup Timer control void setupTimer1() { //Set PWM frequency to about 25khz on pins 9,10 (timer 1 mode 10, no prescale, count to 320) TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); TCCR1B = (1 << CS10) | (1 << WGM13); ICR1 = 320; OCR1A = 0; OCR1B = 0; } //equivalent of analogWrite on pin 10 void setFan(int fan1, int fan2) { float f1 = fan1; float f2 = fan2; f1 = f1 / 100; f1 = f1 < 0 ? 0 : f1 > 1 ? 1: f1; f2 = f2 / 100; f2 = f2 < 0 ? 0 : f2 > 1 ? 1: f2; OCR1B = (uint16_t)(320 f1); OCR1A = (uint16_t)(320 f2);
}`

``