Привет! Это устройство применимо не только в компьютерном БП, но мы будем про компьютерный, как насущный :)
Техпроцесс производства процессоров неуклонно уменьшается, вместе с ним уменьшается и энергопотребление. Процессоры последних поколений содержат в себе пригодную для повседневных задач графическую видео систему. Если вы не сильно требовательны к производительности в видео играх то за относительно скромный бюджет можно задуматься о тихом компьютере который будет издавать звуки только под большой нагрузкой, что случается не часто.
Далее идёт моё видение конфигурации компа для полупассивного охлаждения.
Средний CPU в пике своей загрузки выделяет 65 Вт тепла, охладить его можно заводским кулером с большей (нежели штатный) мощностью 120-150 Вт выставив настройки в BIOS чтобы он начинал крутиться только при загрузке 30-40% CPU либо температурой выше 40°С.
Ещё один источник шума это HDD, но тут всё просто, я заменил его на SSD.
Остался вентилятор блока питания который крутится постоянно. Можно купить полностью пассивный либо полу пассивный изначально, но тут цена вопроса: (от $150) возможно, есть смысл направить эти средства на бОльшую производительность?
Обычный, 500 Вт блок питания ($50) имеет огромный запас по мощности в моём случае, поэтому я решил отключить вентилятор полностью. Но при длительной работе под большой нагрузкой радиаторы внутри стали разогреваться свыше 60°С, так что решено было вернуть вентилятор но сделать его обороты контролируемыми.
За основу был взят Arduino nano на базе ATMEGA168PA, из разных кусков чужих проектов составлен свой.
Поскольку ресурсы контроллера позволяют, решено было сделать трёхцветный светодиодный индикатор по типу smart LED с различным миганием и цветом в зависимости от температуры.
Температуру измеряет датчик 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);
}
}
}
}
Автор: Вадим Васильевич