В одном из предыдущих постов я рассказывал о проектах созданных пользователями программы FLProg. А сегодня я хочу рассказать о системе созданной мною самим.Серверная на станции где я работаю, как и положено находится в отдельном помещении. Для охлаждения серверов там установлено два кондиционера. К сожалению это обычные бытовые модели, так что регулярно то один, то другой находятся в ремонте. Руководство отдела, зная о моей работе над проектом FLProg, предложило создать систему мониторинга температуры в серверных шкафах, и управления работой их вентиляторов. Информация о текущей температуре должна отображаться на табло в помещении дежурных инженеров, и в случае повышения температуры свыше определенного порога выдавать звуковую сигнализацию. Я взялся за эту работу, и вот что получилось…
Ситуация осложнялась тем что мы находимся где то в 200 километров от ближайшей цивилизации, и собирать систему пришлось из тех запасов что у меня были с собой, плюс что то из старого хлама из кладовок. В наличии у меня были:
1. Arduino Nano
2. Датчик температуры DS18B20
3. Два датчика температуры и влажности DHT-22
4. Четырехстрочный дисплей на 20 символов в строке с платой I2C
Была разработана схема устройства: Принципиальная схема
Потом разработаны печатные платы:
Основная плата в программе Sprint-Layout_6
Кнопочная плата в программе Sprint-Layout_6
Утюга и специальной бумаги для технологии ЛУТ не нашлось так что пришлось вспоминать детство и рисовать платы ручками лаком, выпрошенным у уборщицы.




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


Затем была разработана окончательная прошивка для платы.
Проект в программе FLProg.
Скетчь
#include <Wire.h>
#include <OneWire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include "DHT.h"
LiquidCrystal_I2C _lcd1(0x3F, 20, 4);
int _dispTempLength1=0;
boolean _isNeedClearDisp1;
byte _d18x2x1Addr[8]={0x28, 0xFF, 0x11, 0x94, 0x3C, 0x4, 0x0, 0x48};
DHT _dht1(11, DHT22);
OneWire _ow10(10);
bool _gtv1 = 0;
bool _gtv3 = 0;
bool _gtv4 = 0;
bool _gtv5 = 0;
int _gtv2 = 23;
int _gtv6 = 27;
int _gtv7 = 30;
int _gtv8 = 35;
int _gtv9 = 0;
bool _gtv10 = 0;
String _gtv11 = "_C";
bool _gtv12 = 0;
bool _gtv13 = 0;
float _gtv14 = 0;
float _gtv15 = 0;
bool _gtv16 = 0;
int _gtv17 = 10;
bool _gtv18 = 0;
bool _gtv19 = 0;
bool _gtv20 = 0;
bool _gtv21 = 0;
bool _gtv22 = 0;
bool _gtv23 = 0;
bool _gtv24 = 0;
bool _gtv25 = 0;
bool _gtv26 = 0;
bool _gtv27 = 0;
bool _gtv28 = 0;
bool _trgrt9 = 0;
bool _trgrt9I = 0;
bool _bounse1S = 0;
bool _bounse1O = 0;
unsigned long _bounse1P = 0UL;
bool _trgrt4 = 0;
bool _trgrt4I = 0;
bool _bounse2S = 0;
bool _bounse2O = 0;
unsigned long _bounse2P = 0UL;
bool _trgrt5 = 0;
bool _trgrt5I = 0;
bool _bounse3S = 0;
bool _bounse3O = 0;
unsigned long _bounse3P = 0UL;
bool _trgrt8 = 0;
bool _trgrt8I = 0;
bool _count1I = 0;
int _count1P = 0;
bool _tim1I = 0;
bool _tim1O = 0;
unsigned long _tim1P = 0UL;
bool _trgrt1 = 0;
bool _trgrt1I = 0;
bool _trgrt2 = 0;
bool _trgrt2I = 0;
bool _trgrt3 = 0;
bool _trgrt3I = 0;
int _disp1oldLength = 0;
String _mux1;
int _disp3oldLength = 0;
int _disp4oldLength = 0;
int _disp5oldLength = 0;
int _disp6oldLength = 0;
int _disp7oldLength = 0;
String _swi2;
String _swi3;
int _disp2oldLength = 0;
String _mux2;
int _disp8oldLength = 0;
int _disp9oldLength = 0;
int _disp10oldLength = 0;
int _disp11oldLength = 0;
int _disp12oldLength = 0;
String _swi4;
String _swi5;
bool _trgrt10 = 0;
bool _trgrt10I = 0;
bool _trgrt11 = 0;
bool _trgrt11I = 0;
bool _trgrt12 = 0;
bool _trgrt12I = 0;
bool _trgrt13 = 0;
bool _trgrt13I = 0;
unsigned long _d18x2x1Tti = 0UL;
float _d18x2x1O = 0.00;
unsigned long _dht1Tti = 0UL;
float _dht1t = 0.00;
float _dht1h = 0.00;
bool _trgr1 = 0;
bool _trgr2 = 0;
bool _trgrt6 = 0;
bool _trgrt6I = 0;
bool _trgr3 = 0;
bool _trgr4 = 0;
bool _trgrt7 = 0;
bool _trgrt7I = 0;
bool _trgr5 = 0;
bool _pzs1OES = 0;
int _pzs1OFS = 0;
bool _gen1I = 0;
bool _gen1O = 0;
unsigned long _gen1P = 0UL;
int _swi1;
bool _D1B1 = 0;
bool _gen2I = 0;
bool _gen2O = 0;
unsigned long _gen2P = 0UL;
String _swi6;
int _disp13oldLength = 0;
bool _SEEPR1OSN = 0;
bool _SEEPR2OSN = 0;
bool _SEEPR3OSN = 0;
bool _SEEPR4OSN = 0;
void setup()
{
Wire.begin();
pinMode(12, OUTPUT);
pinMode(4, OUTPUT);
pinMode(3, OUTPUT);
pinMode(2, OUTPUT);
_lcd1.init();
_lcd1.noBacklight();
_dht1.begin();
}
void loop()
{if(_isTimer(_dht1Tti, 6000)) {
_dht1Tti = millis();
float tempDht11;
tempDht11 = _dht1.readTemperature();
if (!(isnan(tempDht11))){_dht1t=tempDht11; }
}if (_isNeedClearDisp1) {_lcd1.clear(); _isNeedClearDisp1= 0;}
if (1) { if (_trgrt9I) { _trgrt9 = 0;} else {_trgrt9 = 1; _trgrt9I = 1;} } else {_trgrt9 = 0; _trgrt9I = 0;};
if (_trgrt9) {
_gtv6 = (EEPROMReadInt(0));
}
if (_trgrt9) {
_gtv7 = (EEPROMReadInt(2));
}
if (_trgrt9) {
_gtv2 = (EEPROMReadInt(4));
}
if (_trgrt9) {
_gtv8 = (EEPROMReadInt(6));
}
bool _bounceTmp1 = ! (( (analogRead (3))) > (500));
if (_bounse1S)
{
if (millis() >= (_bounse1P + 40))
{_bounse1O= _bounceTmp1; _bounse1S=0;}
}
else
{
if (_bounceTmp1 != _bounse1O )
{_bounse1S=1; _bounse1P = millis();}
}
if (_bounse1O) { if (_trgrt4I) { _trgrt4 = 0;} else {_trgrt4 = 1; _trgrt4I = 1;} } else {_trgrt4 = 0; _trgrt4I = 0;};
_gtv3 = _bounse1O;
_gtv12 = (_trgrt4) && (!(_gtv20)) ;
bool _bounceTmp2 = ! (( (analogRead (2))) > (500));
if (_bounse2S)
{
if (millis() >= (_bounse2P + 40))
{_bounse2O= _bounceTmp2; _bounse2S=0;}
}
else
{
if (_bounceTmp2 != _bounse2O )
{_bounse2S=1; _bounse2P = millis();}
}
if (_bounse2O) { if (_trgrt5I) { _trgrt5 = 0;} else {_trgrt5 = 1; _trgrt5I = 1;} } else {_trgrt5 = 0; _trgrt5I = 0;};
_gtv4 = _bounse2O;
_gtv13 = (_trgrt5) && (!(_gtv20)) ;
bool _bounceTmp3 = ! (( (analogRead (1))) > (500));
if (_bounse3S)
{
if (millis() >= (_bounse3P + 40))
{_bounse3O= _bounceTmp3; _bounse3S=0;}
}
else
{
if (_bounceTmp3 != _bounse3O )
{_bounse3S=1; _bounse3P = millis();}
}
if (_bounse3O) { if (_trgrt8I) { _trgrt8 = 0;} else {_trgrt8 = 1; _trgrt8I = 1;} } else {_trgrt8 = 0; _trgrt8I = 0;};
_gtv5 = _bounse3O;
_gtv19 = (_trgrt8) && (!(_gtv20)) ;
if (_gtv19)
{
if (! _count1I)
{
_count1P = _count1P+1;
_count1I = 1;
}
}
else
{
_count1I=0;
}
if (_count1P < 0 ) _count1P = 0;
if ( (_gtv1) || (_gtv10) ) _count1P = 0;
if (_gtv5) { if (_trgrt1I) { _trgrt1 = 0;} else {_trgrt1 = 1; _trgrt1I = 1;} } else {_trgrt1 = 0; _trgrt1I = 0;};
if (_gtv3) { if (_trgrt2I) { _trgrt2 = 0;} else {_trgrt2 = 1; _trgrt2I = 1;} } else {_trgrt2 = 0; _trgrt2I = 0;};
if (_gtv4) { if (_trgrt3I) { _trgrt3 = 0;} else {_trgrt3 = 1; _trgrt3I = 1;} } else {_trgrt3 = 0; _trgrt3I = 0;};
if ( ((_count1P) > (0)) && ((! (_trgrt1) || (_trgrt2) || (_trgrt3) )) )
{
if (_tim1I)
{
if ( _isTimer(_tim1P, 60000)) _tim1O = 1;
}
else
{
_tim1I = 1;
_tim1P = millis();
}
}
else
{
_tim1O = 0;
_tim1I = 0;
}
_gtv9 = _count1P;
_gtv1 = _count1P >= 5;
_gtv10 = _tim1O;
if((_gtv9) == 0) {_mux1 = String("Terst");}
if((_gtv9) == 1) {_mux1 = String("Value Off");}
if((_gtv9) == 2) {_mux1 = String("Value 1 On");}
if((_gtv9) == 3) {_mux1 = String("Value 2 On");}
if((_gtv9) == 4) {_mux1 = String("Value Alarm");}
if ((_gtv9) > (0)) {
_dispTempLength1 = ((_mux1)).length();
if (_disp1oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp1oldLength = _dispTempLength1;
_lcd1.setCursor(int((20 - _dispTempLength1)/2), 0);
_lcd1.print((_mux1));
} else {
if (_disp1oldLength > 0) {_isNeedClearDisp1 = 1; _disp1oldLength = 0;}
}
if ((0) == (_gtv9)) {
_dispTempLength1 = (String("SU T:")).length();
if (_disp3oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp3oldLength = _dispTempLength1;
_lcd1.setCursor(0, 0);
_lcd1.print(String("SU T:"));
} else {
if (_disp3oldLength > 0) {_isNeedClearDisp1 = 1; _disp3oldLength = 0;}
}
if ((0) == (_gtv9)) {
_dispTempLength1 = ((( _floatToStringWitRaz(_gtv14,1)))).length();
if (_disp4oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp4oldLength = _dispTempLength1;
_lcd1.setCursor(5, 0);
_lcd1.print((( _floatToStringWitRaz(_gtv14,1))));
} else {
if (_disp4oldLength > 0) {_isNeedClearDisp1 = 1; _disp4oldLength = 0;}
}
if ((0) == (_gtv9)) {
_dispTempLength1 = (String("C")).length();
if (_disp5oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp5oldLength = _dispTempLength1;
_lcd1.setCursor(9, 0);
_lcd1.print(String("C"));
} else {
if (_disp5oldLength > 0) {_isNeedClearDisp1 = 1; _disp5oldLength = 0;}
}
if(_gtv21)
{_swi2=String("*");}
else
{_swi2=String("-");}
if ((0) == (_gtv9)) {
_dispTempLength1 = ((_swi2)).length();
if (_disp6oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp6oldLength = _dispTempLength1;
_lcd1.setCursor(11, 0);
_lcd1.print((_swi2));
} else {
if (_disp6oldLength > 0) {_isNeedClearDisp1 = 1; _disp6oldLength = 0;}
}
if(_gtv22)
{_swi3=String("*");}
else
{_swi3=String("-");}
if ((0) == (_gtv9)) {
_dispTempLength1 = ((_swi3)).length();
if (_disp7oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp7oldLength = _dispTempLength1;
_lcd1.setCursor(13, 0);
_lcd1.print((_swi3));
} else {
if (_disp7oldLength > 0) {_isNeedClearDisp1 = 1; _disp7oldLength = 0;}
}
if((_gtv9) == 0) {_mux2 = String("test");}
if((_gtv9) == 1) {_mux2 = (((String(_gtv2))) + (_gtv11));}
if((_gtv9) == 2) {_mux2 = (((String(_gtv6))) + (_gtv11));}
if((_gtv9) == 3) {_mux2 = (((String(_gtv7))) + (_gtv11));}
if((_gtv9) == 4) {_mux2 = (((String(_gtv8))) + (_gtv11));}
if ((_gtv9) > (0)) {
_dispTempLength1 = ((_mux2)).length();
if (_disp2oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp2oldLength = _dispTempLength1;
_lcd1.setCursor(int((20 - _dispTempLength1)/2), 1);
_lcd1.print((_mux2));
} else {
if (_disp2oldLength > 0) {_isNeedClearDisp1 = 1; _disp2oldLength = 0;}
}
if ((0) == (_gtv9)) {
_dispTempLength1 = (String("CU T:")).length();
if (_disp8oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp8oldLength = _dispTempLength1;
_lcd1.setCursor(0, 1);
_lcd1.print(String("CU T:"));
} else {
if (_disp8oldLength > 0) {_isNeedClearDisp1 = 1; _disp8oldLength = 0;}
}
if ((0) == (_gtv9)) {
_dispTempLength1 = ((( _floatToStringWitRaz(_gtv15,1)))).length();
if (_disp9oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp9oldLength = _dispTempLength1;
_lcd1.setCursor(5, 1);
_lcd1.print((( _floatToStringWitRaz(_gtv15,1))));
} else {
if (_disp9oldLength > 0) {_isNeedClearDisp1 = 1; _disp9oldLength = 0;}
}
if ((0) == (_gtv9)) {
_dispTempLength1 = (String("C")).length();
if (_disp10oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp10oldLength = _dispTempLength1;
_lcd1.setCursor(9, 1);
_lcd1.print(String("C"));
} else {
if (_disp10oldLength > 0) {_isNeedClearDisp1 = 1; _disp10oldLength = 0;}
}
if(_gtv23)
{_swi4=String("*");}
else
{_swi4=String("-");}
if ((0) == (_gtv9)) {
_dispTempLength1 = ((_swi4)).length();
if (_disp11oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp11oldLength = _dispTempLength1;
_lcd1.setCursor(11, 1);
_lcd1.print((_swi4));
} else {
if (_disp11oldLength > 0) {_isNeedClearDisp1 = 1; _disp11oldLength = 0;}
}
if(_gtv24)
{_swi5=String("*");}
else
{_swi5=String("-");}
if ((0) == (_gtv9)) {
_dispTempLength1 = ((_swi5)).length();
if (_disp12oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp12oldLength = _dispTempLength1;
_lcd1.setCursor(13, 1);
_lcd1.print((_swi5));
} else {
if (_disp12oldLength > 0) {_isNeedClearDisp1 = 1; _disp12oldLength = 0;}
}
if ( (_gtv5) && (_gtv3) && (_gtv4) ) { if (_trgrt10I) { _trgrt10 = 0;} else {_trgrt10 = 1; _trgrt10I = 1;} } else {_trgrt10 = 0; _trgrt10I = 0;};
if ( (_gtv12) && ((_gtv9) == (1)) ) {
_gtv2 = (_gtv2)+(1);
}
if ( ((_gtv9) == (1)) && (_gtv13) ) {
_gtv2 = (_gtv2)-(1);
}
if (_trgrt10) {
_gtv2 = 25;
}
_gtv25 = ( (_gtv12) && ((_gtv9) == (1)) ) || ( ((_gtv9) == (1)) && (_gtv13) ) || (_trgrt10) ;
if ( (_gtv5) && (_gtv3) && (_gtv4) ) { if (_trgrt11I) { _trgrt11 = 0;} else {_trgrt11 = 1; _trgrt11I = 1;} } else {_trgrt11 = 0; _trgrt11I = 0;};
if ( (_gtv12) && ((_gtv9) == (2)) ) {
_gtv6 = (_gtv6)+(1);
}
if ( ((_gtv9) == (2)) && (_gtv13) ) {
_gtv6 = (_gtv6)-(1);
}
if (_trgrt11) {
_gtv6 = 27;
}
_gtv26 = ( (_gtv12) && ((_gtv9) == (2)) ) || ( ((_gtv9) == (2)) && (_gtv13) ) || (_trgrt11) ;
if ( (_gtv5) && (_gtv3) && (_gtv4) ) { if (_trgrt12I) { _trgrt12 = 0;} else {_trgrt12 = 1; _trgrt12I = 1;} } else {_trgrt12 = 0; _trgrt12I = 0;};
if ( (_gtv12) && ((_gtv9) == (3)) ) {
_gtv7 = (_gtv7)+(1);
}
if ( ((_gtv9) == (3)) && (_gtv13) ) {
_gtv7 = (_gtv7)-(1);
}
if (_trgrt12) {
_gtv7 = 30;
}
_gtv27 = ( (_gtv12) && ((_gtv9) == (3)) ) || ( ((_gtv9) == (3)) && (_gtv13) ) || (_trgrt12) ;
if ( (_gtv5) && (_gtv3) && (_gtv4) ) { if (_trgrt13I) { _trgrt13 = 0;} else {_trgrt13 = 1; _trgrt13I = 1;} } else {_trgrt13 = 0; _trgrt13I = 0;};
if ( (_gtv12) && ((_gtv9) == (4)) ) {
_gtv8 = (_gtv8)+(1);
}
if ( ((_gtv9) == (4)) && (_gtv13) ) {
_gtv8 = (_gtv8)-(1);
}
if (_trgrt13) {
_gtv8 = 35;
}
_gtv28 = ( (_gtv12) && ((_gtv9) == (4)) ) || ( ((_gtv9) == (4)) && (_gtv13) ) || (_trgrt13) ;
if(_isTimer(_d18x2x1Tti, 5000)) {
_d18x2x1Tti = millis();
_d18x2x1O= _readDS18_ow10(_d18x2x1Addr, 0);}
_gtv14 = (_d18x2x1O);
_gtv15 = _dht1t;
if(((int((_gtv14)*(_gtv17)))) < ((_gtv2)*(_gtv17))) _trgr1 = 0;
if(((int((_gtv14)*(_gtv17)))) > ((_gtv6)*(_gtv17))) _trgr1 = 1;
if(((int((_gtv14)*(_gtv17)))) < ((_gtv2)*(_gtv17))) _trgr2 = 0;
if(((int((_gtv14)*(_gtv17)))) > ((_gtv7)*(_gtv17))) _trgr2 = 1;
if (((int((_gtv14)*(_gtv17)))) > ((_gtv17)*(_gtv8))) { if (_trgrt6I) { _trgrt6 = 0;} else {_trgrt6 = 1; _trgrt6I = 1;} } else {_trgrt6 = 0; _trgrt6I = 0;};
if(((int((_gtv17)*(_gtv15)))) < ((_gtv2)*(_gtv17))) _trgr3 = 0;
if(((int((_gtv17)*(_gtv15)))) > ((_gtv6)*(_gtv17))) _trgr3 = 1;
if(((int((_gtv17)*(_gtv15)))) < ((_gtv2)*(_gtv17))) _trgr4 = 0;
if(((int((_gtv17)*(_gtv15)))) > ((_gtv7)*(_gtv17))) _trgr4 = 1;
if (((int((_gtv17)*(_gtv15)))) > ((_gtv17)*(_gtv8))) { if (_trgrt7I) { _trgrt7 = 0;} else {_trgrt7 = 1; _trgrt7I = 1;} } else {_trgrt7 = 0; _trgrt7I = 0;};
_gtv16 = _trgrt6;
_gtv21 = _trgr1;
digitalWrite(12, _trgr1);
digitalWrite(3, _trgr3);
_gtv18 = _trgrt7;
_gtv23 = _trgr3;
_gtv22 = _trgr2;
digitalWrite(4, _trgr2);
digitalWrite(2, _trgr4);
_gtv24 = _trgr4;
if( (_gtv5) || (_gtv3) || (_gtv4) ) _trgr5 = 0;
if( (_gtv16) || (_gtv18) ) _trgr5 = 1;
if (_trgr5)
{
if (! _gen1I)
{
_gen1I = 1;
_gen1O = 1;
_gen1P = millis();
}
}
else
{
_gen1I = 0 ;
_gen1O= 0;
}
if (_gen1I )
{
if ( _isTimer ( _gen1P , 500 ))
{
_gen1P = millis();
_gen1O = ! _gen1O;
}
}
if( (!(_trgr5)) || (_gen1O) ) {if(! _D1B1){_lcd1.backlight(); _D1B1=1; }} else {if(_D1B1){_lcd1.noBacklight(); _D1B1=0; }}
if(_gen1O)
{_swi1=3000;}
else
{_swi1=2500;}
if(_trgr5)
{if((!_pzs1OES) || (_swi1 != _pzs1OFS)){ tone(13, (_swi1)); _pzs1OES =1;_pzs1OFS = _swi1;}} else {if(_pzs1OES){noTone(13); _pzs1OES =0; }}
_gtv20 = _trgr5;
if (1)
{
if (! _gen2I)
{
_gen2I = 1;
_gen2O = 1;
_gen2P = millis();
}
}
else
{
_gen2I = 0 ;
_gen2O= 0;
}
if (_gen2I )
{
if ( _isTimer ( _gen2P , 1000 ))
{
_gen2P = millis();
_gen2O = ! _gen2O;
}
}
if(_gen2O)
{_swi6=String("----");}
else
{_swi6=String("****");}
if (1) {
_dispTempLength1 = ((_swi6)).length();
if (_disp13oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp13oldLength = _dispTempLength1;
_lcd1.setCursor(int((20 - _dispTempLength1)/2), 2);
_lcd1.print((_swi6));
} else {
if (_disp13oldLength > 0) {_isNeedClearDisp1 = 1; _disp13oldLength = 0;}
}
if(_gtv26){ if(!_SEEPR1OSN){ EEPROMWriteInt(0, _gtv6); _SEEPR1OSN=1;} }else{ if(_SEEPR1OSN){_SEEPR1OSN=0;}}
if(_gtv27){ if(!_SEEPR2OSN){ EEPROMWriteInt(2, _gtv7); _SEEPR2OSN=1;} }else{ if(_SEEPR2OSN){_SEEPR2OSN=0;}}
if(_gtv25){ if(!_SEEPR3OSN){ EEPROMWriteInt(4, _gtv2); _SEEPR3OSN=1;} }else{ if(_SEEPR3OSN){_SEEPR3OSN=0;}}
if(_gtv28){ if(!_SEEPR4OSN){ EEPROMWriteInt(6, _gtv8); _SEEPR4OSN=1;} }else{ if(_SEEPR4OSN){_SEEPR4OSN=0;}}
}
bool _isTimer(unsigned long startTime, unsigned long period )
{
unsigned long endTime;
endTime = startTime+period;
return (millis() >= endTime);
}
String _floatToStringWitRaz(float value, int raz)
{
float tv;
int ti = int(value);
String ts = String(ti);
if (raz == 0) {
return ts;
}
ts += ".";
float tf = abs(value - ti);
for (int i = 1; i <= raz; i++ )
{
tv = tf * 10;
ti = int(tv);
ts += String(ti);
tf = (tv - ti);
}
return ts;
}
float _convertDS18x2xData(byte type_s, byte data[12])
{
int16_t raw = (data[1] << 8) | data[0];
if (type_s)
{
raw = raw << 3;
if (data[7] == 0x10) { raw = (raw & 0xFFF0) + 12 - data[6]; }
}
else
{
byte cfg = (data[4] & 0x60);
if (cfg == 0x00) raw = raw & ~7; else if (cfg == 0x20) raw = raw & ~3; else if (cfg == 0x40) raw = raw & ~1;
}
return (float)raw / 16.0;
}
float _readDS18_ow10(byte addr[8], byte type_s)
{ byte data[12];
byte i;
_ow10.reset();
_ow10.select(addr);
_ow10.write(0xBE);
for ( i = 0; i < 9; i++) {
data[i] = _ow10.read();}
_ow10.reset();
_ow10.select(addr);
_ow10.write(0x44, 1);
return _convertDS18x2xData(type_s, data);}int EEPROMReadInt(int p_address)
{
byte lowByte = EEPROM.read(p_address);
byte highByte = EEPROM.read(p_address + 1);
return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
}
void EEPROMWriteInt(int p_address, int p_value)
{
byte lowByte = ((p_value >> 0) & 0xFF);
byte highByte = ((p_value >> 8) & 0xFF);
EEPROM.write(p_address, lowByte);
EEPROM.write(p_address + 1, highByte);
}
Как работает система.
При подаче питания на контроллер, из EEPROM вычитываются уставки порогов включения ступеней вентиляторов шкафов, и аварийной сигнализации.
Каждые 5 секунд считываются данные из датчиков и отображаются на дисплее. При превышении температуры в шкафу первого порога включается первый вентилятор, второго порога – второй, а при превышении порога аварийной температуры включается двухтональная звуковая сигнализация и начинает моргать подсветка дисплея. Квитирование аварии происходит при нажатии любой из кнопок. При падении температуры ниже уставки отключения вентиляторов оба вентилятора останавливаются.
При каждом нажати�� кнопки “Меню” на экран дисплея выводится последовательно все уставки. Каждую уставку можно изменить кнопками “Прибавить” и “Убавить”. При этом новое значение уставки сразу записывается в EEPROM.
Если в течение 1 минуты не производить никаких действий с кнопками происходит переход на основной экран индикации температуры
При нажатии сразу трех кнопок все уставки сбрасываются на начальные значения, записанные в программе. Это необходимо при первом запуске контроллера, когда в EEPROM находятся непредсказуемые значения. У меня, например, аварийная температура оказалась 387 градусов, и я бы очень устал ее сваливать до 35 градусов нажатиями на кнопку “Убавить”.
Запуск системы на столе и прогрев датчиков феном показал работоспособность программы.

Были установлены датчики и проложены кабеля до шкафов




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

Прошу не обращать внимание на оригинальное крепление дисплея, но я посчитал слишком жирно ставить четырехстрочный дисплей на постоянную основу, и на следующей вахте заменю его на двухстрочный.
На текущий момент система работает третью неделю без зависанй и отказов 24/7.
Теперь немного гик-порно. Я не удержался и распотрошил сгоревший датчик DHT-22. Внутри он оказался очень умным.


