Подробно о проекте рассказано в видео, ниже схемы подключения и исходный код для ардуино.
то как оно работает у меня:
Структурная схема или как все подключено, если собирать на модулях.
Принцип работы прост, измеряем температуру и относительную влажность воздуха в подвале и на улице (в приточной трубе вентиляции), из этих данных вычисляем абсолютную влажность и если в подвале влажность больше чем на улице, включаем вытяжной вентилятор. Для этого установлено два «датчика» с интерфейсом RS485, датчики являются исполнительными устройствами и по запросу передают в сеть данные с сенсора HDC1080 или управляют 9 ногой ардуино к которому подключен мосфет, который в свою очередь управляет вытяжным 12 вольтовым вентилятором. Отправляет команды на датчики ардуино леонардо, он же вычисляет абсолютную влажность из полученных с датчиков данных о температуре и влажности, дает команду на включение или выключение вентилятора, отображает информацию на LCD экране, передает телеметрию на радиомодуль HC12.
Уличный датчик, собран на плате с микроконтроллером, микросхемой MAX485 и стабилизатором питания AMS1117-05. имеет разъем с питанием и I2C шиной для подключения датчика температуры и влажности серии SHT, HDC или подобных, которые могут быть установлены на плате китайского модуля и две колодки, одну для подключения шины RS485 и питания, вторую, для подключения датчиков с однопроводной шиной. Изначально планировалось использовать датчик AM2301 или ему подобный и подключать его к той колодке, в итоге используется HDC1080 в I2C.
Датчик в подвале, имеет аналогичную разводку платы, только за место колодки для датчика AM2301, установлен мосфет и колодка для подключения 12 вольтового вентилятора.
на ардуино леонардо, установлен протошилд, на котором распаяны колодки для подключения RS485 и питания, китайский модуль на МАХ485, колодка для LCD1602 с I2C и радиомодуль HC12. для сети RS485 используется экранированная витая пара для локальной сети.
Для вычисления абсолютной влажности используется формула, истоки которой тут
Код:
код для леонардо с LCD1602 и HC12, как есть
//// код для леонардо с LCD1602 и HC12#include<EasyTransfer.h>#include<LiquidCrystal_I2C.h>#include<SoftEasyTransfer.h>#include<SoftwareSerial.h>#include<Wire.h>#defineDIR10#defineinterval1000// интервал для таймераSoftwareSerialRS485Serial(8,9);LiquidCrystal_I2Clcd(0x27,16,2);EasyTransferET;SoftEasyTransferETtx,ETrx;floatcellarAbsH,outAbsH,inAbsH;unsignedlongpreviousMillis=0;unsignedlongpreviousMillis1=0;intIDsend=0;booleanmosStat;structRECEIVE_DATA_RS485{intID;floatTemp;floatRH;booleanmos;};structSEND_DATA_RS485{intID;intcmd;};structSEND_DATA_HC12{floatoutTemp;// улицаfloatoutRH;floatinTemp;// гараж floatinRH;floatcellarTemp;// подвалfloatcellarRH;// пока всё};RECEIVE_DATA_RS485rxdata;SEND_DATA_RS485txdata;SEND_DATA_HC12HC12data;// вычисление абсалютной влажности из относительной и температуры.// https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/floatCalcAbsH(floatt,floath){doubletmp=pow(2.718281828,(17.67*t)/(t+243.5));return(6.112*tmp*h*2.1674)/(273.15+t);// Это граммы воды в дном кубометре воздуха.}voidsendCmdRS485(intid,intcmd){/// отправка команд в RS485digitalWrite(DIR,HIGH);delay(10);txdata.ID=id;txdata.cmd=cmd;ETtx.sendData();delay(10);digitalWrite(DIR,LOW);}voidsendLCD(){// мониторинг данных на LCD и Seriallcd.clear();lcd.setCursor(0,0);lcd.print("O:");lcd.print(HC12data.outTemp,0);lcd.print("C ");lcd.print(HC12data.outRH,0);lcd.print("% ");lcd.print(outAbsH,1);lcd.print("A");lcd.setCursor(0,1);lcd.print("I:");lcd.print(HC12data.cellarTemp,0);lcd.print("C ");lcd.print(HC12data.cellarRH,0);lcd.print("% ");lcd.print(cellarAbsH,1);lcd.print("A");lcd.setCursor(15,1);lcd.print(mosStat);Serial.print("O:");Serial.print(HC12data.outTemp);Serial.print("C ");Serial.print(HC12data.outRH);Serial.print("% ");Serial.print(outAbsH,1);Serial.println("A");Serial.print("I:");Serial.print(HC12data.cellarTemp);Serial.print("C ");Serial.print(HC12data.cellarRH);Serial.print("% ");Serial.print(cellarAbsH,1);Serial.print("A");Serial.println(mosStat);Serial.println();}voidsetup(){Serial.begin(9600);Serial1.begin(4800);RS485Serial.begin(9600);lcd.begin();lcd.backlight();lcd.clear();ETrx.begin(details(rxdata),&RS485Serial);ETtx.begin(details(txdata),&RS485Serial);ET.begin(details(HC12data),&Serial1);pinMode(DIR,OUTPUT);digitalWrite(DIR,LOW);// включаем прием }voidloop(){unsignedlongcurrentMillis=millis();// ЗАМЕНИТЬ НА ПРЕРЫВАНИЕ!if(currentMillis-previousMillis>interval){previousMillis=currentMillis;if(previousMillis>currentMillis)previousMillis=0;// защита от переполненияIDsend++;// переменаня счетчик if(IDsend>2)IDsend=0;// обнуление счетчика, 0 управление вентелемsendCmdRS485(IDsend,1);// спрашиваем с датчиков данныеsendLCD();if(IDsend==0){// если спросили данные со всех датчиков if(outAbsH+1<cellarAbsH){// если снаружи меньше, +1 для гистерезисаsendCmdRS485(1,2);///// /// включаем вентель}if(outAbsH>cellarAbsH){// если больше, выключаемsendCmdRS485(1,3);// ID 1, 2 вкл, 3 выкл }}}//////////////////////////////if(currentMillis-previousMillis1>30000){// отправляем данные через HC12previousMillis1=currentMillis;if(previousMillis1>currentMillis)previousMillis1=0;ET.sendData();}if(ETrx.receiveData()){switch(rxdata.ID){// смотрим откого данные, 1 подвал, 2 улицаcase1:cellarAbsH=CalcAbsH(rxdata.Temp,rxdata.RH);// вычесляем колво воды в подвалеHC12data.cellarTemp=rxdata.Temp;// для отправки на народмонHC12data.cellarRH=rxdata.RH;mosStat=rxdata.mos;break;case2:outAbsH=CalcAbsH(rxdata.Temp,rxdata.RH);// вычесляем колво воды на улицеHC12data.outTemp=rxdata.Temp;// для отправки на народмонHC12data.outRH=rxdata.RH;break;default:break;}}}
платка для HDC1080, уличный датчик, стоит в дырке у входа
/// платка для HDC1080, уличный датчик, стоит в дырке у входа#include<Wire.h>#include"ClosedCube_HDC1080.h"#include<EasyTransfer.h>ClosedCube_HDC1080hdc1080;#defineRS485ID2#defineDHT21_PIN5#defineMOS9// тут прозапас, можно для второго ветелятора использовать #defineDIR2EasyTransferETtx,ETrx;structSEND_DATA_STRUCTURE{// для отправки данныхintID;floatHDC1080_T;floatHDC1080_RH;booleanmos;};structRECEIVE_DATA_STRUCTURE{// для приема командintID;intcmd;};RECEIVE_DATA_STRUCTURErxdata;SEND_DATA_STRUCTUREtxdata;voidsetup(){// Serial1.begin(9600); Serial.begin(9600);hdc1080.begin(0x40);ETrx.begin(details(rxdata),&Serial);ETtx.begin(details(txdata),&Serial);pinMode(MOS,OUTPUT);pinMode(DIR,OUTPUT);digitalWrite(DIR,LOW);// включаем прием digitalWrite(MOS,LOW);}voidloop(){if(ETrx.receiveData()){// если чтото пришлоif(rxdata.ID==RS485ID){// проверяем для кого пришлоswitch(rxdata.cmd){case1:// вернуть структуру delay(1);txdata.ID=RS485ID;// откого данныеtxdata.HDC1080_T=hdc1080.readTemperature();// данные с датчикаtxdata.HDC1080_RH=hdc1080.readHumidity();txdata.mos=digitalRead(MOS);// пусть будетdigitalWrite(DIR,HIGH);// включаем передачуdelay(10);// небольшая задержка, иначе неуспеваетETtx.sendData();// отправляем delay(50);// небольшая задержка, иначе неуспевает digitalWrite(DIR,LOW);// включаем прием break;case2:// включить вентель digitalWrite(MOS,HIGH);break;case3:// выключить вентель digitalWrite(MOS,LOW);break;default:// если нечего не подошлоbreak;}}}}
платка с HDC1080 и мосфетом для управления вытяжкой в подвале
/// платка с HDC1080 и мосфетом для управления вытяжкой в подвале #include<Wire.h>#include"ClosedCube_HDC1080.h"#include<EasyTransfer.h>#defineRS485ID1#defineMOS9#defineDIR2EasyTransferETtx,ETrx;ClosedCube_HDC1080hdc1080;structSEND_DATA_STRUCTURE{intID;floatSHT20_T;floatSHT20_RH;booleanmos;};structRECEIVE_DATA_STRUCTURE{intID;intcmd;};RECEIVE_DATA_STRUCTURErxdata;SEND_DATA_STRUCTUREtxdata;voidsetup(){Serial.begin(9600);hdc1080.begin(0x40);ETrx.begin(details(rxdata),&Serial);ETtx.begin(details(txdata),&Serial);pinMode(MOS,OUTPUT);pinMode(DIR,OUTPUT);digitalWrite(DIR,LOW);// включаем прием digitalWrite(MOS,LOW);}voidloop(){if(ETrx.receiveData()){// если чтото пришлоif(rxdata.ID==RS485ID){switch(rxdata.cmd){case1:// вернуть структуру delay(1);txdata.ID=RS485ID;txdata.SHT20_T=hdc1080.readTemperature();txdata.SHT20_RH=hdc1080.readHumidity();txdata.mos=digitalRead(MOS);digitalWrite(DIR,HIGH);// включаем передачуdelay(1);// небольшая задержка, иначе неуспеваетETtx.sendData();// отправляем delay(50);// небольшая задержка, иначе неуспевает digitalWrite(DIR,LOW);// включаем прием break;case2:// включить вентель digitalWrite(MOS,HIGH);break;case3:// выключить вентель digitalWrite(MOS,LOW);break;default:// если нечего не подошлоbreak;}}}}
В основе всего функция для получения абсолютной влажности, ей передаем полученную доступным Вам способом температуру и влажность, обратно получаем данные которыми можно оперировать в зависимости от задачи.
вычисление абсолютной влажности из относительной и температуры.
// https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/floatCalcAbsH(floatt,floath){doubletmp=pow(2.718281828,(17.67*t)/(t+243.5));return(6.112*tmp*h*2.1674)/(273.15+t);// Это граммы воды в дном кубометре воздуха.}
А так выглядит код из которого убрано всё что относится к железу.
код
#defineFAN13// https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/floatCalcAbsH(floatt,floath){doubletmp=pow(2.718281828,(17.67*t)/(t+243.5));return(6.112*tmp*h*2.1674)/(273.15+t);// Это граммы воды в дном кубометре воздуха.}voidsetup(){Serial.begin(9600);pinMode(FAN,OUTPUT);}voidloop(){floatoutTemp=22.3;// предположим что это данные с датчиковfloatoutHum=55;// температуры и влажности floatinTemp=15.5;floatinHum=89;floatoutAbsH=CalcAbsH(outTemp,outHum);// вычисляем абсолютную влажностьfloatinAbsH=CalcAbsH(inTemp,inHum);// сверяем значение и управляем вентеляторомif(outAbsH+1<inAbsH){// если снаружи меньше, +1 для гистерезисаdigitalWrite(FAN,HIGH);/// включаем вентель}if(outAbsH>inAbsH){// если больше, выключаемdigitalWrite(FAN,LOW);}Serial.print("outAbsH:");// смотрим результатSerial.println(outAbsH);Serial.print("inAbsH:");Serial.println(inAbsH);Serial.print("FAN:");Serial.println(digitalRead(FAN));Serial.println();delay(5000);}
Далее к этому коду, за место данных которые указаны руками, можно подсунуть данные с датчиков температуры и влажности полученные любым доступным способом, по проводам, радиоканалу или использовать один микроконтроллер с несколькими подключенными датчиками.