Полупассивное охлаждение компьютерного БП

в 16:35, , рубрики: arduino, diy или сделай сам, diy-проекты, PWM, Блок питания, тихий компьютер

Привет! Это устройство применимо не только в компьютерном БП, но мы будем про компьютерный, как насущный :)

Полупассивное охлаждение компьютерного БП - 1

Техпроцесс производства процессоров неуклонно уменьшается, вместе с ним уменьшается и энергопотребление. Процессоры последних поколений содержат в себе пригодную для повседневных задач графическую видео систему. Если вы не сильно требовательны к производительности в видео играх то за относительно скромный бюджет можно задуматься о тихом компьютере который будет издавать звуки только под большой нагрузкой, что случается не часто.

Далее идёт моё видение конфигурации компа для полупассивного охлаждения.

Средний CPU в пике своей загрузки выделяет 65 Вт тепла, охладить его можно заводским кулером с большей (нежели штатный) мощностью 120-150 Вт выставив настройки в BIOS чтобы он начинал крутиться только при загрузке 30-40% CPU либо температурой выше 40°С.

Ещё один источник шума это HDD, но тут всё просто, я заменил его на SSD.

Остался вентилятор блока питания который крутится постоянно. Можно купить полностью пассивный либо полу пассивный изначально, но тут цена вопроса: (от $150) возможно, есть смысл направить эти средства на бОльшую производительность?

Обычный, 500 Вт блок питания ($50) имеет огромный запас по мощности в моём случае, поэтому я решил отключить вентилятор полностью. Но при длительной работе под большой нагрузкой радиаторы внутри стали разогреваться свыше 60°С, так что решено было вернуть вентилятор но сделать его обороты контролируемыми.

Полупассивное охлаждение компьютерного БП - 2

За основу был взят Arduino nano на базе ATMEGA168PA, из разных кусков чужих проектов составлен свой.

Полупассивное охлаждение компьютерного БП - 3

Поскольку ресурсы контроллера позволяют, решено было сделать трёхцветный светодиодный индикатор по типу smart LED с различным миганием и цветом в зависимости от температуры.

Полупассивное охлаждение компьютерного БП - 4

Температуру измеряет датчик DS18B20, в зависимости от температуры увеличиваются либо уменьшаются обороты вентилятора. При достижении >67°С включается звуковой извещатель. Транзистор — любой NPN с током > тока вашего вентилятора. Также я пробовал управлять трёхпроводным вентилятором, всё получилось, но никак не мог заставить его полностью остановиться.

Изначально использовал дефолтную частоту ШИМ (448,28 Гц) но на низких оборотах кулер издавал едва заметный звон, что никак не вяжется с концепцией бесшумного охлаждения. Поэтому программно частота ШИМ поднята до 25 кГц.

Вот видео демонстрирующее работу устройства

А вот собственно, скетч, прошу сильно не пинать это мой первый скетч для Ардуины :)

// 2 - DS18x20 data
// 3 - green LED (a 330 Ohm resistor is necessary)
// 5 - orange LED (a 330 Ohm resistor is necessary)
// 6 - red LED (a 330 Ohm resistor is necessary)
// 9 - PWM Fan
// 8 - Buzzer

#include <OneWire.h>

byte temp; // temperature of sensor
byte greenLED = 3;
byte orangeLED = 5;
byte redLED = 6;
byte FanSpeed = 0;
int piezoPin = 8;
// Массив режимов работы светодиода
byte modes[] = {
   0B00000001, //Светодиод выключен
   0B00000101, //Горит постоянно
   0B00010101, //Мигание по 0.5 сек
   0B01010101, //Короткая вспышка раз в секунду
   0B10101010, //Две короткие вспышки раз в секунду
   0B00010101, //Три короткие вспышки раз в секунду
   0B01010101  //Частые короткие вспышки (4 раза в секунду)
};

uint32_t ms, ms1 = 0, ms2 = 0, ms3 = 0, ms4 = 0, ms5 = 0;
uint8_t  blink_loop = 0;
uint8_t  blink_mode = 0;
uint8_t  modes_count = 0; 
bool FirstRun = 0;

OneWire  ds(2);  // on pin 10 (a 4.7K resistor is necessary)

void analogWrite25k(int pin, int value)
{
    switch (pin) {
        case 9:
            OCR1A = value;
            break;
        case 10:
            OCR1B = value;
            break;
        default:
            // no other pin will work
        break;
    }
}

void setup(void) {

pinMode(redLED, OUTPUT);
pinMode(greenLED, OUTPUT);
pinMode(orangeLED, OUTPUT);
pinMode(9, OUTPUT);

modes_count = 1;
blink_mode = modes[modes_count];

    TCCR1A = 0;           // undo the configuration done by...
    TCCR1B = 0;           // ...the Arduino core library
    TCNT1  = 0;           // reset timer
    TCCR1A = _BV(COM1A1)  // non-inverted PWM on ch. A
           | _BV(COM1B1)  // same on ch; B
           | _BV(WGM11);  // mode 10: ph. correct PWM, TOP = ICR1
    TCCR1B = _BV(WGM13)   // ditto
           | _BV(CS10);   // prescaler = 1
    ICR1   = 200;         // TOP = 320
  
 // Serial.begin(9600);
 

}

void loop() {
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius;

 if ( ( ms - ms3 ) > 1000 || ms < ms3 ){
       ms3 = ms;
  
     if ( !ds.search(addr)) {
      //   Serial.println("No more addresses.");
      //   Serial.println();
         ds.reset_search();
         if ( ( ms - ms4 ) > 250 || ms < ms4 ){
         ms4 = ms;
         //delay(250);
    return;
      }
     }
  
     //  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    //   Serial.write(' ');
     //  Serial.print(addr[i], HEX);
       }

  if (OneWire::crc8(addr, 7) != addr[7]) {
    // Serial.println("CRC is not valid!");
      return;
  }
       
      // Serial.println();
 
  // the first ROM byte indicates which chip
  switch (addr[0]) {
    case 0x10:
      Serial.println("  Chip = DS18S20");  // or old DS1820
      type_s = 1;
      break;
    case 0x28:
      Serial.println("  Chip = DS18B20");
      type_s = 0;
      break;
    case 0x22:
      Serial.println("  Chip = DS1822");
      type_s = 0;
      break;
    default:
      Serial.println("Device is not a DS18x20 family device.");
      return;
  } 

  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end
 
 }
  
  //delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.

  if ( ( ms - ms2 ) > 900 || ms < ms2 ){
       ms2 = ms;
       
  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();

  }


  // Convert the data to actual temperature
  // because the result is a 16 bit signed integer, it should
  // be stored to an "int16_t" type, which is always 16 bits
  // even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw / 16.0;
  
  temp = celsius;

 // Serial.println("TEMPERATURE IS:");
 // Serial.println(temp);
 }
     
    ms = millis();
// Событие срабатывающее каждые 125 мс   
   if( ( ms - ms1 ) > 125|| ms < ms1 ){
       ms1 = ms;
       
// Режим светодиода ищем по битовой маске       

  if ( temp <= 50 ) {
       digitalWrite(orangeLED, LOW);
       digitalWrite(redLED, LOW);
       if(  blink_mode & 1<<(blink_loop&0x07) ) digitalWrite(greenLED, HIGH); 
       else  digitalWrite(greenLED, LOW);
       blink_loop++;    

       

                 if ( temp <= 40 ) {
                 blink_mode = modes[0];
                 analogWrite25k ( 9, 0);
                 FirstRun = 0;
                }
                 if ( temp >= 41 && temp <= 45 ) {
                 blink_mode = modes[1];

// Make a push impulse for starting fan (1 sec)
                 
                 if ( FirstRun == 0 ) {
                     ms5 = ms;
                     FirstRun = 1; 
                 }

                 if (FirstRun == 1 && (2000 > (ms - ms5))) { 
                    analogWrite25k ( 9, 33); // Fan start impulse
                 }
                 if (FirstRun == 1 && (2000 < (ms - ms5))) {
                 analogWrite25k ( 9, 28); // first speed
                 }
              }
                 if ( temp >= 46 && temp <= 50 && FirstRun == 1) {
                 blink_mode = modes[2];
                 analogWrite25k ( 9, 29);
                 }
      }

  
  if ( temp >= 51 && temp <= 61 ) {
       digitalWrite(greenLED, LOW);
       digitalWrite(redLED, LOW);
       if(  blink_mode & 1<<(blink_loop&0x07) ) digitalWrite(orangeLED, HIGH); 
       else  digitalWrite(orangeLED, LOW);
       blink_loop++;    
    

                if ( temp >= 51 && temp <= 54 ) {
                 blink_mode = modes[0];
                 analogWrite25k ( 9, 30);
                }
                 else if ( temp >= 55 && temp <= 58 ) {
                 blink_mode = modes[1];
                 analogWrite25k ( 9, 31);
                }
                 else if ( temp >= 59 && temp <= 61) {
                 blink_mode = modes[2];
                 analogWrite25k ( 9, 32);
                }
      }
   
     if ( temp >= 62 && temp <= 120 ) {
       digitalWrite(greenLED, LOW);
       digitalWrite(orangeLED, LOW);
       if(  blink_mode & 1<<(blink_loop&0x07) ) digitalWrite(redLED, HIGH); 
       else  digitalWrite(redLED, LOW);
       blink_loop++;    
    

                if ( temp >= 62 && temp <= 66 ) {
                 blink_mode = modes[0];
                 analogWrite25k ( 9, 33);
                }
                if ( temp >= 67 && temp <= 70 ) {
                 blink_mode = modes[1];
                 analogWrite25k ( 9, 34);
                }
                if ( temp >= 71 && temp <= 120) {
                 blink_mode = modes[2];
                 analogWrite25k ( 9, 50);
                 tone(piezoPin, 2500, 30);
                }
      }
   
   }  
 
}

Автор: Вадим Васильевич

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js