Temperature Based Fan PWM Control

I want to PWM control 2 set of fans based on the temperatures of 2 different temperature DS18B20 sensors. Is this possible on a single Arduino Nano controller?
I have the code for PWM control one set of fans using a single DS18B20 temperature sensor.
I dont know how to interface the second temperature sensor to control the second set of fans.

The program I found on this GitHub repo:

// 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 <OneWire.h>
#include <DallasTemperature.h>

// Digital pin of temperature sensor
#define ONE_WIRE_BUS 2

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

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

// PWM output pin
const byte OC1B_PIN = 10;

// 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 = 50;
const float hyteresis = 5;
const int minDuty = 10;
const int maxDuty = 100;

// state on/off of Fan
bool fanState = HIGH;

// current duty cycle
byte duty = 100;

// new duty cycle
byte newDuty = 100;




void setup() {
	//enable output for Timer 1
	pinMode(OC1B_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(" 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("(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 (duty == 0) {
		fanState = LOW;
		// Disable high side switch
		digitalWrite(HS_SWITCH, LOW);
	} else if (duty > 0) {
		fanState = HIGH;
		// Enable high side switch
		digitalWrite(HS_SWITCH, HIGH);
	}

	setFan(duty);

}


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

	sensors.requestTemperatures();

	float temp = sensors.getTempCByIndex(0);

	Serial.print(temp);
	Serial.print("°C, ");

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

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

 	//set new duty
 	duty = newDuty;

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

 	if (fanState==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 fan){
	float f = fan;
	f = f / 100;
    f=f<0?0:f>1?1:f;
    OCR1B = (uint16_t)(320*f);
}

Can someone suggest a way for me to implement my use case by modifying the above code?

Yes

Please show a schematic of how you interfaced the first set

1 Like

Hello rohanpp02

Design and code a sketch for two physically separated OneWire sensors simply.

Have a nice day and enjoy coding in C++.

1 Like

Just duplicate the sections I circled in greem.
Connect the new temp sensor to D3 and the new fan pwm to D9

So when you say new temp sensor to D3 I would code the following in addition to the above script:


// Digital pin of temperature sensor
//sensor 1 at D2
#define ONE_WIRE_BUS1 2
//sensor 2 at D3
#define ONE_WIRE_BUS2 3

// Setup a oneWire instance
//instance for sensor 1
OneWire oneWire1(ONE_WIRE_BUS1);  
//instance for sensor 2
OneWire oneWire2(ONE_WIRE_BUS2);  

// Setup temperature sensor library
//for sensor 1
DallasTemperature sensors(&oneWire1);
//for sensor 2
DallasTemperature sensors(&oneWire2);

Am I understanding this correctly?

I'm sorry, (a typo) there is only ONE oneWire bus, so the new DS18B20 also connects to pin D2.
So that part of the code remains unchanged.
This is a good tutorial on how to use two DS18B20s

Thanks everyone for your help. I managed to accomplish WM control 2 set of fans based on the temperatures of 2 different temperature DS18B20 sensors.
Leaving the code below for anyone who might need it in the future! Cheers!

// 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 <OneWire.h>
#include <DallasTemperature.h>

// 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);  
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.