Система вентеляции подвала, этюд в 3 частях. Часть 1 - теория

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Уровень сложности - новичек!

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

Проект на стадии разработки, а именно проработана теоретическая и програмная часть, далее будет создание макета проекта, создание финального проекта.

 

Итак суть проекта: есть загородный дом, в нем есть подвал, в подвале есть комнотка, что-то вроде кладовой, в котором должна поддерживаться определенная температура в зимний период.

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

 

Задача проекта такова:

*Если температура в комнате в пределе нормы, которую можно настроить в программе, то ничего не делаем

*Если температура в комнате выше чем на улице и выше максимума, то включаем вентилятор и нагнетаем холодный воздух с улицы.

*Если температура в комнате меньше минимальной, то закрываем заслонку, и комната нагревается от естественного тепла в остальном доме.

Также в проекте должна быть предусмотрена возможность ручного управления вентилятором и заслонкой без использования нашей автоматики.

 

Этап разработки :

1)   ТЕОРИЯ

a.   Теоретическая схема (Done)

b.   Подборка компонентов (Done)

c.   Симуляция схемы и скетча (Done)

2)   Сборка макета (Waiting hardware)

a.   Собственно сборка макета.

b.   Дополнительная отладка скетча на реальном железе.

c.   Устранение возможных неисправностей чего-либо

3)   Сборка финального проекта

a.   Установка вентелятора.

b.   Установка ардуинки.

c.   Сдача объекта тестю.

d.   Последующая модернизация программной и аппаратной составляющей.

 

1)  Теоретическая схема.

Принципиальная схема такая

 

Упрощенная электрическая схема такая

 

2)  Подборка компонентов

Итак нам нужно:

1)  Ардуино нано

 

2)  2 датчика температуры, я выбрал (DHT22)

3)  реле ( взял двойное )

 

4)  серво

 

5)  переключатели

 

6)  кнопки

 

7)  серво-тестер

 

8)  конвертер 220 to 12

9)  конвертер 12 to 5

 

11) вентилятор от 220 (пока нет)     

12) заслонка (пока нет)

3)  Симуляция схемы и скетча

В симуляторе набросал такую схему.

 

 

Здесь нет развода по питанию на 12 и 5 в, но это больше для отладки скетча, пока жду железа.

 

Настрочил такой скетч:

#include <LiquidCrystal.h> // Подключаем библиотеку лсд экрана
#include <Servo.h> // Подключаем библиотеку серво
Servo motor; // обозначаем серву как мотор

//////////ЗАДАНИЕ ПОРТОВ//////////////////

uint8_t servo = 3;						// вешаем серву на 3 пин
LiquidCrystal lcd(4, 5, 6, 7, 8, 9);	// подключаем ЛСД к портам 4-9
int lcd_led = 13;						// вешаем подсветку ЛСД на пин 13
int prop = 2;							// вешаем вентелятор (реле от него) на пин 2
int t1 = A0;							// вешаем датчик температуры внутр на пин А0
int t2 = A1;							// вешаем датчик наружней температуры на пин А1
int button_1 = 12;						//порт кнопки 1 (+)
int button_2 = 11;						//порт кнопки 2 (-)
int button_3 = 10;						//порт кнопки 3 (настройка)

//////////////////////////////////////////

boolean button_push_1 = false;			//переменная нажатой кнопои 1
boolean button_push_2 = false;			//переменная нажатой кнопои 2
boolean button_push_3 = false;			//переменная нажатой кнопои 3
boolean maxmin_next = false;			//	
boolean goto_maxmin = false;			//
boolean screen_update = true;			// переменная обновления экрана
int temp_inside = 0; 					// переменные для датчика температуры 
int temp_outside = 0;					//
int hum_inside = 0;						//	
int hum_outside = 0;					//
int tmax = 5;							// начальная максимальная температура = 5 
int tmin = 1;							// начальная минимальная температура =0
int menu = 1;							// переменная меню
int regim = 0; 							// переменная режима работы
int i=0;								// вспомогательная переменная
boolean error_1 = false; 				// ошибка датчика 1
boolean error_2 = false; 				// ошибка датчика 2
unsigned long time_last_push=millis(); 	//время последнего нажатия кнопки
unsigned long time_last_term_update=0;	//время последнего обновления датчиков
unsigned long time_period = 0; 			// переменные для экрана отображения времени работы
int days = 0;							//										
int hours = 0;							//
int minutes = 0;						//
unsigned long seconds = 0;				//
  
//////// Настраиваемые параметры /////////
int time_term_update = 500;				//время обновления датчиков
int sleep = 2000; 						// время гашения экрана
int open_servo = 90; 					//положение открытой заслонки
int close_servo = 0; 					//положение закрытой заслонки

//////////////////////////////////////////
void setup() 							//предварительные настройки
{
pinMode(lcd_led, OUTPUT); 				//пин с подсветкой как выход
digitalWrite(lcd_led,HIGH); 			// включаем подсветку
lcd.begin(16, 2);						// включаем экран
//////////////////////////////////////////
//lcd.setCursor(5,0);            		//
//lcd.write("HELLO!");           		// П
//delay(100);                     		// Р
//lcd.clear();                    		// И
//lcd.setCursor(4,0);             		// В
//lcd.write("LOADING...");        		// Е
//lcd.setCursor(0,1);             		// Т
//  for (i=0;i<17;i++){           		// С
//lcd.setCursor(i,1);             		// Т
//lcd.print("#");                 		// В
//delay(10);                      		// И
//  }                             		// Е
//lcd.clear();                    		//
//////////////////////////////////////////

lcd.setCursor(0,0);
Serial.begin(9600);						//включаем вывод в порт
  pinMode(t1, INPUT);        			//ОБОЗНАЧАЕМ ПОРТЫ
  pinMode(t2, INPUT);        			//
  pinMode(button_1, INPUT);  			//  
  pinMode(button_2, INPUT);  			//
  pinMode(button_3, INPUT);  			//
  pinMode(prop, OUTPUT);     			//
term_update ();							// обновляем показания датчиков
}
void loop() 
{
  
  ////////////////////////////////////////если кнопку нажали больше чем слип милисекунд назад
  if(millis()-time_last_push>=sleep) 	//то гасим экран, если нет то зажигаем
  {
  digitalWrite(lcd_led,LOW);			 
  }
  else 
  {
  digitalWrite(lcd_led,HIGH);			
  }
  /////////////////////////////////////////////////Если кнопка плюс нажата, то листаем вперед
  
  if(digitalRead(button_2)==HIGH&&!button_push_2)	
  {
    button_push_2=true;								
    menu++;
    screen_update=true;
    if (menu==6)
    {menu=1;}
    time_last_push=millis();
   }
  if(digitalRead(button_2)==LOW&&button_push_2)
  {
    button_push_2=false;
    time_last_push=millis();
  }
  
  ///////////////////////////////////////////////// Если кнопка минус нажата, то листаем назад
  
 if(digitalRead(button_1)==HIGH&&!button_push_1)
  {
    button_push_1=true;
    menu--;
   screen_update=true;
    if (menu==0)
    {menu=5;}
    time_last_push=millis();
   }
  if(digitalRead(button_1)==LOW&&button_push_1)
  {
    button_push_1=false;
    time_last_push=millis();
  }
  
  //////////////////////////////////////////////////// Если нажимаем кнопку 3 то приравниваем переход к правде
  if(digitalRead(button_3)==HIGH&&!button_push_3)	// здесь эта заморочка с переменной перехода нужна для того,
  {													// чтобы при отпускании кнопки 3 переменная пушбаттон 3 
    button_push_3=true;								// принимала ложь, иначе кнопка 3 работает не корректно далее
    goto_maxmin =true;
    time_last_push=millis();
   }
  if(digitalRead(button_3)==LOW&&button_push_3)
  {
    button_push_3=false;
    time_last_push=millis();
  }
  //////////////////////////////////////////////////// идем в настройки лимитов
  if (!button_push_3&&goto_maxmin)
  {	
  	maxmin();
  }
  //////////////////////////////////////////////////// Если пришло время обновлять датчики делаем это
  if (millis()-time_last_term_update>=time_term_update)
  {
    term_update();
    screen_update=true;
  }
  
  //////////////////////////////////////////////////// Сравниваем температуры и ставим режим
  
  if(temp_inside>=tmax)
  {
  	if(temp_inside>temp_outside)
    {
      regim1();
      
    }
  	else 
    {
      regim2();
      
    }
  }
  else
  {
    if (temp_inside>tmin)
    {
      regim2();
      
    }
    else 
    {
      regim3();
      
    }
  }
  ///////////////////////////////////////////////////// В зависимости от значения меню идем туда
  switch (menu){
    case 1:
      menu_1();
      break;
    case 2:
      menu_2();
      break;
    case 3:
      menu_3();
      break;
    case 4:
      menu_4();
      break;
    case 5:
      menu_5();
      break;   
  	}
  }
////////////////////////////////////////////////////// 3 режима:
													// 1 вент включен, заслонка поднята (усиленное охлаждение)
													// 2 вент выключен, заслонка открыта (умеренное охлаждение)
													// 3 вент выключен, заслонка закрыта (сохранение/нагрев)
void regim1 (){
  digitalWrite(prop, HIGH);//включаем вент
  motor.attach(servo);
  motor.write(open_servo);// заслонка открыта
  regim=1;
}
void regim2 (){
  digitalWrite(prop, LOW);//выключаем вент
  motor.attach(servo);// заслонка открыта
  motor.write(open_servo);
  regim=2;
}
void regim3 (){
  digitalWrite(prop, LOW);//выключаем вент
  motor.attach(servo);// заслонка закрыта
  motor.write(close_servo);
  regim=3;
}

////////////////////////////////////////////////////// Обновление показания датчиков температуры
													// пока нет железа, делаем из эмулятора
													// показания влажности чисто для справки
													// Если температура не получена, выводим ошику
void term_update () {
  temp_inside =(analogRead(t1)-103)*0.5;
  temp_outside =(analogRead(t2)-103)*0.5;
  hum_inside = 90;
  hum_outside = 80;
  time_last_term_update = millis();
  if (temp_inside == 0)
    {error_1=true;}
  else  {error_1=false;}
  if(temp_outside == 0)
    {error_2=true;}
    else{error_2=false;}  
}
/////////////////////////////////////////////////////// Вывод данных о температуре
void menu_1()
{
  if(screen_update)
  {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.clear();
  lcd.print("1) TEMPERATURE");
  lcd.setCursor(1,1);
  lcd.print("IN=");
  if (error_1)
  {
    lcd.print("ERR");
  }
  else
  {
    lcd.print(temp_inside);
  }
  lcd.setCursor(8,1);
  lcd.print("OUT=");
  if (error_2)
  {
    lcd.print("ERR");
  }
  else 
  {
    lcd.print(temp_outside);
  }
  }
  screen_update=false;
}

////////////////////////////////////////////////////// Вывод данных о влажности

void menu_2(){
  if (screen_update)
  {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.clear();
  lcd.print("2) HUMIDITY");
  lcd.setCursor(1,1);
  lcd.print("IN=");
  if (error_1)
  {lcd.print("ERR");}
  else{lcd.print(hum_inside);}
  lcd.setCursor(8,1);
  lcd.print("OUT=");
  if (error_2)
  {lcd.print("ERR");}
  else {lcd.print(hum_outside);}
  }
  screen_update=false;
}

////////////////////////////////////////////////////// Вывод крайних значений (не настройка)

void menu_3(){
  if (screen_update)
  {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.clear();
  lcd.print("3) LIMITS");
  lcd.setCursor(1,1);
  lcd.print("MIN=");
  lcd.print(tmin);
  lcd.setCursor(8,1);
  lcd.print("MAX=");
  lcd.print(tmax);
  }
  screen_update=false;
}

////////////////////////////////////////////////////// Информация о текущем режиме работы

void menu_4(){
  if (screen_update)
  {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.clear();
  lcd.print("4) MODE ");
  lcd.print(regim);
  lcd.setCursor(0,1);
  lcd.print("FUN ");
  if (regim == 1){lcd.write("ON");}else{lcd.write("OFF");}
  lcd.setCursor(8,1);
  lcd.print("GATE ");
  if (regim != 3){lcd.write("ON");}else{lcd.write("OFF");}
  }
  screen_update=false;
  }

////////////////////////////////////////////////////// Информация о продолжительности времени работы

void menu_5(){
  if (screen_update)
  {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("5) WORK TIME");
  lcd.setCursor(1,1);
  time_period = millis()/1000;
  seconds=time_period-60*minutes-3600*hours-86400*days;
  while (seconds>=60){
  minutes++;
  seconds=seconds-60;
  }
  while (minutes>=60){
  hours++;
  minutes=minutes-60;
  }
  while (hours>=24){
    days++;
  hours=hours-24;}
if (days<10){lcd.print(" ");}
lcd.print(days);
lcd.print("D ");
if (hours<10){lcd.print(" ");}    
lcd.print(hours);
lcd.print("H ");
if (minutes<10){lcd.print(" ");}    
lcd.print(minutes);
lcd.print("M ");
if (seconds<10){lcd.print(" ");}  
lcd.print(seconds);
  lcd.print("S");
  }
  screen_update=false;
}  

////////////////////////////////////////////////////// Настройка митимальной и максимальной температуры
void maxmin()
{
  maxmin_next=false;
  screen_update=false;
  
  while(!maxmin_next)// Печатаем мин пока нет некс
	{
  		button_push_3=false;
  		lcd.clear();
  		lcd.setCursor(3,0);
  		lcd.print("SET LIMITS");
  		lcd.setCursor(5,1);
  		lcd.print("MIN=");
  		lcd.print(tmin);
    	while(!screen_update)// Читаем кнопки пока не изменится значение Тмин
  		{
  			if (digitalRead(button_1)==HIGH&&!button_push_1)
   			{
    			button_push_1 = true;
    			tmin++;
    			screen_update=true;
   			}
    		if (digitalRead(button_1)==LOW&&button_push_1)
	    	{
    			button_push_1= false;
    			time_last_push=millis();
   			}
  		  	if (digitalRead(button_2)==HIGH&&!button_push_2)
   			{
    			button_push_2=true;
    			tmin--;
    			screen_update=true;
   			}
    		if (digitalRead(button_2)==LOW&&button_push_2)
  	 		{
    			button_push_2=false;
    			time_last_push=millis();
   			}
  			if (tmin>=tmax-1)
   			{
    			tmax=tmin+1;
  			}
  			if (digitalRead(button_3)==HIGH&&!button_push_3)
  			{
    			button_push_3=true;
		    	maxmin_next=true;
              	screen_update=true;   
      	     	time_last_push=millis();
       		 }
    		if (digitalRead(button_3)==LOW&&button_push_3)
    		{
    			button_push_3=false; 
    			time_last_push=millis();
    		}
		}
  		screen_update=false;
  	}
  	screen_update=false;
  	maxmin_next=false;
  	while(!maxmin_next)
  	{
  		lcd.clear();
  		lcd.setCursor(3,0);
  		lcd.print("SET LIMITS");
  		lcd.setCursor(5,1);
  		lcd.print("MAX=");
   		lcd.print(tmax); 
  		while(!screen_update)
  		{
  			if (digitalRead(button_1)==HIGH&&!button_push_1)
   		 	{    
       	    	button_push_1=true;
    		 	tmax++;
    		 	screen_update=true; 
       		}
    		if (digitalRead(button_1)==LOW&&button_push_1)
    		{	 
    			button_push_1=false;
			 	time_last_push=millis();
       		}
    		if (digitalRead(button_2)==HIGH&&!button_push_2)
    		{
            	button_push_2=true;
				tmax--;
    		 	screen_update=true;
       		}
    		if (digitalRead(button_2)==LOW&&button_push_2)
       	 	{
    			button_push_2=false;
    			time_last_push=millis();
     		}
  				if(tmax<=tmin+1)
     		{
    			tmin=tmax-1;
     		}
			if (digitalRead(button_3)==HIGH&&!button_push_3)
        	{
    			button_push_3=true;
           		maxmin_next=true;
              	screen_update=true;
       			time_last_push=millis();
        	}  
    		if (digitalRead(button_3)==LOW&&button_push_3)
    		{
     			button_push_3=false; 
     			time_last_push=millis();
    		}
  		}
    	screen_update=false;
  	}
    maxmin_next=false;
  goto_maxmin=false;
  screen_update=false;
}

 

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

Итак, вроде все худо-бедно работает.

 

На этом теоретическая часть заканчивается, жду железа для сборки макета.

 

Мысли для последующей реализации (будут реализовываться в дальнейшем):

1)   Прикрутить спящий режим для экономии энергии.

2)   Добавить датчик движение и включение света (в помещении).

3)   В меню настроек включить другие функции (поворот серво, яркость экрана, время задержки обновления датчиков и.т.д.)

4)   Запись в память настроек максимума и минимума, чтение из памяти настроек в начале.

bwn
Offline
Зарегистрирован: 25.08.2014

В порядке размышлений, не критика. Заменить серву с заслонкой на второй вентилятор - первый вент.выполняет функцию перемешивания (забор сверху, выход снизу.) и нормализует температуру по всему объему помещения. Приточный вентилятор поставить как вытяжной, на выход воздушный клапан (заслонку). Температуру помещения измеряем по двум точкам (верх-низ), при заданной разнице осуществляем перемешивание, если средняя выше заданной, включаем вытяжку.
А лепить спящие режимы на систему с сетевым питанием занятие бесполезное, сэкономите на миллисекунду работы вентилятора.

pav2000
Offline
Зарегистрирован: 15.12.2014

Предложения по железу:

1. Используйте один ИП на 220 в 5 вольт и подавайте на Vcc. Иначе встроенный стабилизатор будет не хило грется. Заодно "большая" экономия энергии будет. Правда одновремеенно включать USB и питатель не рекомендую.

2. Согласен с bwn. Вентилятор лучше ставить на вытяжку + обратный клапан. Заслонку выкинуть с сервоприводом, сделать отверстие приточки с жалюзи. Подсос конечно будет но он будет минимален. Если помещение небольшое то перемешивание можно не делать.

3. Датчики влажности температуры - нужен подтягивающий резистор на каждый датчик 4.7 к.

4. Кнопки если как на картинке то очень плохие.

5. ИХМО я бы  выкинул тумблера для ручного управления и сделал бы управление програмное через кнопки и выбор из меню.  Либо тумблера ставил параллельно реле на 220 вольт.

По программе:

1. Вопрос - не увидел подавления дребезга кнопок.

2. Однозначно надо учитывать влажность иначе весной можно получить обильный конденсат в подвале.

 

 

 

 

 

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

bwn пишет:

Заменить серву с заслонкой на второй вентилятор - первый вент.выполняет функцию перемешивания (забор сверху, выход снизу.) и нормализует температуру по всему объему помещения. Приточный вентилятор поставить как вытяжной, на выход воздушный клапан (заслонку). 

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

bwn пишет:

Температуру помещения измеряем по двум точкам (верх-низ), при заданной разнице осуществляем перемешивание, если средняя выше заданной, включаем вытяжку.

Помещение не большое, буквально 2м х 3м х 2м. тоже сначала думал о 2-х датчиках, но потом отказался. По той же причине нет смысла использовать 2-ой перемешивающий вентелятор.

pav2000 пишет:

1. Используйте один ИП на 220 в 5 вольт и подавайте на Vcc. Иначе встроенный стабилизатор будет не хило грется. Заодно "большая" экономия энергии будет. Правда одновремеенно включать USB и питатель не рекомендую.

спасибо за совет, может так и сделаю, опять же сообщаю что я новичек и руководствовался рекомендуемым входным напряжением 7-12V, я так понял что если подавать на Vcc то он идет без стабилизации. Учту.

pav2000 пишет:

2. Согласен с bwn. Вентилятор лучше ставить на вытяжку + обратный клапан. 

Вытяжка там есть, так сказать естественная, и вытягивает она хорошо, с этим проблем не должно быть. 

pav2000 пишет:

5. ИХМО я бы  выкинул тумблера для ручного управления и сделал бы управление програмное через кнопки и выбор из меню.  Либо тумблера ставил параллельно реле на 220 вольт.

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

pav2000 пишет:

1. Вопрос - не увидел подавления дребезга кнопок.

Кнопочки сделаю, наверное прикручу "титановый велосипед"

pav2000 пишет:

2. Однозначно надо учитывать влажность иначе весной можно получить обильный конденсат в подвале.

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

 

 

 

bwn
Offline
Зарегистрирован: 25.08.2014

У меня помещение тоже небольшое, перемешивание делал для ликвидации темных углов с плесенью. Застойные зоны там всегда.
Ну а воздушный клапан вместо заслонки. Он и заслонку изображает и воздуху течь не мешает.
У себя из них еще и кошкам вход с улицы сделал.

pav2000
Offline
Зарегистрирован: 15.12.2014

По поводу тумблеров их надо ставить как дубль контактов реле. Так надежнее будет.

По поводу влажности  http://arduino.ru/forum/proekty/kontrol-vlazhnosti-podvala-arduino-pro-mini

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

При увеличении воздухообмена возможно выпадение конденсата.

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

pav2000 пишет:

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

При увеличении воздухообмена возможно выпадение конденсата.

Я сейчас понял что название темы может смутить, но по функционалу устройство нужно, чтобы поддерживать температуру, забирать с улицы холодный воздух, но не переохлаждать помещение ниже установленного уровня.

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Проект медленно эволюционирует на данный момент код такой:

//++++++++++++++++++++++++++++++++++++++++++++++++++++
// ПРОГРАММА УПРАВЛЕНИЯ ВЕНТЕЛЯЦИЕЙ ПОДВАЛА ТЕСТЯ   //
//----------------------------------------------------
#define Ver 1.32									//
// создатель Mr.PRIVET								//
// отдельное спасибо Клапауцию за кнопочный велсепед//
//++++++++++++++++++++++++++++++++++++++++++++++++++++

//====================================================
//Титановый велсипед Клапауция						//
//====================================================
class BUTTON {										//
public:												//
//====================================================
static const byte bounce_              =   5; 		// длительность отслеживания дребезга.
static const byte doubleclick_         =  20; 		// длительность отслеживания двойного клика.
static const unsigned long timer_      = 500; 		// длительность отслеживания неактивности.
static const unsigned int retention_   = 200; 		// длительность отслеживания нажатия и удержания.
//====================================================
bool       click_down;								//
bool         click_up;								//
bool      doubleclick;								//
bool            timer;								//
bool        retention;								//
//====================================================
unsigned long _millis;								//
bool            _push;								//
bool       _real_push;								//
bool    _double_click;								//
byte          _clicks;								//
bool           _timer;								//
bool       _retention;								//
//====================================================
byte       _pinbutton;								//
//====================================================
BUTTON(byte pinbutton) {							//
_pinbutton = pinbutton;								//
pinMode(_pinbutton, INPUT);							//
digitalWrite(_pinbutton, 1);						//
//====================================================
click_down                = 0;						//
click_up                  = 0;						//
doubleclick               = 0;						//
timer                     = 0;						//
retention                 = 0;						//
//====================================================
_millis            = millis();						//
_push=digitalRead(_pinbutton);						//
_real_push                = 0;						//
_double_click             = 0;						//
_clicks                   = 0;						//
_timer                    = 0;						//
_retention                = 0;						//
//====================================================
}													//
void read() {										//
//====================================================
unsigned long _new_millis     = millis();			//
bool _new_push = digitalRead(_pinbutton);			//
//====================================================
bool _new_real_push	   = 0;							//
bool _new_double_click = 0;							//
bool _new_timer        = 0;							//
bool _new_retention    = 0;							//
//====================================================
click_down             = 0;							//
click_up               = 0;							//
doubleclick            = 0;							//
timer                  = 0;							//
retention              = 0;							//
//====================================================
if(_new_push!=_push)                                //
{_push=_new_push;_millis=_new_millis;}	            //
//====================================================
if (_new_millis - _millis > bounce_)                // 
{_new_real_push = 1;}		                        //
if (_new_millis - _millis > doubleclick_)           //
{_new_double_click = 1;}	                        //
//====================================================
if (_new_double_click != _double_click)             //
{_double_click = _new_double_click;                 //
if(_double_click == 1) {_clicks = 0;}}	            //
if(_new_real_push!=_real_push)                      //
{_real_push=_new_real_push;                    		//
if (_push == 0 && _real_push == 0) 					//
{click_down = 1;++_clicks;							//
if (_clicks == 2) {_clicks = 0; doubleclick = 1;}	//
}													//
if (_push == 1 && _real_push == 1) {click_up = 1;}	//
}													//
//====================================================
if (_new_millis - _millis > timer_) _new_timer = 1; //
if (_new_timer != _timer) {_timer = _new_timer;		//
if (_push == 1 && _timer == 1) {timer = 1;}			//
}													//
//====================================================
if (_new_millis-_millis>retention_)_new_retention=1;//
if (_new_retention!=_retention)						//
{_retention=_new_retention;		                    //
if (_push == 0 && _retention == 1) {retention = 1;}	//
}													//
//====================================================
}													//
};													//
//====================================================

//====================================================
//Библионтеки										//
//====================================================
#include <LiquidCrystal.h>                      	// Подключаем библиотеку лсд экрана
#include <Servo.h>                              	// Подключаем библиотеку серво
//#include <DHT.h>									// подключаем библиотеку термодатчика РАСКОМЕНТИТЬ
#include <EEPROM.h>								    // подключаем библиотеку памяти РАСКОМЕНТИТЬ
//Servo motor;                                    	// обозначаем серву как мотор
//====================================================
// Обозначение пинов								//
//====================================================
#define pin_button_1 		12						// порт кнопки 1 (+)
#define pin_button_2 		11						// порт кнопки 2 (-)
#define pin_button_3 		10						// порт кнопки 3 (настройка)
#define pin_termo_in 		A0						// вешаем датчик температуры внутр на пин А0
#define pin_termo_out 		A1						// вешаем датчик наружней температуры на пин А1
#define pin_piezo_low 		A2						// вешаем пьезо пищалку на A2 порт (тихо)
#define pin_piezo_hi 		A3						// вешаем пищалку на А3 порт (громко)
#define pin_prop 			 2						// вешаем вентелятор (реле от него) на пин 2
//#define pin_servo 			14						// вешаем серву на 3 пин (ПЕРЕДЕЛАТЬ)
#define pin_lcd_led 		13						// вешаем подсветку ЛСД на пин 13
#define RGB_R 				3						// вешаем RGB на пины 	3
#define RGB_G 				0						//						0
#define RGB_B 				1						//						1
//====================================================
//ЗАДАНИЕ ПОРТОВ									//
//====================================================
LiquidCrystal lcd(4, 5, 6, 7, 8, 9);            	// подключаем ЛСД к портам 4-9
int lcd_led = 13;                               	// вешаем подсветку ЛСД на пин 13
BUTTON b_1(pin_button_1);                           // велсипед на 1 кнопку
BUTTON b_2(pin_button_2);                           // велсипед на 2 кнопку
BUTTON b_3(pin_button_3);                           // велсипед на 3 кнопку
//DHT termo_in(pin_termo_in,DHT22);					// подключаем внутренний термометр РАСКОМЕНТИТЬ
//DHT termo_out(pin_termo_out,DHT22);					// подключаем внешний термометр РАСКОМЕНТИТЬ
//====================================================

//====================================================
// Переменные										//
//====================================================
bool               screen_update = true;       		// переменная обновления экрана
bool                   error_in = false;       		// ошибка датчика 1
bool                  error_out = false;       		// ошибка датчика 2
bool             manual_mode_on = false;			// переменная ручного режима
bool 				  vent_anim = false;			// для анимации вентелятора
float 		            	    temp_in;           	// переменная температуры внутри
float 		                   temp_out;           	// переменная температуры снаружи
float 			                 hum_in;          	// переменная влажности внутри           
float 			                hum_out;           	// переменная влажности снаружи
float                   temp_in_cal = 0;			// калибровка температуры внутри
float                  temp_out_cal = 0;			// калибровка температуры снаружи
float                    hum_in_cal = 0;			// калибровка влажности внутри
float                   hum_out_cal = 0;			// калибровка влажности снаружи
int 			               menu = 0;           	// переменная меню
byte    		               mode = 0;           	// переменная режима работы
byte					     p_mode = 0;			// переменная предыдущий режим
byte                   sound_volume = 1;			// переменная уровня звука
unsigned long time_last_term_update = 0;          	// время последнего обновления датчиков
unsigned long   time_last_vent_anim = 0;			// время последней анимации вентелятора
unsigned long           time_period = 0;           	// переменные для экрана отображения времени работы
unsigned long               seconds = 0;            // количество секунд работы
int                            days = 0;       	    // количество дней работы                                                                                                                                                        
int                           hours = 0;   	        // количество часов работы
int                         minutes = 0;            // количество минут работы
//====================================================

//====================================================
//Начальные параметры								//
//====================================================
int				 time_term_update = 500;       	    // время обновления датчиков
//int						open_servo = 90;            // положение открытой заслонки
//int						close_servo = 0;            // положение закрытой заслонки
int					time_vent_anim = 50;			// скорость анимации вентелятора
float					  	   temp_max;            // начальная максимальная температура = 5 
float					   	   temp_min;            // начальная минимальная температура =1
//====================================================

//====================================================
//Кастомные символы параметры						//
//====================================================
byte cels[8] ={B01100,B10010,B10010,B01100,B00000,B00000,B00000,B00000};
byte vent_1[8] ={B00011,B00011,B00001,B00000,B00111,B00110,B00000,B00000};
byte vent_2[8] ={B00000,B01100,B11100,B00000,B10000,B11000,B11000,B00000};
byte drop[8] ={B00000,B00100,B00100,B01110,B11101,B11101,B01110,B00000};
byte vent_3[8] ={B00000,B00110,B00111,B00000,B00001,B00011,B00011,B00000};
byte vent_4[8] ={B11000,B11000,B10000,B00000,B11100,B01100,B00000,B00000};
byte termo[8] ={B00110,B00110,B00110,B00110,B01101,B01101,B00110,B00000};
//====================================================
// Запись и чтение EEPROM							//
//====================================================
void EEPROM_float_write(int addr, float val)		//
{													//
//byte *x = (byte *)&val;							//РАСКОМЕНТИТЬ
//for(byte i = 0; i < 4; i++) 						//РАСКОМЕНТИТЬ
//EEPROM.write(i+addr*4, x[i]);						//РАСКОМЕНТИТЬ
}													//
float EEPROM_float_read(int addr) 					//
{   												//
byte x[4];											//
for(byte i = 0; i < 4; i++)							//
x[i] = EEPROM.read(i+addr*4);						//
float *y = (float *)&x;								//
return y[0];										//
}													//
//====================================================

//================================================================================================
// Изменение цвета диода																		//
//================================================================================================
void RGB_color (char color[ ],byte color_n)														//
{																								//
  if (color_n==0)																				//
  {																								//
  if (color     == "RED"){digitalWrite(RGB_R, 1);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 0);}//
  if (color    == "BLUE"){digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 1);}//
  if (color   == "GREEN"){digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 1);digitalWrite(RGB_B, 0);}//
  if (color   == "WHITE"){digitalWrite(RGB_R, 1);digitalWrite(RGB_G, 1);digitalWrite(RGB_B, 1);}//
  if (color   == "YELOW"){digitalWrite(RGB_R, 1);digitalWrite(RGB_G, 1);digitalWrite(RGB_B, 0);}//
  if (color == "MARRINE"){digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 1);digitalWrite(RGB_B, 1);}//
  if (color    == "PINK"){digitalWrite(RGB_R, 1);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 1);}//
  if (color     == "OFF"){digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 0);}//
  }																								//
  else																							//
  {																								//
  if (color_n == 1){digitalWrite(RGB_R, 1);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 0);}		//
  if (color_n == 5){digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 1);}		//
  if (color_n == 3){digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 1);digitalWrite(RGB_B, 0);}		//
  if (color_n == 6){digitalWrite(RGB_R, 1);digitalWrite(RGB_G, 1);digitalWrite(RGB_B, 1);}		//
  if (color_n == 2){digitalWrite(RGB_R, 1);digitalWrite(RGB_G, 1);digitalWrite(RGB_B, 0);}		//
  if (color_n == 4){digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 1);digitalWrite(RGB_B, 1);}		//
  if (color_n == 7){digitalWrite(RGB_R, 1);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 1);}		//
  if (color_n == 8){digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 0);}		//
  }																								//
}																								//
//================================================================================================

//================================================================================================
// Мерцание светодиода
//================================================================================================
void RGB_blink (char color[ ],int _delay)														//
{																								//
  bool pin_r = digitalRead(RGB_R);																//
  bool pin_g = digitalRead(RGB_G);																//
  bool pin_b = digitalRead(RGB_B);																//
  digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 0);							//
  delay(_delay/4);																				//
  if (color     == "RED"){digitalWrite(RGB_R, 1);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 0);}//
  if (color    == "BLUE"){digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 1);}//
  if (color   == "GREEN"){digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 1);digitalWrite(RGB_B, 0);}//
  if (color   == "WHITE"){digitalWrite(RGB_R, 1);digitalWrite(RGB_G, 1);digitalWrite(RGB_B, 1);}//
  if (color   == "YELOW"){digitalWrite(RGB_R, 1);digitalWrite(RGB_G, 1);digitalWrite(RGB_B, 0);}//
  if (color == "MARRINE"){digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 1);digitalWrite(RGB_B, 1);}//
  if (color    == "PINK"){digitalWrite(RGB_R, 1);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 1);}//
  if (color     == "OFF"){digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 0);}//
  delay(_delay/2);																				//
  digitalWrite(RGB_R, 0);digitalWrite(RGB_G, 0);digitalWrite(RGB_B, 0);							//
  delay(_delay/4);																				//
  digitalWrite(RGB_R, pin_r);digitalWrite(RGB_G, pin_g);digitalWrite(RGB_B, pin_b);				//
}																								//
//================================================================================================

//====================================================
// Обновление показания датчиков температуры		//
//====================================================
void term_update()									//
{                                                   //
temp_in  =  -9.5+temp_in_cal;			        	// отладка
temp_out = -10.56+temp_out_cal; 			        //
hum_in   = 90.26+hum_in_cal;    	                //
hum_out  = 80.88+hum_out_cal; 			            //==
//temp_in=termo_in.readTemperature()*100+temp_in_cal;	//
//temp_out=termo_out.readTemperature()*100+temp_out_cal;// РАСКОМЕНТИТЬ
//hum_in=termo_in.readHumidity()*100+hum_in_cal;		//
//hum_out=termo_out.readHumidity()*100+hum_out_cal;		//
  if (hum_in>100) hum_in=100;				        //==						
  if (hum_out>100) hum_out=100;				        //
time_last_term_update = millis();       	        //
if(isnan(hum_in)||isnan(temp_in))      	            //
{error_in=true;}									//
else  {error_in=false;}                            	//
if(isnan(hum_out)||isnan(temp_out))        	        //
{error_out=true;}                                	//
else{error_out=false;}								//
}                                                   //
//====================================================

//====================================================
//Обновление кнопок									//
//====================================================
void update_buttons()								//
{													//
  	b_1.read();										//
	b_2.read();										//
	b_3.read();										//
  if(b_1.timer||b_2.timer||b_3.timer)  				// если кнопки не нажали определенный период, то гасим экран, если нет то зажигаем
	{												//
    digitalWrite(pin_lcd_led,LOW);                  // ЗАКОМЕНТИТЬ
    //lcd.backlight()								// РАСКОМЕНТИТЬ
	}												//
if(b_1.click_down||b_2.click_down||b_3.click_down)	//
	{												//
    digitalWrite(pin_lcd_led,HIGH);                 // ЗАКОМЕНТИТЬ                
  //lcd.nobacklight()								// РАСКОМЕНТИТЬ
	}												//
}													//
//====================================================

//====================================================
// Режимы											//
//====================================================
void modes(byte _mode)                             	// 
{													//
  if(_mode==1&&!manual_mode_on)						//
  {                                      			//
    digitalWrite(pin_prop, HIGH);                   // включаем вент
    //motor.attach(pin_servo);                        // подключаем серво
    //motor.write(open_servo);                        // заслонка открыта
  }													//
  if (_mode==2&&!manual_mode_on)					//
  {    												//
    digitalWrite(pin_prop, LOW);                    // выключаем вент
    //motor.attach(pin_servo);                        // подключаем серво
    //motor.write(open_servo);                        // заслонка открыта
  }                                                 //
  if (_mode==3&&!manual_mode_on)					//
  {													//
    digitalWrite(pin_prop, LOW);                    // выключаем вент
    //motor.attach(pin_servo);                        // подключаем серво
    //motor.write(close_servo);                       // заслонка закрыта
  }													//
}													//
//====================================================

//====================================================
//Настройка переменных								//
//====================================================
int set_up											//
(char vid[], char tip[],int min, int max,float step)// 
{float valum;										//
update_buttons();									//
bool press_1 = false;								//
bool press_2 = false;								//
screen_update= false;								//
while(!b_3.click_down)                        	 	// Печатаем пока не нажата b_3
	{												//
  		lcd.clear();								//
      	lcd.print(vid);								//
      	lcd.setCursor(0,1);							//
      	lcd.setCursor(4,1);							//
  		lcd.print(tip);								//
        lcd.print("=");								//
        lcd.print(int(valum));						//
  		lcd.print(".");                             //
  		lcd.print(int(abs((valum-int(valum))*10)));	//
      	while(!screen_update)						// Читаем кнопки пока не изменится значение
        {											//
        	update_buttons();						//
            if (b_2.click_down)						//
            {										//
            	valum=valum+step;					//
                if(valum>max){valum=max;}			//
                screen_update=true;					//
            }										//
            if (b_2.retention)						//
            {										//
              press_2=true;							//
            }										//
            if(press_2)								//
            {										//
            	valum=valum+step;					//
                if(valum>max){valum=max;}			//
                delay(10);							//
                screen_update=true;					//
            }										//
            if (b_2.click_up)						//
            {										//
              	press_2=false;						//
            }										//
            if (b_1.click_down)						//
            {										//
                valum=valum-step;					//
                if (valum<min)						//
                {									//
                  	valum=min;						//
                }									//
                screen_update=true;					//
            }										//
            if (b_1.retention)						//
            {										//
              	press_1=true;						//
            }										//
            if(press_1)								//
            {										//
            	valum=valum-step;					//
                if(valum<min)						//
                {									//
                  	valum=min;						//
                }									//
                delay(10);							//
                screen_update=true;					//
            }										//
            if (b_1.click_up)						//
            {										//
              	press_1=false;						//
            }										//							
        if (b_3.click_down)							//
            {										//
          		screen_update=true;					//
            }										//
        }											//
        screen_update=false;						//
    }												//
screen_update=true;									//
 return valum;										//
}													//
//====================================================

//====================================================
//Играние тонов										//
//====================================================
void play_tone(int ton, int dur, int post_delay) 	//
{ 													//
  if (ton>29){ton=29;}								//
  for(long i=0;i<dur*1000L;i+=(3000-100*ton)*2) 	//
  {													//
    if (sound_volume=1)                             //
    digitalWrite(pin_piezo_low, HIGH);				//
    if (sound_volume=2)                             //
    digitalWrite(pin_piezo_hi, HIGH);				//
    delayMicroseconds(3000-100*ton);				//
    if (sound_volume=1)                             //
    digitalWrite(pin_piezo_low, LOW);				//
    if (sound_volume=2)                             //
    digitalWrite(pin_piezo_hi, LOW);				//
    delayMicroseconds(3000-100*ton);				//
  }													//
  delay(post_delay);								//
}													//
//====================================================

//====================================================
//Вывод данных о температуре						//
//====================================================
void menu_1()                                       //
  													//
{													//
  if(screen_update)									//
  {													//
  	lcd.setCursor(0,0);								//
  	lcd.clear();									//
  	lcd.print("1) TEMPERATURE");					//
  	lcd.setCursor(0,1);								//
  	lcd.print("IN=");								//
  	if (error_in)									//
  	{												//
    	lcd.print("ERR");							//
  	}												//
  else												//
  {													//
   lcd.print(temp_in,1);					  		//
  }													//
    lcd.setCursor(8,1);								//
    if(temp_out<=-10){lcd.print("OUT");}		    //
    else{lcd.print("OUT=");}						//
  	if (error_out)									//
  	{												//
    lcd.print("ERR");								//
  	}												//
  else 												//
  	{												//
    lcd.print(temp_out,1);					 		//
    }												//
  }													//	
  screen_update=false;								//
}													//
//====================================================

//====================================================
//Вывод данных о влажности							//
//====================================================
void menu_2()										//
{                                    				//
  if (screen_update)								//
  {													//
  lcd.clear();										//
  lcd.setCursor(0,0);								//
  lcd.clear();										//
  lcd.print("2) HUMIDITY");							//
  lcd.setCursor(1,1);								//
  lcd.print("IN=");									//
  if (error_in)										//
  {lcd.print("ERR");}								//
  else{lcd.print(hum_in,0);}					    //
  lcd.setCursor(8,1);								//
  lcd.print("OUT=");								//
  if (error_out)									//
  {lcd.print("ERR");}								//
  else {lcd.print(hum_out,0);}					    //
  }													//
screen_update=false;								//
}													//
//====================================================

//====================================================
//Вывод крайних значений (не настройка)				//
//====================================================
void menu_3()                                       // 
{                                                   //
  if (screen_update)                                //
  {                                					//
  lcd.clear();                                		//
  lcd.setCursor(0,0);                               //
  lcd.clear();                                		//
  lcd.print("3) MIN    MAX"); 		                //
  lcd.setCursor(3,1);                               //
  lcd.print(temp_min,1);							//  
  lcd.setCursor(10,1);                              //
  lcd.print(temp_max,1);        					//
  screen_update=false;                              //
	}												//
}													//
//====================================================

//====================================================
//Информация о текущем режиме работы				//
//====================================================
void menu_4()                              			//
{                                                   //
if (screen_update)                              	//
                                					//
    lcd.clear();									//
   	lcd.setCursor(0,0);								//
    lcd.print("4) MODE ");                          //
    lcd.print(mode);                   	            //
    lcd.setCursor(0,1);                             //
    lcd.print("FUN ");                              //
  	if (mode == 1) lcd.write("ON"); 				//
   else lcd.write("OFF"); 							//
    lcd.setCursor(8,1);                             //
    lcd.print("GATE ");                             //
    if (mode != 3) lcd.write("N/A");                //
    else lcd.write("N/A");         					//
  screen_update=false;                              //
}                                					//
//====================================================

//====================================================
//Информация о продолжительности времени работы		//
//====================================================
void menu_5()										//
{													//
if (screen_update)									//
    {												//
        lcd.clear();								//
        lcd.setCursor(0,0);							//
        lcd.print("5) WORK TIME");					//
        lcd.setCursor(1,1);							//============
        time_period = millis()/1000;							//
        seconds=time_period-60*minutes-3600*hours-86400*days;	//
        while (seconds>=60)										//
        {											//============
            minutes++;								//
            seconds=seconds-60;						//
        }											//
        while (minutes>=60)							//
        {											//
            hours++;								//
            minutes=minutes-60;						//
        }											//
        while (hours>=24)							//
        {											//
            days++;									//
            hours=hours-24;							//
        }											//
    if (days<10){lcd.print(" ");}					//
    lcd.print(days);								//
    lcd.print("D ");								//
    if (hours<10){lcd.print(" ");}					//    
    lcd.print(hours);								//
    lcd.print("H ");								//
    if (minutes<10){lcd.print(" ");}				//
    lcd.print(minutes);								//
    lcd.print("M ");								//
    if (seconds<10){lcd.print(" ");}  				//
    lcd.print(seconds);								//
    lcd.print("S");									//
    }												//
screen_update=false;								//
}  													//
//====================================================

//====================================================
void set_1 ()										//
{													//
  temp_in_cal=set_up("1) SET CALIB T","IN",-10,10,0.1);//
  if (temp_in_cal!=EEPROM_float_read(2))			//
  EEPROM_float_write(2, temp_in_cal);		    	//
  temp_out_cal=set_up("1) SET CALIB T","OUT",-10,10,0.1);//
  if (temp_out_cal!=EEPROM_float_read(3))			//
  EEPROM_float_write(3, temp_out_cal);              //
  screen_update=true;								//
  update_buttons();									//
}													//
//====================================================

//====================================================
void set_2()										//
{													//
  hum_in_cal=set_up("2) SET CALIB H","IN",-30,30,1);//
  if (hum_in_cal!=EEPROM_float_read(4))				//
  EEPROM_float_write(4, hum_in_cal);				//
  hum_out_cal=set_up("2) SET CALIB H","OUT",-30,30,1);//
  if (hum_out_cal!=EEPROM_float_read(5))			//
  EEPROM_float_write(5, hum_out_cal);			    //
  screen_update=true;								//
  update_buttons();									//
}													//
//====================================================

//====================================================
//Установка лимитов									//
//====================================================
void set_3()										//
{													//
temp_min=set_up("3) SET LIMITS","MIN",-20,20,0.1);	//
if (temp_min>=temp_max)temp_max=temp_min+1;			//
temp_max=set_up("3) SET LIMITS","MAX",-20,20,0.1);	//
if (temp_max<=temp_min)temp_min=temp_max-1;			//
if (temp_min!=EEPROM_float_read(0))					//
EEPROM_float_write(0, temp_min);				    //	
if (temp_max!=EEPROM_float_read(1))					//
EEPROM_float_write(1, temp_max);					//
}													//
//====================================================

//====================================================
// Настройки серво									//
//====================================================
void set_4()										//
{													//
 // valum=open_servo;									//
 // set_up("4) SET SERVO","OP",0,180,5);				//
 // open_servo=valum;									//
 // EEPROM_float_write(6, open_servo);				//
 // valum=close_servo;								//
 // set_up("4) SET SERVO","CL",0,180,5);				//
 // close_servo=valum;								//
 // EEPROM_float_write(7, close_servo);				//
  screen_update=true;								//
  update_buttons();									//
}													//
//====================================================

//====================================================
void set_5()										// 
{													//
  	update_buttons();								//
	screen_update=false;							//
	while(!b_3.click_down)                         	// Печатаем пока не нажата b_3
    	{											//
        	lcd.clear();							//
      		lcd.print("5) SET SOUND");				//
      		lcd.setCursor(6,1);						//
  			if (sound_volume==0)					//
               {lcd.print("OFF");}					//
            if (sound_volume==1)					//
               {lcd.print("LOW");}					//
            if (sound_volume==2)					//
               {lcd.print("HIGH");}					//
           	while(!screen_update)					// Читаем кнопки пока не изменится значение
        	{										//
          	update_buttons();						//
            	if (b_2.click_down)					//
            	{									//
                sound_volume++;						//
                sound_volume=constrain(sound_volume,0,2);//
                screen_update=true;					//
            	}									//
            	if (b_1.click_down)					//
            {										//
                sound_volume--;						//
                sound_volume=constrain(sound_volume,0,2);//
                screen_update=true;					//
            }										//							
        if (b_3.click_down)							//
            {										//
          		screen_update=true;					//
            }										//
        }											//
        screen_update=false;						//
    }												//
screen_update=true;									//
}													//
//====================================================

//====================================================
// Печатная машинка									//
//====================================================
void type_mashine (String word)						//
{													//
  for (byte i=0; i<word.length();i++)				//
  {													//
    lcd.print(word[i]);								//
    play_tone(1,20,0);								//
    delay(random(0,1));								//
  }													//
}													//
//====================================================

//====================================================
// Стартовый экран
//====================================================
void info_screen()									//
{													//
  update_buttons();									//
  lcd.setCursor(0,0);								//
  lcd.print(" IN");									//
  lcd.write(7);										//
  if(temp_in>=9.50) lcd.print(" ");					//
  if(temp_in<9.50&&temp_in>=0.00) lcd.print("  ");	//
  if(temp_in<0.00&&temp_in>-9.50) lcd.print(" ");	//
  lcd.print(temp_in,0);								//
  lcd.write(3);										//
  lcd.print(" ");									//
  lcd.write(4);										//
  lcd.print(hum_in,0);								//
  lcd.print("%");									//
  lcd.print(" ");									//
  if (vent_anim)									//
  {													//
    lcd.write(1);									//
    lcd.write(2);									//
  }													//
  else 												//
  { 												//
   	if(digitalRead(pin_prop))						//
   	{												//
  		lcd.write(5);								//
  		lcd.write(6);  								//
  	}												//
    else {											//
           	lcd.write(1);							//
   			lcd.write(2);							//
         }											//
  }													//
  lcd.setCursor(0,1);								//
  lcd.print("OUT");									//
  lcd.write(7);										//
  if(temp_out>=9.50) lcd.print(" ");				//
  if(temp_out<9.50&&temp_out>=0.00) lcd.print("  ");//
  if(temp_out<0.00&&temp_out>-9.50) lcd.print(" ");	//
  lcd.print(temp_out,0);							//
  lcd.write(3);										//
  lcd.print(" ");									//
  lcd.write(4);										//
  lcd.print(hum_out,0);								//
  lcd.print("%");									//
  lcd.print(" ");									//
  if (manual_mode_on) lcd.print(" M");				//
  else lcd.print(" A");								//
}													//
//====================================================
//====================================================
// ВКЛ/ВЫКЛ Ручной режим							//
//====================================================
void manual_mode_yes_no()							//
{													//
  lcd.clear();										//
  if (manual_mode_on) lcd.print("OFF "); 			//
  else lcd.print("ON ");							//
  lcd.print("MANUAL MODE?");						//
  lcd.setCursor(1,1);								//
  lcd.print("NO(-)  YES(+)");						//
  update_buttons();									//
  while(!b_1.click_down&&!b_2.click_down&&!b_3.click_down)//
  update_buttons();									//
  if (b_2.click_down)								//
   {												//
      manual_mode_on=!manual_mode_on;				//
      p_mode=mode;  								//
    }												//
  screen_update = true;								//
}													//
													//
//====================================================
//предварительные настройки							//
//====================================================
void setup()                                    	//
{													//
pinMode(pin_lcd_led,OUTPUT);                        //
digitalWrite(pin_lcd_led,HIGH);						// ЗАКОМЕНТИТЬ
pinMode(RGB_R,OUTPUT);								// порты кнопок обозначаются в классе
pinMode(RGB_G,OUTPUT);								//
pinMode(RGB_B,OUTPUT);								//
lcd.begin(16, 2);                               	// включаем экран 
//lcd.backlight();									// РАСКОМЕНТИТЬ
//term_in.begin();									// РАСКОМЕНТИТЬ
//term_out.begin();									// РАСКОМЕНТИТЬ
  lcd.createChar(1, vent_1);						//
  lcd.createChar(2, vent_2);						//
  lcd.createChar(3, cels);							//
  lcd.createChar(4, drop);							//
  lcd.createChar(5, vent_3);						//
  lcd.createChar(6, vent_4);						//
  lcd.createChar(7,termo);							//
//====================================================
lcd.clear();										//	
lcd.blink();										//
type_mashine("VENTILATION ");						//просто фишечка на начальные экраны
lcd.print(Ver);  									//
delay(200);											//
//lcd.clear();                                 		//
//RGB_color("RED",0);								//
//type_mashine("SETTING PINMODE");					//
//delay(50);										//
pinMode(pin_termo_in, INPUT);                      	// ОБОЗНАЧАЕМ ПОРТЫ
pinMode(pin_termo_out, INPUT);						//
pinMode(pin_prop, OUTPUT);                        	//
pinMode(pin_piezo_low, OUTPUT);                     //
pinMode(pin_piezo_hi, OUTPUT);						//	  
//lcd.setCursor(14,1);								//
//RGB_color("GREEN",0);								//
//lcd.print("OK");									//
//delay(50);										//
//lcd.clear();										//
//RGB_color("RED",0);								//
//type_mashine("LOADING DATA");						//
//delay(50);										//
temp_min = EEPROM_float_read(0);					// Читаем из памяти	
temp_max = EEPROM_float_read(1);					//	
temp_in_cal = EEPROM_float_read(2);                 //
temp_out_cal = EEPROM_float_read(3);                //
hum_in_cal = EEPROM_float_read (4);                 //
hum_out_cal = EEPROM_float_read(5);                 //
//open_servo = EEPROM_float_read(6);                  //
//close_servo = EEPROM_float_read(7);                 //
//lcd.setCursor(14,1);								//
//lcd.print("OK");									//
//RGB_color("GREEN",0);								//
//delay(50);										//
//lcd.clear();										//
//RGB_color("RED",0);								//
//type_mashine("UPDATING"); 						//
//lcd.setCursor(0,1);								//
//type_mashine("TERMOSENSOR");						//
//delay(50);										//
term_update();                                  	// обновляем показания датчиков
//lcd.setCursor(14,1);								//
//lcd.print("OK");									//
//RGB_color("GREEN",0);								//
//delay(50);										//
//lcd.clear();										//
lcd.noBlink();										//
}													//
//====================================================
void loop() 		
//====================================================
{													//
update_buttons();									//
if(b_2.click_down&&!manual_mode_on)									// Если кнопка плюс нажата, то листаем вперед
	{												//
      menu++;										//
      screen_update=true;							//
      if (menu==6)									//
      {												//
          menu=0;									//
      }												//
	}												//
if(b_1.click_down&&!manual_mode_on)									// Если кнопка минус нажата, то листаем назад
	{												//
      menu--;										//
      screen_update=true;							//
      if (menu==-1)									//
      {												//
          menu=5;									//
      }												//
	}												//
  if (b_1.click_down&&manual_mode_on)
    digitalWrite(pin_prop,LOW);
    if (b_2.click_down&&manual_mode_on)
    digitalWrite(pin_prop,HIGH);
if(b_3.click_down)                              	// Если нажимаем кнопку 3 то идем в настройки 
{													//
  switch (menu)										// В зависимости от значения меню идем туда
	{												//
    case 0:manual_mode_yes_no();break;				//
    case 1:set_1();break;							//
    case 2:set_2();break;							//
    case 3:set_3();break;							//
    case 4:set_4();break;							//
    case 5:set_5();break;   						//
	}												//
}                                					//
if(millis()-time_last_term_update>=time_term_update)// Если пришло время обновлять датчики делаем это
	{												//
	    term_update();								//
    	screen_update=true;							//
	}												//
if(millis()-time_last_vent_anim>=time_vent_anim)	//
	{												//
  		vent_anim=!vent_anim;						//
  		time_last_vent_anim=millis();				//
	}												//
  if(!manual_mode_on)								//
  {													//
if(temp_in>=temp_max&&!error_in&&!error_out)		// Сравниваем температуры и ставим режим если нет ошибки
	{												//
    	if(temp_in>temp_out) mode=1;		        //
    	else mode=2;								//
    }												//
else												//
	{												//
        if(temp_in>temp_min) mode=2;	    		//
        else mode=3;								//
	}												//
  if(error_in||error_out)							//
  	{												//
    	mode=2;										// Если есть ошибка ставим 2 режим
    }												//
  }													//
  													//
switch (menu)										// В зависимости от значения меню идем туда
	{												//
  	case 0:info_screen();break;						//
    case 1:menu_1();break;							//
    case 2:menu_2();break;							//
    case 3:menu_3();break;							//
    case 4:menu_4();break;							//
    case 5:menu_5();break;							//
	}												//
if(p_mode!=mode)modes(mode);						//
if (vent_anim&&error_in||error_out)					//
  RGB_blink("RED",20);								//
  if (manual_mode_on)								//
  RGB_color("PINK",0);								//
  else{												//
  if(mode==1)										//
  RGB_color("BLUE",0);								//
  if (mode==2)										//
  RGB_color("YELLOW",0);							//
  if (mode==3)										//
    RGB_color("GREEN",0);							//
  }													//
}													//
//====================================================

ИЗМЕНЕНИЕ :

добавлены символы (градусник, капелька, вентелятор)

прикручен велсипед для кнопок 

добавлен цветной диод для обозначения режимов и ошибок

ручной режим прикручен через ардуинку

пока закоментирована серва, целесообразность установки рассматривается.

прикручена пещалка

прикручена красотень при загрузке

реализовано множество войдов

реалезовано сохранение параметров при сохранении.

все что закоменчено, раскоменчено с комментариями закоментить нужно чтобы вся эта шняга работала в онлайн симуляторе вот ссыль https://123d.circuits.io/circuits/1187491-termovent/

В будущем планируется сборка макета, дальнейшая оптимизация-эволюция кода.

 

 

 

бармолей
Offline
Зарегистрирован: 26.01.2016

если честно то я пока не понял функционального предназначения помещения.

вы пишите "что-то вроде кладовой в котором должна поддерживаться определенная температура в зимний период." Также смущает слово подвал.

если речь идет о подвале в котором храняться маркошка картошка  соленья варенья - то это одно дело! а если это полу жилое подвальное помещение (комната) вы там проводите время или там хряняться вещи это другое дело.

В любом случае вам человек правильно подсказал нужно идти по пути наименьшего сопротивления - тоесть использовать возможности естественого циркулирования воздуха по максимуму. (тем более если это подвальное помещение).

При этом забор свежего воздуха должен производиться из вашего подполья (1го этажа)  диаметр трубы около 150 -200 мм в зависимости от объема (помещения) о котором вы говорите , вход этой  трубы  в ваше помещение на высоте 0.3 -0.5 м от пола. Выхлоп отработанного воздуха должен производиться с верхней точки вашего помещения д=80 -120мм(в зависимости от V) и уходить на крышу вашего дома и там торчать на высоте не менне 0.5 метра от кровли. (получили полный функционал естественной вентиляции).

Вот теперь достаточно дополнить принудительную вентиляцию - если хотим теплый воздух зимой.

вентилятор и заслонку на отводящию трубу, заслонку на входящую.

при проектировании я бы больше делал упор на влажность а не на температуру.

сервоприводы и клапана я бы посоветовал BKA-150 или ченить от Belimo. не забывайте о безопасности линий если полезите в 220в. ставьте на линии вентеляторов АВДТ обязательно. но лучше с 220 не заморачиваться а через трансформатор брать 12 или 24 в.

если пол в вашей комнатке в подвале земляной обязательно положите гидро изоляцию, цементную подушку и пролейте наливным полом - так вы избавитесь от влажности на %30 сразу. стены заштукатурьте - и побелите это даст возможность им дышать от земли вокруг них тоесть брать естественное тепло земли.

Если это помещение для хранения овощей и фруктов, а из коментов в кодинге так и думаеться: тмакс=5 тмин=1 то тут задача немного другая - температура не должна опястится ниже 5гр. зимой при любых морозах для нашей полосы. (все зависит от типа овощей которые вы храните) и не привышать +15 самые жаркие периоды.  влажность держим в районе не превышающей 80 это средний вариант. С этими задачами выбираеться правильная глубина залегания подвала, его тепло изоляция и перечисленная выше вентеляция. При этом принудительная выполняет роль борьбы с влажносью в подвале. (это делать нужно обязательно иначе возникнит плесень).

В любом случае я бы лично не находился в таком помещении в момент просушки - лично у меня когда продуваеться подвал даже летом без бушлата лучше не находиться - ветрище бешеный можно сразу просквозиться. Вентеляторы я использую от телекомунникационного шкафа блок сразу на 6-ть штук.

 Не используя принудительную вентеляцию: имею февраль tул=-25 tпод=+5 ВЫТЯЖКА ЗАКРЫТА. весна tул=+15 tпод=+5~+7 ВСЕ вытяжки  ОТКРЫТы. лето tул=+35 макс tпод= +7~+12макс.  ВХОДная вытяжка ЗАКРЫТа НА 50%.

Режим просушки (принудительная вентиляция) если летом то tпод =+15 макс. Зимой только при условии что tподполья не ниже +5 - тоесть когда первый этаж отоплен. Продуваю пока влажность не понизится до 40% этого хватает на 3-4 месяца затем влажность доходит до нормы подполья тоесть до 80-90%.

 

 

 

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Всем привет, после того как проект пролежал ящике (руки не доходили) собрал макетик на плате, все работало ок, потом спаял между собой все детальки, тут начались проблемы, релюшка отказывалась работать от питания ЮСБ (точнее при включении релюшки выключался экран, видимо им на двоих не хватало мощности. Запитал от ибп, вроде релюха работает норм. Потом начались проблемы с кнопками. Они нажимаются через раз да и иногда просто срабатывает нажатие. Не могу понять в чем проблема. Возможно я зря их решил подтянуть от встроенного сопротивления, буду перепаивать на внешнее, да еще и конденсатор добавлю. Это все при том, что на макете все работало норм. Скетч через пол-года моего не быстрого изучения ардуино выглядет очень убого, но решил его не переписывать. т.к. он работает... в общем буду паять дальше, после чего отпишусь о результатах... 

бармолей
Offline
Зарегистрирован: 26.01.2016

Mr.Privet  )) привет!

Я сам не особо крут в контроллерах - но решил вспомнить молодость и повелся на вашу затею.

Скажу сразу у меня задача в принципе такая же как и у тебя толко я ее немного упростил и одновременно расширил и совмещал еще и с охранкой!

Скетч у тебя для - моего уровня меня устраивает я его во всяком случае читать могу и т.д.

Проблема скорее всего в сборке!

или

Попробуй отдельно (ну тут нужно все вспомнить поднять доки)! - запитать лсидишку от питалова - затем отдельно попинать микроконтроллер с релюхой на предмет вкл выкл. ит.д.

Мне кажеться просто мат часть подзабыл!

 

 

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Итак, проблема была кажется в питании, причем когда я запитывал нано от AC\DC диодной лампочки, после долгих страданий она благополучно сгорела, я взял уно, заменил кнопки на энкодер, питаться решил через USB, теперь все пашет нормально, осталось только проверить как поведет себя вся схема когда к релюшке подключить нагрузку. С энкодером мне даже больше понравилось, теперь все запихну в коробочку и тогда уже отпишусь. Из скетча выкинул пищалку и трехцветный диод, поскольку добавлял всю эту красоту больше для собственного развития чем для функциональности. скетчик выложу попозже.

Andrey12
Andrey12 аватар
Онлайн
Зарегистрирован: 26.12.2014

А конструктив заслонки какой? Ну которой сервомотор управляет? Фото есть? 

А то тоже буду делать вентиляцию, не хотелось бы наступать на грабли.

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

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

spa-sam
Offline
Зарегистрирован: 14.12.2012

Нужно разделить питание реле и МК (разные БП) т.к. возможны глюки на LCD и вплоть до зависания МК

angersos
angersos аватар
Offline
Зарегистрирован: 09.06.2016

Мне интересно, поможет это система вентиляции, в подвале всегда будет высокая влажность из за конденсата?

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

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

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

возможно и нужно, но пока все работает без глюков если будет глючить разнесу. А вообще сейчас переключился на другой проект, к этому вернусь позже, поскольку актуален он в основном зимой...

BogAD
Offline
Зарегистрирован: 30.01.2016

Пороект хороший но...

Моё мнение - не стоит игнорировать данные влажности улицы и подвала!

Есть такое понятие абсолютной влажности и относительной.

Абсолютная - количество воды в парообразном состоянии в объеме воздуха, гр/м3. Понятие "насыщенного пара" по другому завется - "точка росы", это когда влажности в воздухе столько, что влага из воздухе конденсируется на поверхностях. Значения давления насыщенного пара напрямую зависит от ТЕМПЕРАТУРЫ!

Относительная - процентное соотношение  замеряемой влажности от значения насыщенного пара при одной температуре, выражается в %.

Попробую пояснить. Приведу график давления насыщенного пара в зависимости от температуры.

что из это следует?

К примеру, на улице +25 гр.С, влажность 40%. При такой температуры давление насыщенного пара  - 31,67, соответственно, 40% от этого 12,66

Но... в подвале +15гр.С влажность 60%. При такой температуры давление насыщенного пара  - 17,04, соответственно, 60% от этого 10,53...

Т.е. если воздух с улицы попадет в подвал и остынет до +15, то влажность в подвале повысится, что не есть хорошо.

Другой пример

на улице +10 гр.С, влажность 80%. При такой температуры давление насыщенного пара  - 12,27, соответственно, 80% от этого 9,82

Но... в подвале +15гр.С влажность 60%. При такой температуры давление насыщенного пара  - 17,04, соответственно, 60% от этого 10,53...

Т.е. если воздух с улицы попадет в подвал инагреется до +15, то влажность в подвале понизится, что хорошо.

Что этим хочу сказать - надо не только температуры сравнивать, но и влажность. Имея сухой подвал со стабильной температурой, это мечта многих. А т.к. используются датчики DHТ22, то тут сам бог велел...

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

про влажность я тоже думал, она у меня только показывается. Хочу заметить что в данном помещении естественная вытяжка вполне хороша (из подвала труба идет на крышу) и отток воздуха хороший, проблема с повышенной влажностью в данном помещении не наблюдались. Я уже говорил что немного не точно назвал этот проект, это больше не вентеляция подвала а поддержание постоянной температуры в небольшом подвальном помещении. Из приведенных BogADом примеров следует что повышение влажности возможно при охлаждении теплого воздуха, забранного с улицы, но у меня по условиям если на улице теплее чем в подвале то воздух с улицы не сосется, соответственно он может быть только холоднее, и соответственно при нагревании влажность будет понижаться. Спасибо BogADу за разъяснения. Если проблемы с влажностью будет иметь место быть то буду его "контролить".  Пока пинаю тестя на установку "силовой" части, а "мозги" почти готовы...