1

Тема: Управление куллерами - фанбас.

Видео работы устройства: http://www.youtube.com/watch?v=ghqfvw53gIA
Стоит у меня домашний сервер, и вот проблема: или шумит жутко, или перегревается и виснет. Немного подумав решил что соорудив управление куллерами с этой проблемой хоть не окончательно, но справлюсь.
Контроллер решил использовать в корпксе TQFP32 (ATMEGA168-20AU). Куллеры у меня немного различаются - один имеер 2 вывода (только питание), на втором есть 3й контакт - скорость вращения. Скорость вращения регулировать решил через ШИМ. Отображать решил в процентах. На управление решил сделать два режима:
1)Управляется автоматически, в зависимости от температуры. При 45С скорость 70%. При 50С скорость 78%. Третий показатель температуры задается переменным резистером, и включает вращение на 100%. При этом режиме отображается: текущая температура, заданная температура и скорость куллеров в процентах.
2)Ручное управление. Два потенциометра регулируют скорость вращения каждый своего куллера. При этом режиме отображается: Скорость вращения кулера с датчиком в оборотах в минуту (rpm), скорость вращения в процентах, текущая температура.

Выбор режима управления определяется переключателем, встроенным в один из переменных резистеров. Второй резистер в автоматическом режиме управляет выбором критической температуры. В ручном режиме каждый резистер управляет своим кулером.

Детали использовал:
HL1    = Светодиод по вкусу
HL2    = Светодиод по вкусу
IC1    = DS18B20
IC2    = ATMEGA168-20AU
LCD    = WH1602M-YGH-CTK
M1    = Кулер 12v
M2    = Кулер 12В с датчиком
R1    = 1k
R2    = 10k
R3    = 4.7k
R4    = 50KПеременный с выключателем
R5    = 50KПеременный
R6    = 100
R7    = 100
R8    = 10k
R9    = 10k
S1    = Выключатель в резисторе
VD1    = диод любой smd
VD2    = диод любой smd
VD3    = диод любой smd
VD4    = диод любой smd
VT1    = КТ315б
VT2    = КТ315б
X    = 16MHz
Схема в формате spl7 http://mogalkov.ath.cx/fanbus/fanbus.spl7
http://mogalkov.ath.cx/fanbus/E3s.JPG
Плата  в формате lay http://mogalkov.ath.cx/fanbus/fancontrol002.lay
http://mogalkov.ath.cx/fanbus/layS.JPG
Скетч:

//Эта библиотека входит в комплект АРДУИНО ИДЕ
#include <LiquidCrystal.h> //библиотека ЛСД экранчика
//Эту библиотеку брал тут: http://robocraft.ru/files/library/OneWire.zip
#include <OneWire.h> //Библиотека работы с 1-ware
//А эту тут: dallas.milesburton.com/index.php?title=Dallas_Temperature_Control_Library#Latest
#include <DallasTemperature.h>//Библиотека работы с термодатсиками 1-ware
#define pwmpinA 10 //Выход ШИМ 1
#define pwmpinB 11 //Выход ШИМ 2
#define HallSensor 2  // pin для датчика оборотов вентилятора (прерывание)
#define ONE_WIRE_BUS 1 //Датчик температуры на аналоговом входе 5
//переключатель встроен в переменный резистор, как только повернул ручку - включился управляемый в ручную режим
#define SWBTN 0 //Переключатель режима работы (Авто/Управляемый) 
OneWire oneWire(ONE_WIRE_BUS);//скажем библиотеке где у нас градусник
DallasTemperature sensors(&oneWire);//скажем библиотеке где у нас градусник
LiquidCrystal lcd(5,6,7,8,9,12); //пины подключения ЛСД
int potB=5; //потенциометр изменения оборотов 2
int potA=0; //потенциометр изменения оборотов 1
int NbTopsFan, Calc, fadeValue, fadeValueA, procfade, procfadeA, CtempA,CtempB;  //целочисленные переменные для расчетов
typedef struct{ // Вводим новый тип переменных для вентиляторов 
  char fantype;
  unsigned int fandiv;
}fanspec;
//Массив переменных нового типа
fanspec fanspace[3]={{0,1},{1,2},{2,8}};
//Переменная, отвечающая за выбор типа датчика вентилятора (1 – униполярный датчик Холла, 2 –биполярный датчик Холла)
char fan = 1;  
//Эта функция у нас будет вызываться при каждом прерывании
void rpm(){NbTopsFan++;}

void rpmcalk()//подсчитываем обороты кулера
{
 NbTopsFan = 0; // Обнуляем переменную, содержащую обороты
 delay (1000); //Ждем 1 секунду
 Calc = ((NbTopsFan * 60)/fanspace[fan].fandiv);   //Рассчитываем величину оборотов за 60 секунд, поделенную на множитель вентилятора
}

void lcdprn()//отображаем информацию на экран
{
lcd.clear();//очистка экрана
lcd.setCursor(0, 0);//курсор на координаты
lcd.print("RPM:");//пишем текст
lcd.print(Calc);//пишем скорость кулера из переменной
lcd.setCursor(8, 0);//курсор на координаты
lcd.print("Spd1:");//пишем текст
lcd.print(procfade);//пишим проценты скорости кулера1
lcd.setCursor(0, 1);//курсор на координаты
lcd.print("Spd2:");//пишем текст
lcd.print(procfadeA);//пишим проценты скорости кулера2
lcd.setCursor(8, 1);//курсор на координаты
lcd.print("Temp:");//пишем текст
lcd.print(CtempA);//пишим температуру
lcd.print("C");//пишем текст
}

void lcdprnA()//отображаем информацию на экран в режиме автоконтроля
{
lcd.clear();//очистка экрана
lcd.setCursor(0, 1);//курсор на координаты
lcd.print("AUTO");//пишем текст значащий что выбран автоконтроль температуры
lcd.setCursor(9, 1);//курсор на координаты
lcd.print("Spd:");//пишем текст
lcd.print(procfade);//пишим проценты скорости кулеров
lcd.setCursor(0, 0);//курсор на координаты
lcd.print("Tmp:");//пишем текст
lcd.print(CtempA);//пишим текущюю температуру
lcd.print("C");//пишем текст
lcd.setCursor(8, 0);//курсор на координаты
lcd.print("CrT:");//пишем текст
lcd.print(CtempB);//пишим температуру КРИТИЧЕСКОГО реагирования
lcd.print("C");//пишем текст
}


void PotReadALL()//читаем и считаем потенциометры
{
  fadeValue=analogRead(potA);//читаем первый потенциометр
  fadeValueA=analogRead(potB);//читаем второй потенциометр
  fadeValue=fadeValue/4;//уменьшаем показания первого потенциометра до приемлимых для ШИМ вывода
  if (fadeValue<=128){fadeValue=128;}//Ограничиваем минимум оборотов до 50%
  procfade=(fadeValue/2.54);//пересчитываем показания первого потенциометра в проценты
  fadeValueA=fadeValueA/4;//уменьшаем показания второго потенциометра до приемлимых для ШИМ вывода
  procfadeA=(fadeValueA/2.54);//пересчитываем показания второго потенциометра в проценты
}

void TempTOvalue()//Читаем температуру с градусника
{
  sensors.requestTemperatures();//Опрашиваем градусники
  //градусник может быть не один, протокол 1-ware позволяет подключать
  //много устройств паралельно, но на моем дисплее место хватило токо на
  //один показатель температуры
  CtempA=sensors.getTempCByIndex(0);//присваиваем температуру переменной
}

//ручная регулировка скорости вращения
void manualcontrol(){

  PotReadALL();//читаем и считаем потенциометры
  rpmcalk();//считаем скорость кулера
  TempTOvalue();
  lcdprn();//Выводим информацию на дисплей
  analogWrite(pwmpinA, fadeValue);//задаем скорость вращения кулера 1         
  analogWrite(pwmpinB, fadeValueA);//задаем скорость вращения кулера 2         
  
}

void autocontrol()//Автоконтроль температуры
{
  PotReadALL();//читаки потенциомерты(с них получим установку критической температуры)
  CtempB=fadeValueA/3; //переводим результат потенциометра в температуру от 0 до 85
  TempTOvalue();//меряем температуру
  fadeValue=0;//сбрасываем показатель скорости
  if (CtempA>=45){fadeValue=180;}//сверяем скорость с критами
  if (CtempA>=50){fadeValue=200;}//сверяем скорость с критами
  if (CtempA>=CtempB){fadeValue=254;}//сверяем скорость с заданой температурой, если задана 
  //температура ниже предыдущих сверок скорость ВСЕГДА на максимуме.
  procfade=(fadeValue/2.54);//пересчитываем показания первого потенциометра в проценты
  lcdprnA();//Выводим информацию на дисплей
  analogWrite(pwmpinA, fadeValue);//задаем скорость вращения кулера 1         
  analogWrite(pwmpinB, fadeValue);//задаем скорость вращения кулера 2         
}

void setup()  { 
  pinMode(HallSensor, INPUT);  // Настраиваем pin на получение прерываний
  pinMode(SWBTN,INPUT); //пин на переключатель -на вход
  attachInterrupt(0, rpm, RISING);  //Привязываем прерывание по номеру 0 к нашей функции, причем высчитываться
 // она будет каждый раз при смене сигнала
  sensors.begin();//включаем сенсор температуры
  lcd.begin(16, 2);//Выставляем параметры экрана
  lcd.home();//очищаем экран и переводим курсор в начало
} 

void loop()  { 
 if (digitalRead(SWBTN)==HIGH){manualcontrol();}  //если переключатель включен - ручное управление вентиляторами
 else {autocontrol();}//иначе - автоконтроль
}

//При разработке этого устройствы использовал следующие статьи:
//http://mk90.blogspot.com/2010/08/arduino.html
//http://robocraft.ru/blog/arduino/136.html

http://mogalkov.ath.cx/fanbus/FANBAS002.7z Здесь лежит архив со схемами, скетчем и библиотеками.