Ремонт системы охлаждения ноутбука Asus Zenbook с Arduino

После очередной чистки моего ноутбука Asus Zenbook вентиляторы охлаждения стали работать постоянно на полную мощность. Переустановка асусовских драйверов не помогла. Шум от двух постоянно работающих вентиляторов ужасный, замена всей платы ноута в сервисном центре займет время и деньги, решено поставить контроллер Arduino и термодатчик.

Оказалось, что сгорел каким-то образом выходной каскад цепи управления вентиляторами: на выходе control было 3.25 вольта. Когда я его отключил, вентиляторы продолжали работать: они выключаются при подаче нуля (видимо, рассчитано, что при обрыве цепи вентиляторы должны автоматически переходить в постоянно включенное состояние).

В ноутбуке оказалось место, точно подходящее под маленькую версию этого контроллера DF Robot Beetle (Arduino Leonardo):

 

Термодатчик, дающий температуру по протоколу OneWire с точностью до 0.1 градуса - Dallas DS18B20 установил на радиатор процессора на термопасту. Температура в этом месте отличается от температуры процессора, но это будет учтено в программе.

 

Схема подключения. Питание от USB удобно было подключить, к тому же это дает возможность легко соединить проводом USB и программировать.

 

Осталось за малым - написать программу:

#include <OneWire.h>

OneWire  oneWire(10);
byte addr[8] = {0x28, 0x2B, 0xC4, 0x9B, 6, 0, 0, 0xC9};

void setup() {
  Serial.begin(9600);
}

byte v = 0;
void loop(void) {
  float t = getTempOneWire(addr);

  if(v > 0 && t < 49) { // 58
    v = 0;
  } else {
    if(t >= 50) v = 80;
    if(t >= 51) v = 100; // 70 deg on CPU
    if(t >= 51.5) v = 130; // 71
    if(t >= 52) v = 160; // 72
    if(t >= 52.5) v = 200; // 73
    if(t >= 53) v = 255; // 74
  }
 
  analogWrite(11, v);
  Serial.print(t);
  Serial.print(' ');
  Serial.println(v);
  delay(1);
}

float getTempOneWire(byte *addr) {
  byte data[2];
  oneWire.reset();
  oneWire.select(addr);
  oneWire.write(0x44);
  delay(750);
  oneWire.reset();
  oneWire.select(addr);
  oneWire.write(0xBE);
  data[0] = oneWire.read();
  data[1] = oneWire.read();
  return ((data[1]<< 8)+data[0]) / 16.0;
}