Controll 1 PWM fan with several DS18B20

Found this code on website but for two PWM fans to be controlled by two DS18B20 and can't change it to work with only one fan so I can control 1 PWM fan with several DS18B20.

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

Welcome to the forum

What should happen when the sensors return different values ?

Fan speed must be set based on the highest temp that one of the DS18B20 will detect

So where are you stuck with implementing it ?

Can you read 1 sensor ?
Can you read multiple sensors ?
Can you control the speed of the fan ?

Stuck at converting the code to my needs
I can read all the connected DS18B20 and control the fan based on only one Ds18B20

I am sure that solution is simple but for some reason I can't get it to work although I am few days in to Arduino

So you have multiple readings. The first thing to do is to discover which reading is the highest

One way to do this would be to sort the values into numerical order.

Another would be to set a variable to a value lower than the minimum possible reading, then compare each reading with that value. If the value is greater than that of the variable then save the value to the variable. Continue until you have tested all values and the highest is now in the variable

I will do more tests and see what works.
thanks

why isn't the code simply

    if (Thresh < sensor1 || Thesh < sensor1)
        turn fan on
    else if (Thresh > sensor1 && Thesh > sensor1)
        turn fan off

how is fan speed related to temperature?

It is not clear how many sensors there are

So I am trying to make cooling solution for 3 QC and 3 PD charging modules
And code needs to be done in the way so if any module is getting used it will get hot and will trigger the fan to spin

6 sensors is planned to be used but for now just playing with the code so only two sensors

Ok. So I think I found partial solution for now and just calculated the average

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

  sensors.requestTemperatures();
  float temp1 = sensors.getTempC(sensor1);
  float temp2 = sensors.getTempC(sensor2);
  int tempC = (int)(temp1 + temp2) / 2;

seems llike a logic, not a math problem

why isn't this what you need?

I will try use it later
But main point is for the fan spin up gradually as temp rises.

Also I am very new to arduino so I need to get in to depth and try to use ur code

Thanks for idea

mode important than getting code correct, is a complete and correct undestanding of what it needs to do

does this mean gradually increase speed

or does it mean fan speed depends on how quickly it reduces temperature? does it mean adjust speed to maintain some temperature?

Found solution

#include <DallasTemperature.h>
#include <OneWire.h>
#include <U8g2lib.h>

// Digital pin of temperature sensor
#define ONE_WIRE_BUS 2

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

// Setup u8g2 library
DallasTemperature sensors(&oneWire);

// Setup temperature sensor library
U8G2_SSD1309_128X64_NONAME2_F_SW_I2C u8g2(U8G2_R0, SCL, SDA, U8X8_PIN_NONE);

// PWM output pin
const byte OC1A_PIN = 9;  // PWM Fan 1

// Timer control
const int tempSetInterval = 5000;

// Temperature settings
const float tempLow = 30;
const float tempHigh = 45;
const float hyteresis = 1;
const int minDuty = 10;
const int maxDuty = 100;

// State on/off of Fan 1
bool fanState1 = HIGH;

// Current duty cycle of Fan 1
byte duty1 = 100;

// New duty cycle of Fan 1
byte newDuty1 = 100;

// Temperature sensors' unique addresses
uint8_t sensor1[8] = { 0x28, 0x7C, 0x1E, 0x43, 0x00, 0x00, 0x00, 0x4D }; // BMS MOS

uint8_t sensor2[8] = { 0x28, 0x32, 0x68, 0x41, 0x00, 0x00, 0x00, 0xDD }; // UPS Board Charge MOS
uint8_t sensor3[8] = { 0x28, 0x41, 0x01, 0x44, 0x00, 0x00, 0x00, 0x7F }; // UPS Board Discharge MOS

uint8_t sensor4[8] = { 0x28, 0x34, 0x31, 0x80, 0xE3, 0xE1, 0x3C, 0x30 }; // 6S UPS LiFePo4 Cell 1 Pad 1 botom 1S Main
uint8_t sensor5[8] = { 0x28, 0xF8, 0x63, 0x80, 0xE3, 0xE1, 0x3C, 0xC4 }; // 6S UPS LiFePo4 Cell 2 Pad 1 botom 2S Main
uint8_t sensor6[8] = { 0x28, 0x98, 0x1D, 0x80, 0xE3, 0xE1, 0x3C, 0xC8 }; // 6S UPS LiFePo4 Cell 3 Pad 1 botom 3S Main

uint8_t sensor7[8] = { 0x28, 0xF6, 0x09, 0x80, 0xE3, 0xE1, 0x3C, 0x7B }; // 6S UPS LiFePo4 Cell 1 Pad 2 botom 4s Main
uint8_t sensor8[8] = { 0x28, 0xBB, 0x71, 0x80, 0xE3, 0xE1, 0x3C, 0x17 }; // 6S UPS LiFePo4 Cell 2 Pad 2 botom 5s Main
uint8_t sensor9[8] = { 0x28, 0x7F, 0x1C, 0x80, 0xE3, 0xE1, 0x3C, 0xA9 }; // 6S UPS LiFePo4 Cell 3 Pad 2 botom 6s Main

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

  u8g2.begin();
  u8g2.setContrast(10);  // Adjust brightness (0 - 255)


  //u8g2.clearBuffer();
  //u8g2.setFont(u8g2_font_fub14_tf);
  //u8g2.drawStr(10, 30, "PC 6S UPS");
  //u8g2.drawStr(5, 50, "USB Cooling");
  //u8g2.sendBuffer();

  // Start serial port
  Serial.begin(9600);
  
  // Start up the temperature library
  sensors.begin();
  sensors.requestTemperatures();

  //delay(5000);

}

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;
  } else if (duty1 > 0) {
    fanState1 = HIGH;
  }
  setFan(duty1);
}

// Calculate new PWM based on highest temperature
void tempToPwmDuty() {
  sensors.requestTemperatures();

  // Read temperatures from sensors
  float temp1 = sensors.getTempC(sensor1); // BMS MOS
  float temp2 = sensors.getTempC(sensor2); // UPS Board Charge MOS
  float temp3 = sensors.getTempC(sensor3); // UPS Board Discharge MOS
  float temp4 = sensors.getTempC(sensor4); // 6S UPS LiFePo4 Cell 1 Pad 1 botom 1S Main
  float temp5 = sensors.getTempC(sensor5); // 6S UPS LiFePo4 Cell 2 Pad 1 botom 2S Main
  float temp6 = sensors.getTempC(sensor6); // 6S UPS LiFePo4 Cell 3 Pad 1 botom 3S Main
  float temp7 = sensors.getTempC(sensor7); // 6S UPS LiFePo4 Cell 1 Pad 2 botom 4S Main
  float temp8 = sensors.getTempC(sensor8); // 6S UPS LiFePo4 Cell 3 Pad 2 botom 5S Main
  float temp9 = sensors.getTempC(sensor9); // 6S UPS LiFePo4 Cell 3 Pad 2 botom 6S Main

  // Find the highest temperature
  float highestTemp = max(max(max(max(max(max(max(max(temp1, temp2), temp3), temp4), temp5), temp6), temp7), temp8), temp9);


  // Display highest temperature and fan speed on OLED
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_luRS08_tf);
  

  // USB type column USB A Top to Botom 1,2,3
  //u8g2.setFont(u8g2_font_6x13_tf);  // Font 9 Pixel Height X11
  //u8g2.drawStr(5, 9, "A  USB  C");


  // BMS MOS
  u8g2.drawStr(0, 8, "BMS");
  u8g2.setCursor(0,20);
  u8g2.print(temp1, 1);

  // UPS Board Charge MOS
  u8g2.drawStr(0, 31, "MOSC");
  u8g2.setCursor(0,41);
  u8g2.print(temp2, 1);

  // UPS Board Discharge MOS
  u8g2.drawStr(0, 52, "MOSD");
  u8g2.setCursor(0,62);
  u8g2.print(temp3, 1);

  // 6S UPS LiFePo4 Cell 1 Pad 1 botom 1S Main
  u8g2.setCursor(35,8);
  u8g2.print(temp4, 1);

  // 6S UPS LiFePo4 Cell 2 Pad 1 botom 2S Main
  u8g2.setCursor(70,8);
  u8g2.print(temp5, 1);

  // 6S UPS LiFePo4 Cell 3 Pad 1 botom 3S Main
  u8g2.setCursor(105,8);
  u8g2.print(temp6, 1);

  // 6S UPS LiFePo4 Cell 1 Pad 2 botom 4S Main
  u8g2.setCursor(35,20);
  u8g2.print(temp7, 1);

  // 6S UPS LiFePo4 Cell 3 Pad 2 botom 5S Main
  u8g2.setCursor(70,20);
  u8g2.print(temp8, 1);

  // 6S UPS LiFePo4 Cell 3 Pad 2 botom 6S Main
  u8g2.setCursor(105,20);
  u8g2.print(temp9, 1);

  
  // Dsiplay Fan PWM Speed in %
  //u8g2.setFont(u8g2_font_fub14_tf);
  //u8g2.drawStr(80, 40, "Fan");
    // Dsiplay highest temp
  //u8g2.setFont(u8g2_font_gb24st_t_2);  // Font 22 Pixel Height Fontstruct
  u8g2.drawStr(40, 35, "Highest T");
  u8g2.setCursor(95,35);
  u8g2.print(highestTemp, 1);

  u8g2.drawStr(50, 55, "FAN");


  u8g2.setFont(u8g2_font_spleen16x32_mf);  // Font 22 Pixel Height Fontstruct
  u8g2.setCursor(75,63);
  u8g2.print(duty1, 1);
  u8g2.sendBuffer();

  // Adjust PWM based on the highest temperature
  if (highestTemp < tempLow) {
    newDuty1 = 0;
  } else if (highestTemp < tempHigh) {
    newDuty1 = map(highestTemp, tempLow, tempHigh, minDuty, maxDuty);
  } else {
    newDuty1 = maxDuty;
  }

  duty1 = newDuty1;
  setPwmDuty();

  // Debug output
  Serial.print("Highest Temp: ");
  Serial.print(highestTemp);
  Serial.print("°C, Fan Speed: ");
  Serial.print(duty1);
  Serial.println("%");
}

// Setup Timer control
void setupTimer1() {
  // Set PWM frequency to about 25kHz on pin 9 (Timer 1 mode 10, no prescale, count to 320)
  TCCR1A = (1 << COM1A1) | (1 << WGM11);
  TCCR1B = (1 << CS10) | (1 << WGM13);
  ICR1 = 320;
  OCR1A = 0;
}

// Equivalent of analogWrite on pin 9 (PWM pin)
void setFan(int fan1) {
  float f1 = fan1;
  f1 = f1 / 100;
  f1 = f1 < 0 ? 0 : f1 > 1 ? 1 : f1;
  OCR1A = (uint16_t)(320 * f1);
}

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