Тема: Управление куллерами - фанбас.
Видео работы устройства: 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
Плата в формате lay http://mogalkov.ath.cx/fanbus/fancontrol002.lay
Скетч:
//Эта библиотека входит в комплект АРДУИНО ИДЕ
#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 Здесь лежит архив со схемами, скетчем и библиотеками.