Осушитель подвала ver.2.0 stm32, доступ через сеть
Потребовалось мне еще один осушитель, для предполья бани. Решил сделать версию с удаленным управлением.
Вся информация размещена на гитхабе https://github.com/pav2000/Dehumidifier-2.0
Короткий ролик поясняющий работу и конструкцию. https://youtu.be/ywdXSmak6OI
Данный проект - дальнейшее развитие проекта: http://arduino.ru/forum/proekty/kontrol-vlazhnosti-podvala-arduino-pro-mini
Принцип работы остался прежним - Идея контроля влажности подвала была подсмотрена на http://geektimes.ru (http://geektimes.ru/post/255298/) Вся идея состоит в том чтобы измерить температуру и относительную влажность в подвале и на улице, на основании температуры и относительной влажности рассчитать абсолютную влажность и принять решение о включении вытяжного вентилятора в подвале. Теория для расчета изложена здесь - https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/
Аппаратная часть полностью переделана. Теперь используется STM32 и сетевой чип wiznet w5500. На самом чипе поднят простейший веб сервер, через который проводится настройка устройства и его контроль. Разрабатывая этот блок я планировал сделать универсальный модуль для домашней автоматизации, и заложил избыточность в схеме для реализации будущих устройств. Сам блок реализован на плате maple mini (STM32F103CBT6).
Для упрощения программирования используется free RTOS 8 немного заточенная под себя
Схема платы:

На схеме (и плате) разведены следующие узлы:
-
кварц для часов реального времени stm32
-
батарейка для часов
-
два порта i2c для подключения внешних устройств
-
флеш память spi (можно установить до 32 мбит)
-
разъем sd карты (режим spi)
-
дисплей 2.8 дюйма на контроллере ili9341 подключение spi
-
модуль питания 220->5в
-
два ssr реле со схемами гашения помех и варисторами
-
датчик переменного тока (0-50A) для измерения токов нагрузки 220
-
разъем для подключения отладчика
-
разъем для подключения nrf24f01 - для работы с беспроводными датчиками
-
два светодида на отдельных gpio
-
мост i2c oneWire со схемой защиты для подключения OneWire датчиков
-
пищалка
-
разъем расширения (uart+gpio)
Под этот проект была разработана и изготовлена печатная плата. Плата предназначена для установки в корпус G212C (https://www.chipdip.ru/product/g212c)

Сборка.
Косяки разводки:
-
шелкография - на разъеме отладчика SWD перепутаны надписи DIO CLK
-
шелкография - на разъеме 220 и реле перепутаны надписи ssr1 ssr2
-
разводка - надо бросить сигнальный провод (почему то не развелся) от датчика тока до maple mini
-
дополнительно было распаяно (частично учтено на схеме) RC фильтр на датчик тока, конденсатор на ножку питания, резистор 6.8к между землей и DO usb (без него и без подключения к usb МК переходил в режим загрузчика)

Работа.
Первоначально планировалось использовать датчики температуры и влажности AHT10 на шине i2c. Два датчика отказывались работfь на одной шине (хотя были разнесены по разным адресам), т.е. работают корректно 20-30 минут а потом отваливаются от шины и шину клинит, было лень разбираться. Один датчик работает хорошо. При переходе на программный i2c (ногодрыг) оба датчика нормально заработали.
НО при увеличении длины провода более 1.5 метра на программном i2c датчики отказались работать (в принципе это ожидаемо). По этому принято решение использовать проверенные временем DHT22 (шина типа 1-wire). Разъем i2c имеет 4 контакта (питание SDA SCL) и был перепрограммирован для подключения двух датчиков DHT22. Длина проводов: внутренний датчик 3 метра, внешний 8 метров, все работает с разумным количеством ошибок.
Датчик тока ACS758 (диапазон 50A - применен для универсальности) позволяет измерять ток потребления устройством (есть задумка в его использовании в других устройствах). При этом при работающем вентиляторе вытяжки можно измерить общий ток и сделать вывод об работоспособности вентилятора. Обычно вентиляторе есть термо предохранитель, который срабатывает при их отказе. Так можно следить за работой вентилятора через инет. Единственная проблема, что устройство потребляет достаточно мало и много шумов, но эту проблему удалось побороть усреднением и дополнительной обработкой данных.
Web морда устройства:
Графики используют google chart api, по этому без инета они работать не будут.

Установка на объекте.

Исходники почти 150к по просьбе модератора напрягся и вставил сюда -)):
Podval20.ino
016 | #include <MapleFreeRTOS821.h> |
019 | #include "Adafruit_GFX_AS.h" |
020 | #include "Adafruit_ILI9341_STM.h" // |
021 | #include <Ethernet_STM.h> // Сеть прицецеплена на 1 spi |
023 | #include "utility/w5100.h" |
024 | #include <libmaple/iwdg.h> |
027 | #define DEBUG // Выводить отладочную информацию в консоль |
029 | #define VERSION 44 // Версия программы |
033 | #include "webserver.h" |
037 | #define fTFT_180 0 // Флаг поворота дисплея на 180 градусов |
038 | #define fTFT_OFF 1 // Флаг выключения дисплея 1 выключен |
039 | #define fDHCP 2 // Флаг использования DHCP |
040 | #define fNTP 3 // Флаг обновления времени по NTP |
041 | #define fUPDATE 4 // Флаг обновления страницы каждые 60 сек |
042 | #define fBEEP 5 // Флаг разрешения пищалки |
043 | #define fTEST 6 // Флаг ежедневного тестирования и определениея "0" датчика тока |
044 | #define fFULL_WEB 7 // Флаг показа настроек |
045 | #define fAUTO 8 // Флаг автокалибровки датчика ACS758 |
046 | static struct type_setting_eeprom |
048 | char name[24]= "Dehumidifier pav2000" ; |
049 | TYPE_MODE mode = BLOCK_OFF; |
050 | uint16_t dH_min,T_min; |
056 | unsigned long hour_unit; |
057 | unsigned long hour_motor; |
058 | unsigned long hour_heat; |
060 | uint16_t CurMax=2000; |
061 | uint16_t constACS758=2519; |
071 | static struct type_sensors |
075 | uint8_t inErr,outErr; |
076 | uint32_t numErrIn=0,numErrOut=0; |
078 | int16_t av_tOut=-5000,av_tIn=-5000; |
079 | int16_t av_relHOut=5555,av_relHIn=5555; |
080 | int16_t av_absHOut=5555,av_absHIn=5555; |
084 | int16_t tOut=-5000,tIn=-5000; |
085 | int16_t relHOut=5000,relHIn=5000; |
086 | int16_t dat_tOut[NUM_SAMPLES],dat_tIn[NUM_SAMPLES]; |
087 | int16_t dat_relHOut[NUM_SAMPLES],dat_relHIn[NUM_SAMPLES]; |
088 | int32_t sum_tOut=0,sum_tIn=0; |
089 | int32_t sum_relHOut=0,sum_relHIn=0; |
091 | uint16_t CurrentACS758=0; |
092 | uint16_t offsetACS758=0; |
093 | uint16_t autoACS758=0; |
098 | int16_t dataIn[CHART_POINT]; |
099 | int16_t dataOut[CHART_POINT]; |
100 | } chartTemp,chartAbsH; |
102 | static uint8_t posChart=0; |
103 | static bool ChartMotor= false ; |
104 | static uint16_t last_error=0; |
107 | TaskHandle_t hReadSensor; |
108 | TaskHandle_t hUpdateTFT; |
109 | TaskHandle_t hWebTask; |
110 | SemaphoreHandle_t xTFTSemaphore; |
113 | #define TZ 3*60*60 // Часовой пояс в секундах !!! |
114 | RTClock rt(RTCSEL_LSE); |
118 | unsigned int localPort = 8888; |
119 | #define _rcc_csr *(uint32_t*)0x40021024 // Адрес Регистра управления/статуса RCC_CSR |
123 | Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(pinTFT_CS, pinTFT_DC,pinTFT_RST); |
124 | static boolean fullTftUpdate= false ; |
125 | SimpleDHT22 inDHT(PIN_IN_DHT); |
126 | SimpleDHT22 outDHT(PIN_OUT_DHT); |
128 | EthernetServer server(80); |
132 | uint8_t mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x51, 0x00 }; |
135 | inline void _delay( uint t) |
136 | { if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) vTaskDelay(t/portTICK_PERIOD_MS); else delay(t);} |
137 | /////////////////////////////////////////////////////////////////////////////////////////////////////////// |
139 | /////////////////////////////////////////////////////////////////////////////////////////////////////////// |
141 | uint8_t ip[] = { 192, 168, 1, 175}; |
143 | float temperature = 0; |
147 | Serial .begin(115200); |
148 | Serial .println( "DEBUG MODE" ); |
152 | reg_RCC_CSR=(uint32_t)_rcc_csr; |
153 | bitSet(_rcc_csr,RCC_CSR_RMVF_BIT); |
156 | pinMode(PIN_CS_W25Q8, OUTPUT); |
157 | digitalWrite(PIN_CS_W25Q8, HIGH); |
158 | pinMode(PIN_CS_SDCARD, OUTPUT); |
159 | digitalWrite(PIN_CS_SDCARD, HIGH); |
164 | pinMode(PIN_RELAY1, OUTPUT); |
165 | digitalWrite(PIN_RELAY1, LOW); |
166 | pinMode(PIN_RELAY2, OUTPUT); |
167 | digitalWrite(PIN_RELAY2, LOW); |
168 | pinMode(PIN_KEY, INPUT); |
169 | pinMode(PIN_ACS758 , INPUT_ANALOG); |
170 | pinMode(PIN_BEEP, OUTPUT); |
171 | digitalWrite(PIN_BEEP, LOW); |
172 | pinMode(PIN_LED1, OUTPUT); |
173 | pinMode(PIN_LED2, OUTPUT); |
174 | digitalWrite(PIN_LED1, LOW); |
175 | digitalWrite(PIN_LED2, LOW); |
177 | sensors.autoACS758=CalibrACS758(); |
178 | digitalWrite(PIN_LED1, HIGH); |
179 | digitalWrite(PIN_LED2, HIGH); |
183 | for (i=0;i<CHART_POINT;i++){chartTemp.dataOut[i]=-3000;chartTemp.dataIn[i]=-3000;chartAbsH.dataOut[i]=0;chartAbsH.dataIn[i]=0;} |
185 | setting.mode = BLOCK_OFF; |
187 | SETBIT1(setting.flag,fBEEP); |
188 | SETBIT1(setting.flag,fDHCP); |
189 | SETBIT1(setting.flag,fAUTO); |
190 | setting.hour_unit = 0; |
191 | setting.hour_motor = 0; |
192 | setting.hour_heat = 0; |
195 | parseIPAddress( "192.168.1.176" , '.' ,setting.ip); |
196 | parseIPAddress( "192.168.1.1" , '.' ,setting.dns); |
197 | parseIPAddress( "192.168.1.1" , '.' ,setting.gateway); |
198 | parseIPAddress( "255.255.255.0" , '.' ,setting.mask); |
199 | sensors.CurrentACS758=0; |
209 | Serial .print(setting.name); Serial .println( " start . . ." ); |
212 | if (initEEPROM()!=0) {formatEEPROM(); saveEEPROM();} |
214 | if (GETBIT(setting.flag,fAUTO))sensors.offsetACS758=sensors.autoACS758; else sensors.offsetACS758=setting.constACS758*10; |
221 | rtc_set_prescaler_load(0x7fff); |
222 | Udp.begin(localPort); |
225 | rt.breakTime(rt.now(),tm); |
226 | Serial .print( "RTC timestamp:" ); Serial .print(tm.year+1970); Serial .print( "/" ); Serial .print(tm.month); Serial .print( "/" ); Serial .print(tm.day); Serial .print( " " ); Serial .print(tm.hour); Serial .print( ":" ); Serial .print(tm.minute); Serial .print( ":" ); Serial .println(tm.second); |
229 | rt.breakTime(rt.now(),rTime); |
231 | Serial .print( "Register RCC_CSR:" ); Serial .println(uint32ToHex(reg_RCC_CSR)); |
235 | if ((sensors.inErr = inDHT.read2(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess){ |
237 | Serial .print( "Read inDHT failed, err=" ); Serial .println(uint8ToHex(sensors.inErr)); |
242 | Serial .println( "Read inDHT Ok" ); |
244 | sensors.av_tIn = temperature*100; |
245 | sensors.av_relHIn = humidity*100; |
246 | sensors.av_absHIn = calculationAbsH(temperature, humidity)*100; |
247 | for (i=0;i<CHART_POINT;i++){chartTemp.dataIn[i]=sensors.av_tIn; chartAbsH.dataIn[i]=sensors.av_absHIn;} |
249 | if ((sensors.outErr = outDHT.read2(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) { |
251 | Serial .print( "Read outDHT failed, err=" ); Serial .println(uint8ToHex(sensors.outErr)); |
256 | Serial .println( "Read outDHT Ok" ); |
258 | sensors.av_tOut = temperature*100; |
259 | sensors.av_relHOut = humidity*100; |
260 | sensors.av_absHOut = calculationAbsH(temperature, humidity)*100; |
261 | for (i=0;i<CHART_POINT;i++){chartTemp.dataOut[i]=sensors.av_tOut; chartAbsH.dataOut[i]=sensors.av_absHOut;} |
266 | SPI.setClockDivider(SPI_CLOCK_DIV2); |
271 | xTaskCreate(vReadSensor, "ReadSensor" ,150,NULL,4,&hReadSensor); |
272 | xTaskCreate(vUpdateTFT, "UpdateTFT" ,150,NULL,2,&hUpdateTFT); |
273 | xTaskCreate(vWebTask, "Web" ,350,NULL,1,&hWebTask); |
274 | vSemaphoreCreateBinary(xTFTSemaphore); |
276 | if (xTFTSemaphore==NULL){ |
278 | Serial .println( "Error create semaphore (low memory?)" ); |
283 | iwdg_init(IWDG_PRE_256, 2*1250); |
284 | setup_vdd_tempr_sensor(); |
286 | Serial .println( " . . . Start free RTOS . . ." ); |
288 | vTaskStartScheduler(); |
290 | Serial .println( "vTaskStartScheduler() NOT RUNNING!!!" ); |
298 | static const uint8 periodLen = 9; |
299 | volatile TickType_t curIdleTicks = 0; |
300 | volatile TickType_t lastCountedTick = 0; |
301 | volatile TickType_t lastCountedPeriod = 0; |
302 | static TickType_t lastPeriodIdleValue = 0; |
303 | volatile TickType_t minIdleValue = 1 << periodLen; |
304 | extern "C" void vApplicationIdleHook( void ) |
307 | volatile TickType_t curTick = xTaskGetTickCount(); |
308 | if (curTick != lastCountedTick) |
311 | lastCountedTick = curTick; |
314 | curTick >>= periodLen; |
315 | if (curTick > lastCountedPeriod) |
317 | lastPeriodIdleValue = curIdleTicks; |
319 | lastCountedPeriod = curTick; |
321 | if (lastPeriodIdleValue < minIdleValue) |
322 | minIdleValue = lastPeriodIdleValue; |
328 | static void vReadSensor( void *pvParameters) { |
331 | static TickType_t DHT22Tick = 0; |
332 | static TickType_t curTick = 0; |
333 | static TickType_t sockTick = 0; |
340 | SPI.setClockDivider(SPI_CLOCK_DIV2); |
341 | xSemaphoreGive(xTFTSemaphore); |
343 | if (curTick < sockTick) {DHT22Tick=0;sockTick=0;} |
346 | for (i=0;i<CURRENT_SAMPLES;i++) |
348 | rawVolt=(analogRead(PIN_ACS758)*UREF_VCC*10)/(4096-1); |
349 | if (rawVolt>sensors.offsetACS758) sum=sum+rawVolt-sensors.offsetACS758; else sum=sum+sensors.offsetACS758-rawVolt; |
351 | delayMicroseconds(100); |
353 | sensors.CurrentACS758 = (sum/CURRENT_SAMPLES)*100/miliVoltsPerAmp; |
354 | curTick = xTaskGetTickCount(); |
355 | if (curTick < sockTick) {DHT22Tick=0;sockTick=0;} |
358 | if (curTick-sockTick>10*60*1000){ |
361 | SPI.setClockDivider(SPI_CLOCK_DIV2); |
362 | xSemaphoreGive(xTFTSemaphore); |
367 | if (curTick-DHT22Tick>TIME_SCAN_SENSOR-CURRENT_SAMPLES/10){ |
369 | digitalWrite(PIN_LED1,LOW); |
371 | digitalWrite(PIN_LED1,HIGH); |
379 | static void vUpdateTFT( void *pvParameters) { |
380 | static TickType_t UpdateDataTick = 0; |
381 | static TickType_t UpdateChartTick = 0; |
382 | static TickType_t UpdateDayTick = 0; |
383 | static TickType_t curTick = 0; |
386 | curTick = xTaskGetTickCount(); |
387 | if (curTick<UpdateDataTick) {UpdateDataTick=0;UpdateChartTick=0;UpdateDayTick=0;} |
388 | if ((GETBIT(setting.flag,fTFT_OFF))&&(fullTftUpdate)) |
391 | if (switchTFT()) tft.fillScreen(ILI9341_BLACK); |
394 | if (curTick-UpdateDayTick>24*TIME_HOUR){ |
395 | UpdateDayTick=curTick; |
396 | if (!checkNetLink()) {reset_w5500();_delay(100); init_w5500();} |
397 | if (GETBIT(setting.flag,fNTP)) |
399 | Udp.begin(localPort); |
402 | rt.breakTime(rt.now(),tm); |
403 | Serial .print( "RTC update NTP:" ); Serial .print(tm.year+1970); Serial .print( "/" ); Serial .print(tm.month); Serial .print( "/" ); Serial .print(tm.day); Serial .print( " " ); Serial .print(tm.hour); Serial .print( ":" ); Serial .print(tm.minute); Serial .print( ":" ); Serial .println(tm.second); |
406 | if (GETBIT(setting.flag,fTEST)) testMotorAndACS758(); |
410 | if (!GETBIT(setting.flag,fTFT_OFF)) |
417 | print_status(checkNetLink()); |
423 | if (curTick-UpdateDataTick>TIME_SCAN_SENSOR){ |
424 | UpdateDataTick=curTick; |
427 | print_status(checkNetLink()); |
428 | if (FLAG_FAN_CHECK) ChartMotor= true ; |
430 | if (curTick-UpdateChartTick>TIME_PRINT_CHART){ |
431 | UpdateChartTick=curTick; |
434 | Serial .println( "Point add chart" ); |
436 | if (GETBIT(setting.flag,fBEEP)) beep(30); |
439 | vTaskDelay(TIME_UPDATE_TFT); |
444 | static void vWebTask( void *pvParameters) { |
445 | static TickType_t NetTick = 0; |
446 | static TickType_t curTick = 0; |
448 | curTick = xTaskGetTickCount(); |
449 | if (curTick<NetTick) {NetTick=0;} |
450 | if (curTick-NetTick>TIME_UPDATE_TFT){NetTick=curTick; if (FLAG_NET_CHECK) FLAG_NET_TRUE; else FLAG_NET_FALSE;} |
control.ino
007 | sensors.sum_relHOut=0; |
010 | for (i=0;i<NUM_SAMPLES;i++) |
012 | sensors.dat_tOut[i]=0; |
013 | sensors.dat_tIn[i]=0; |
014 | sensors.dat_relHOut[i]=0; |
015 | sensors.dat_relHIn[1]=0; |
021 | float temperature = 0; |
026 | if (FLAG_FAN_CHECK) { if (sensors.CurrentACS758<setting.CurMin) FLAG_TEST_ERR; else FLAG_TEST_OK;} |
028 | #ifdef DEMO1 // Внутренний датчик |
030 | sensors.tIn=sensors.tIn+random(-60,95); |
031 | if (sensors.tIn>2000) sensors.tIn=1900; |
032 | if (sensors.tIn<-1000) sensors.tIn=-900; |
033 | sensors.relHIn=sensors.relHIn+( float )random(-60,90); |
034 | if (sensors.relHIn>9600) sensors.relHIn=9000; |
035 | if (sensors.relHIn<500) sensors.relHIn=1000; |
037 | if ((sensors.inErr = inDHT.read2(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) { |
040 | Serial .print( "Read inDHT failed, err=" ); Serial .println(uint8ToHex(sensors.inErr)); |
044 | temp=temperature*100+setting.eTIN; |
045 | if (sensors.tIn==-5000) sensors.tIn=temp; else { |
046 | sensors.tIn=constrain(temp, sensors.tIn-GAAP_TEMP, sensors.tIn+GAAP_TEMP); } |
048 | temp=humidity*100+setting.eHIN; |
049 | if (sensors.relHIn==5000) sensors.relHIn=temp; else { |
050 | sensors.relHIn=constrain(temp, sensors.relHIn-GAAP_REALH, sensors.relHIn+GAAP_REALH); } |
059 | #ifdef DEMO1 // Внешний датчик |
061 | sensors.tOut=sensors.tOut+random(-60,95); |
062 | if (sensors.tOut>2000) sensors.tOut=1900; |
063 | if (sensors.tOut<-1000) sensors.tOut=-900; |
064 | sensors.relHOut=sensors.relHOut+( float )random(-70,90); |
065 | if (sensors.relHOut>9600) sensors.relHOut=9000; |
066 | if (sensors.relHOut<500) sensors.relHOut=1000; |
069 | if ((sensors.outErr = outDHT.read2(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) { |
072 | Serial .print( "Read outDHT failed, err=" ); Serial .println(uint8ToHex(sensors.outErr)); |
076 | temp=temperature*100+setting.eTOUT; |
077 | if (sensors.tOut==-5000) sensors.tOut=temp; else { |
078 | sensors.tOut=constrain(temp, sensors.tOut-GAAP_TEMP, sensors.tOut+GAAP_TEMP); } |
080 | temp=humidity*100+setting.eHOUT; |
081 | if (sensors.relHOut==5000) sensors.relHOut=temp; else { |
082 | sensors.relHOut=constrain(temp, sensors.relHOut-GAAP_REALH, sensors.relHOut+GAAP_REALH); } |
091 | if ((sensors.outErr==SimpleDHTErrSuccess)&&(sensors.inErr==SimpleDHTErrSuccess)) |
094 | sensors.sum_tOut=sensors.sum_tOut-sensors.dat_tOut[sensors.index]; |
095 | sensors.sum_tIn=sensors.sum_tIn-sensors.dat_tIn[sensors.index]; |
096 | sensors.sum_relHOut=sensors.sum_relHOut-sensors.dat_relHOut[sensors.index]; |
097 | sensors.sum_relHIn=sensors.sum_relHIn-sensors.dat_relHIn[sensors.index]; |
099 | sensors.dat_tOut[sensors.index]=sensors.tOut; |
100 | sensors.dat_tIn[sensors.index]=sensors.tIn; |
101 | sensors.dat_relHOut[sensors.index]=sensors.relHOut; |
102 | sensors.dat_relHIn[sensors.index]=sensors.relHIn; |
104 | sensors.sum_tOut=sensors.sum_tOut+sensors.tOut; |
105 | sensors.sum_tIn=sensors.sum_tIn+sensors.tIn; |
106 | sensors.sum_relHOut=sensors.sum_relHOut+sensors.relHOut; |
107 | sensors.sum_relHIn=sensors.sum_relHIn+sensors.relHIn; |
110 | sensors.av_tIn=sensors.sum_tIn/(sensors.index+1); |
111 | sensors.av_relHIn=sensors.sum_relHIn/(sensors.index+1); |
112 | sensors.av_tOut=sensors.sum_tOut/(sensors.index+1); |
113 | sensors.av_relHOut=sensors.sum_relHOut/(sensors.index+1); |
115 | sensors.av_tIn=sensors.sum_tIn/NUM_SAMPLES; |
116 | sensors.av_relHIn=sensors.sum_relHIn/NUM_SAMPLES; |
117 | sensors.av_tOut=sensors.sum_tOut/NUM_SAMPLES; |
118 | sensors.av_relHOut=sensors.sum_relHOut/NUM_SAMPLES; |
121 | sensors.av_absHIn=( int )(calculationAbsH(( float )(sensors.av_tIn/100.0),( float )(sensors.av_relHIn/100.0))*100.0); |
122 | sensors.av_absHOut=( int )(calculationAbsH(( float )(sensors.av_tOut/100.0),( float )(sensors.av_relHOut/100.0))*100.0); |
125 | if (sensors.index==NUM_SAMPLES) {sensors.index=0;sensors.first= false ;} |
127 | Serial .println( "Average value" ); |
128 | Serial .print( "IN T=" ); Serial .print(sensors.av_tIn); Serial .print( " H=" ); Serial .print(sensors.av_relHIn); Serial .print( " abs H=" ); Serial .println(sensors.av_absHIn); |
129 | Serial .print( "OUT T=" ); Serial .print(sensors.av_tOut); Serial .print( " H=" ); Serial .print(sensors.av_relHOut); Serial .print( " abs H=" ); Serial .println(sensors.av_absHOut); |
139 | uint16_t CalibrACS758( void ) |
143 | for (i=0;i<CALIBR_SAMPLES;i++) |
145 | sumOffset=sumOffset+(analogRead(PIN_ACS758)*UREF_VCC*10)/(4096-1); |
147 | delayMicroseconds(100); |
150 | Serial .print( "ACS758 '0' (mV)=" ); Serial .println(sumOffset/CALIBR_SAMPLES/10); |
152 | return sumOffset/CALIBR_SAMPLES; |
157 | #define ADC_CR2_TSVREFE_BIT 23 |
158 | #define ADC_CR2_TSVREFE (1U << ADC_CR2_TSVREFE_BIT) |
159 | void setup_vdd_tempr_sensor() { |
160 | adc_reg_map *regs = ADC1->regs; |
161 | regs->CR2 |= ADC_CR2_TSVREFE; |
163 | regs->SMPR1 |= (0b111 << 18); |
164 | regs->SMPR1 |= (0b111 << 21); |
171 | #ifdef USE_HEAT // Если определен калорифер |
173 | if (sensors.av_tIn<=TEMP_LOW) { FAN_OFF; HEAT_ON; return ;} |
174 | if ((FLAG_HEAT_CHECK)&&(sensors.av_tIn>TEMP_LOW+dT_OFF)) HEAT_OFF; |
178 | if ((setting.mode==BLOCK_OFF)&&(!FLAG_FAN_CHECK)) return ; |
179 | if ((setting.mode==BLOCK_OFF)&&(FLAG_FAN_CHECK)) { FAN_OFF ; return ;} |
180 | if ((setting.mode==HOOD_ON )&&(FLAG_FAN_CHECK)) return ; |
181 | if ((setting.mode==HOOD_ON )&&(!FLAG_FAN_CHECK)) { FAN_ON ; return ;} |
184 | if (setting.mode==COOLING) |
186 | if ((!FLAG_FAN_CHECK)&&(sensors.av_tIn>setting.T_min)&&((sensors.av_tIn-sensors.av_tOut)>setting.dH_min)) |
188 | if ((FLAG_FAN_CHECK)&&(sensors.av_tIn<=sensors.av_tOut)) |
194 | if ((sensors.av_tIn<=setting.T_min)&&(FLAG_FAN_CHECK)){FAN_OFF; return ;} |
196 | if ((sensors.av_absHIn<=sensors.av_absHOut)&&(FLAG_FAN_CHECK)){FAN_OFF; return ;} |
200 | if ((sensors.av_tIn<=(setting.T_min))||(sensors.av_absHIn<(sensors.av_absHOut+dH_OFF))){FAN_OFF; return ;} |
202 | if ((sensors.av_tIn>setting.T_min)&&(sensors.av_absHIn>(sensors.av_absHOut+setting.dH_min))){FAN_ON; return ;} |
209 | boolean testMotorAndACS758( void ) |
211 | boolean state=FLAG_FAN_CHECK; |
212 | if (GETBIT(setting.flag,fAUTO)){ |
214 | Serial .println( "Аutocalibration ACS758 . . ." ); |
216 | if (state){FAN_OFF; _delay(4000);} |
218 | sensors.autoACS758=CalibrACS758(); |
220 | if (GETBIT(setting.flag,fAUTO))sensors.offsetACS758=sensors.autoACS758; else sensors.offsetACS758=setting.constACS758*10; |
223 | Serial .print( "Offset ACS758 (mV): " ); Serial .println(sensors.offsetACS758/10); |
224 | Serial .println( "Test fan . . ." ); |
226 | if (!state){ FAN_ON; _delay(5000);} |
227 | if (sensors.CurrentACS758<setting.CurMin)FLAG_TEST_ERR; else FLAG_TEST_OK; |
229 | if (FLAG_TEST_CHECK) Serial .println( "Fan OK" ); else Serial .println( "Fan not work!!" ); |
231 | if (!state){_delay(2000);FAN_OFF;} |
Podval20.h
002 | #define GETBIT(b,f) ((b&(1<<(f)))?true:false) // получить состяние бита |
003 | #define SETBIT1(b,f) (b|=(1<<(f))) // установка бита в 1 |
004 | #define SETBIT0(b,f) (b&=~(1<<(f))) // установка бита в 0 |
005 | #define SWAPB(x) ((unsigned short)x>>8) | (((unsigned short)x&0x00FF)<<8) |
008 | #define pinTFT_CS D19 // SPI2 PB4 // CS |
009 | #define pinTFT_DC D31 // SPI2 PB12 // DC |
010 | #define pinTFT_RST D27 // SPI2 PA8 // сброс дисплея |
011 | #define PIN_BEEP D18 // Ножка куда повешена пищалка |
012 | #define PIN_KEY D24 // Ножка куда повешена кнопка (пока не поддерживается) |
013 | #define PIN_RELAY1 D8 // Ножка на которую повешено реле (SSR1) вентилятора |
014 | #define PIN_RELAY2 D9 // Ножка на которую повешено реле (SSR2) Калорифер |
015 | #define PIN_LED1 D20 // Ножка на которую повешен первый светодиод (LED1) |
016 | #define PIN_LED2 D17 // Ножка на которую повешен второй светодиод (LED2) |
017 | #define PIN_IN_DHT PB6 // Ножка на которую повешен внутренний датчик IN |
018 | #define PIN_OUT_DHT PB7 // Ножка на которую повешен внешний датчик OUT |
019 | #define PIN_ACS758 PA0 // A0 Нога куда прицеплен токовый датчик ACS758 |
020 | #define PIN_W5500 D3 // SPI1 сброс W5500 |
021 | #define PIN_CS_W25Q8 D10 // SPI1 CS чипа памяти W25Q8ODVSSIG |
022 | #define PIN_CS_SDCARD D23 // SPI1 CS карты памяти |
025 | #define FAN_BIT 0 // бит мотора в sensors.flags |
026 | #define HEAT_BIT 1 // бит калорифера в sensors.flags |
027 | #define TEST_BIT 2 // бит отказа вентилятора (false-отказ) |
028 | #define NTP_BIT 3 // бит удачного обновления времени по NTP |
029 | #define NET_BIT 4 // бит контроля здачи вебсервера |
031 | #define FLAG_FAN_ON (SETBIT1(sensors.flags,FAN_BIT)) // бит мотора установить в 1 |
032 | #define FLAG_FAN_OFF (SETBIT0(sensors.flags,FAN_BIT)) // бит мотора установить в 0 |
033 | #define FLAG_FAN_CHECK (GETBIT(sensors.flags,FAN_BIT)) // бит мотора проверить на 1 |
034 | #define FAN_ON {digitalWrite(PIN_RELAY1,HIGH); FLAG_FAN_ON; } // включить мотор |
035 | #define FAN_OFF {digitalWrite(PIN_RELAY1, LOW) ; FLAG_FAN_OFF; } // выключить мотор |
038 | #define FLAG_HEAT_ON (SETBIT1(sensors.flags,HEAT_BIT)) // бит калорифера установить в 1 |
039 | #define FLAG_HEAT_OFF (SETBIT0(sensors.flags,HEAT_BIT)) // бит калорифера установить в 0 |
040 | #define FLAG_HEAT_CHECK (GETBIT(sensors.flags,HEAT_BIT)) // бит калорифера проверить на 1 |
041 | #define HEAT_ON {digitalWrite(PIN_RELAY2, HIGH); FLAG_HEAT_ON; } // включить калорифер |
042 | #define HEAT_OFF {digitalWrite(PIN_RELAY2, LOW); FLAG_HEAT_OFF; } // выключить калорифер |
045 | #define FLAG_TEST_OK (SETBIT1(sensors.flags,TEST_BIT)) // бит теста установить в 1 |
046 | #define FLAG_TEST_ERR (SETBIT0(sensors.flags,TEST_BIT)) // бит теста установить в 0 - ОТКАЗ ВЕНТИЛЯТОРА |
047 | #define FLAG_TEST_CHECK (GETBIT(sensors.flags,TEST_BIT)) // бит теста проверить на 1 |
049 | #define FLAG_NTP_OK (SETBIT1(sensors.flags,NTP_BIT)) // бит NTP установить в 1 |
050 | #define FLAG_NTP_ERR (SETBIT0(sensors.flags,NTP_BIT)) // бит NTP установить в 0 - Время не обновилось по ntp |
051 | #define FLAG_NTP_CHECK (GETBIT(sensors.flags,NTP_BIT)) // бит NTP проверить на 1 |
053 | #define FLAG_NET_FALSE (SETBIT1(sensors.flags,NET_BIT)) // бит NET установить в 1 |
054 | #define FLAG_NET_TRUE (SETBIT0(sensors.flags,NET_BIT)) // бит NET установить в 0 |
055 | #define FLAG_NET_CHECK (GETBIT(sensors.flags,NET_BIT)) // бит NET проверить на 1 |
058 | #define dH_OFF 20 // Гистерезис абсолютной влажности в сотых грамма на куб (фактически сколько не доходит до уличной влажности и выключается) |
059 | #define dT_OFF 20 // Гистерезис температуры в сотых градуса |
060 | #define TEMP_LOW 200 // Температура подвала критическая (в сотых градуса) - система выключается и включается калорифер |
062 | #define UREF_VCC 3330 // опорное напряжение (Напряжение питания контроллера в данном случае) для ацп stm mV (для калибровки необходимо померить 3.3 вольта и занести сюда точное значение) |
063 | #define CALIBR_SAMPLES 800 // ACS758 число усреднений при калибровке должно быть кратно 20 |
064 | #define CURRENT_SAMPLES 400 // ACS758 число усреднений при измернии должно быть кратно 20 |
065 | #define miliVoltsPerAmp 40 // ACS758 Чуствительность датчика см даташит |
066 | #define GAAP_TEMP 50 // Максимальное изменение температуры между измерениями (в сотых градуса) |
067 | #define GAAP_REALH 100 // Максимальное изменение температуры между измерениями (в сотых %) |
069 | #define CHART_POINT 120 // Число точек графика |
072 | #ifdef DEMO // Для демо все быстрее и случайным образом |
073 | #define NUM_SAMPLES 2 // Число усреднений измерений датчика |
074 | #define TIME_SCAN_SENSOR 1000 // Время опроса датчиков мсек, для демки быстрее |
075 | #define TIME_UPDATE_TFT 1000 // Время обновления дисплея |
076 | #define TIME_PRINT_CHART 4000 // Время вывода точки графика мсек, для демки быстрее |
077 | #define TIME_HOUR 50000 // Число мсек в часе, для демки быстрее |
079 | #define NUM_SAMPLES 50 // Число усреднений измерений датчика (скользящее среднее) NUM_SAMPLES*TIME_SCAN_SENSOR=Время полного обновления данных |
080 | #define TIME_SCAN_SENSOR 6000 // Время опроса датчиков мсек |
081 | #define TIME_UPDATE_TFT 2000 // Время обновления дисплея |
082 | #define TIME_PRINT_CHART 300000 // Время вывода точки графика мсек |
083 | #define TIME_HOUR 3600000 // Число мсек в часе |
087 | #define NUM_SETTING 8 // Число вариантов настроек |
088 | const char *strMode[]= { "Выключено" , |
090 | "Охлаждение T>10 dT>5" , |
091 | "Осушение T>+3 dH>0.3" , |
092 | "Осушение T>+3 dH>0.6" , |
093 | "Осушение T>+4 dH>0.4" , |
094 | "Осушение T>+4 dH>0.8" , |
095 | "Осушение T>+5 dH>0.8" |
webserver.ino
001 | #include "webserver.h" |
002 | const char IP_FORMAT[]= "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}" ; |
003 | const char INT3_FORMAT[]= "-?[0-9]{1,3}" ; |
004 | const char INT4_FORMAT[]= "\\d{1,4}" ; |
005 | const char RED_FONT[]= "<font color=\"red\">" ; |
006 | const char GREEN_FONT[]= "<font color=\"green\">" ; |
007 | const char END_FONT[]= "</font>" ; |
010 | uint32_t connectTime[MAX_SOCK_NUM]; |
013 | #define W5500_LINK 0x01 // МАСКА регистра PHYCFGR (W5500 PHY Configuration Register) [R/W] [0x002E] при котором считается что связь есть |
014 | #define W5500_SPEED 0x02 // МАСКА регистра PHYCFGR (W5500 PHY Configuration Register) [R/W] [0x002E] определяется скорость Speed Status |
015 | #define W5500_DUPLEX 0x04 // МАСКА регистра PHYCFGR (W5500 PHY Configuration Register) [R/W] [0x002E] определяется дуплекс Duplex Status |
016 | boolean checkNetLink() |
020 | st= W5100.readPHYCFGR(); |
021 | if (st & W5500_LINK) break ; |
024 | if (st & W5500_LINK) return true ; else return false ; |
027 | void reset_w5500( void ) |
029 | pinMode(PIN_W5500, OUTPUT); |
030 | digitalWrite(PIN_W5500, LOW); |
032 | digitalWrite(PIN_W5500, HIGH); |
036 | void init_w5500( void ){ |
038 | Serial .println( "Init w5500 . . ." ); |
040 | Ethernet.begin(mac, setting.ip, setting.dns, setting.gateway,setting.mask); |
041 | if (GETBIT(setting.flag,fBEEP)) beep(200); else _delay(200); |
044 | if (GETBIT(setting.flag,fDHCP)){digitalWrite(PIN_LED1, LOW); Ethernet.begin(mac); digitalWrite(PIN_LED1, HIGH); |
046 | Serial .print( "Local IP:" ); Serial .println(Ethernet.localIP()); |
047 | Serial .print( "Gateway IP:" ); Serial .println(Ethernet.gatewayIP()); |
048 | Serial .print( "DNS server IP:" ); Serial .println(Ethernet.dnsServerIP()); |
049 | Serial .print( "Subnet mask:" ); Serial .println(Ethernet.subnetMask()); |
055 | realIP=Ethernet.localIP(); |
057 | Serial .print( "Web server is at " ); Serial .println(realIP); |
062 | void checkSockStatus() |
064 | for (uint8_t i = 0; i < MAX_SOCK_NUM; i++) { |
065 | uint8_t s = W5100.readSnSR(i); |
067 | if ((s == SnSR::ESTABLISHED) || (s == SnSR::CLOSE_WAIT) ) { |
068 | if (abs(millis() - connectTime[i]) > 5000) { |
070 | Serial .print( " Socket frozen:" ); Serial .println(i); |
072 | W5100.execCmdSn(i, Sock_CLOSE); |
073 | W5100.writeSnIR(i, 0xFF); |
076 | else connectTime[i] = millis(); |
080 | EthernetClient client; |
086 | uint8_t getCount=0,i; |
089 | client = server.available(); |
097 | boolean currentLineIsBlank = true ; |
098 | while (client.connected()) { |
099 | if (client.available()) { |
100 | char c = client.read(); |
103 | if (c== 'G' ) getCount=1; else |
104 | if ((c== 'E' )&&(getCount==1))getCount=2; else |
105 | if ((c== 'T' )&&(getCount==2))getCount=3; else |
106 | if ((c== ' ' )&&(getCount==3))getCount=4; else |
107 | if ((c== '/' )&&(getCount==4))getCount=5; else |
108 | if ((c== 'g' )&&(getCount==5))getCount=6; else |
109 | if ((c== 'e' )&&(getCount==6))getCount=7; else |
110 | if ((c== 't' )&&(getCount==7))getCount=8; else |
111 | if ((c== '?' )&&(getCount==8)){ modeParser= true ;getCount=9; } else getCount=0; |
114 | if (modeParser== true ){ |
115 | if (c != '\n' ) { inBufGet[num]=c; num++;} |
116 | else { modeParser= false ; parserGET(inBufGet);} |
121 | if (c == '\n' && currentLineIsBlank) { |
125 | client.println( "HTTP/1.1 200 OK" ); |
126 | client.println( "Content-Type: text/html; charset=utf-8" ); |
127 | client.println( "Connection: close" ); |
128 | if (GETBIT(setting.flag,fUPDATE)) client.println( "Refresh:60" ); |
130 | client.println(indexMain0); |
131 | client.println( "<form action=\"/get\"enctype=\"text/plain\"id=\"mode\"method=\"get\">" ); |
132 | oneInputMode(client, ( char *) "Режим работы: " ,setting.mode); |
134 | strcpy(inBufGet,( char *) " Показать настройки" );strcat(inBufGet, " <input name=\"" );strcat(inBufGet,( char *) "QUICK" );strcat(inBufGet, "\" type=\"checkbox\"" ); |
135 | if (GETBIT(setting.flag,fFULL_WEB)) strcat(inBufGet, "checked" ); |
136 | strcat(inBufGet, "/>" ); |
137 | client.println(inBufGet); |
138 | client.println( "<input name=\"send\" type=\"submit\"value=\">>\"/></form>" ); |
139 | client.println( "</td></tr></table></body><hr/>" ); |
142 | if (GETBIT(setting.flag,fFULL_WEB)){ |
144 | client.println(indexMain1); |
146 | client.println( "<tr><td><i> 1. Сетевые настройки W5500</i></td><td></td></tr>" ); |
147 | oneInputCheckbox(client, ( char *) "Получение сетевых настроек по DHCP" ,( char *) "DHCP" , GETBIT(setting.flag,fDHCP)); |
148 | oneInputText(client, ( char *) "IP адрес" , ( char *) "IP" , ( char *)IPAddress2String(setting.ip), 16,( char *)IP_FORMAT); |
149 | oneInputText(client, ( char *) "DNS" , ( char *) "DNS" , ( char *)IPAddress2String(setting.dns), 16,( char *)IP_FORMAT); |
150 | oneInputText(client, ( char *) "Шлюз" , ( char *) "gateway" ,( char *)IPAddress2String(setting.gateway), 16,( char *)IP_FORMAT); |
151 | oneInputText(client, ( char *) "Маска подсети" , ( char *) "mask" , ( char *)IPAddress2String(setting.mask), 16,( char *)IP_FORMAT); |
152 | client.println( "<tr><td><i> 2. Опции</i></td><td></td></tr>" ); |
153 | oneInputCheckbox(client, ( char *) "Обновление времени раз в сутки по NTP" ,( char *) "NTP" , GETBIT(setting.flag,fNTP)); |
154 | oneInputCheckbox(client, ( char *) "Авто обновление web страницы раз в 60 сек." ,( char *) "UPDATE" , GETBIT(setting.flag,fUPDATE)); |
155 | oneInputCheckbox(client, ( char *) "Повернуть изображение на дисплее на 180 градусов" ,( char *) "TFT_180" , GETBIT(setting.flag,fTFT_180)); |
156 | oneInputCheckbox(client, ( char *) "Выключить дисплей" ,( char *) "TFT_OFF" , GETBIT(setting.flag,fTFT_OFF)); |
157 | oneInputCheckbox(client, ( char *) "Включить биппер" ,( char *) "BEEP" , GETBIT(setting.flag,fBEEP)); |
158 | client.println( "<tr><td><i> 3. Датчик тока ACS758</i></td><td></td></tr>" ); |
159 | oneInputCheckbox(client, ( char *) "Ежедневное тестирование вентилятора" ,( char *) "TEST" , GETBIT(setting.flag,fTEST)); |
160 | oneInputCheckbox(client, ( char *) "Автоматическое определение смещения \"0\" ACS758" ,( char *) "AUTO" , GETBIT(setting.flag,fAUTO)); |
161 | arg[0]=0; _itoa(setting.constACS758,arg); oneInputText(client, ( char *) "Смещение \"0\" ACS758, если нет автоматического определения (мВ)" , ( char *) "CONST" ,arg,4,( char *)INT4_FORMAT); |
162 | arg[0]=0; _itoa(setting.CurMin,arg); oneInputText(client, ( char *) "Минимальный ток потребления вентилятора при тесте (мА)" , ( char *) "CurMin" ,arg,4,( char *)INT4_FORMAT); |
163 | client.println( "<tr><td><i> 4. Ошибки датчиков DHT22 (добавляются)</i></td><td></td></tr>" ); |
164 | arg[0]=0; _itoa(setting.eTIN,arg); oneInputText(client, ( char *) "Ошибка внутреннего датчика температуры (сотые доли C°)" , ( char *) "eTIN" ,arg,4,( char *)INT3_FORMAT); |
165 | arg[0]=0; _itoa(setting.eTOUT,arg); oneInputText(client, ( char *) "Ошибка внешнего датчика температуры (сотые доли C°)" , ( char *) "eTOUT" ,arg,4,( char *)INT3_FORMAT); |
166 | arg[0]=0; _itoa(setting.eHIN,arg); oneInputText(client, ( char *) "Ошибка внутреннего датчика влажности (сотые доли %)" , ( char *) "eHIN" ,arg,4,( char *)INT3_FORMAT); |
167 | arg[0]=0; _itoa(setting.eHOUT,arg); oneInputText(client, ( char *) "Ошибка внешнего датчика влажности (сотые доли %)" , ( char *) "eHOUT" ,arg,4,( char *)INT3_FORMAT); |
168 | client.println(indexMain2); |
171 | client.print( "<i>Версия прошивки: " ); client.print(VERSION); |
172 | client.print( " Текуший IP адрес: " ); client.print(IPAddress2String(realIP)); |
173 | client.print( " mac:" ); for (i=0;i<6;i++){client.print(mac[i],HEX); if (i!=5) client.print( ":" );} client.print( "</i><br>" ); |
175 | client.println(indexMain3); |
180 | currentLineIsBlank = true ; |
183 | else if (c != '\r' ) { |
185 | currentLineIsBlank = false ; |
199 | void parserGET( char *buf) |
203 | boolean update= false , tft_off= false , tft_180= false , ChangeTFT= false , upTFT= false , dhcp= false , ntp= false , _update= false , _beep= false , test= false , keyForm= false , quick= false , _auto= false ; |
205 | str = strstr(buf, "HTTP" ); str[0]=0; |
207 | while ((str = strtok_r(buf, "&" , &buf)) != NULL) |
211 | if (strstr(str, "IP" )!=NULL) |
213 | strGet=strchr(str, '=' ); |
214 | if (strGet!=NULL){parseIPAddress(strGet+1, '.' ,temp); if (setting.ip!=temp){setting.ip=temp; update= true ;}} |
216 | if (strstr(str, "DNS" )!=NULL) |
218 | strGet=strchr(str, '=' ); |
219 | if (strGet!=NULL){parseIPAddress(strGet+1, '.' ,temp); if (setting.dns!=temp){setting.dns=temp; update= true ;}} |
221 | if (strstr(str, "gateway" )!=NULL) |
223 | strGet=strchr(str, '=' ); |
224 | if (strGet!=NULL){parseIPAddress(strGet+1, '.' ,temp); if (setting.gateway!=temp){setting.gateway=temp; update= true ;}} |
226 | if (strstr(str, "mask" )!=NULL) |
228 | strGet=strchr(str, '=' ); |
229 | if (strGet!=NULL){parseIPAddress(strGet+1, '.' ,temp); if (setting.mask!=temp){setting.mask=temp; update= true ;}} |
231 | if (strstr(str, "mode" )!=NULL) |
233 | strGet=strchr(str, '=' ); |
234 | code=((uint8_t)strGet[1])-0x30; |
235 | if (strGet!=NULL){ if ((setting.mode!=(TYPE_MODE)code)&&(code>=0)&&(code<=7)){setting.mode=(TYPE_MODE)code; update= true ;ChangeTFT= true ;}} |
238 | if (strstr(str, "QUICK" )!=NULL) |
240 | strGet=strchr(str, '=' ); |
242 | if (strcmp(strGet+1, "on" )==0) quick= true ; |
244 | if (strstr(str, "TFT_OFF" )!=NULL) |
246 | strGet=strchr(str, '=' ); |
248 | if (strcmp(strGet+1, "on" )==0) tft_off= true ; |
250 | if (strstr(str, "TFT_180" )!=NULL) |
252 | strGet=strchr(str, '=' ); |
254 | if (strcmp(strGet+1, "on" )==0) tft_180= true ; |
256 | if (strstr(str, "DHCP" )!=NULL) |
258 | strGet=strchr(str, '=' ); |
260 | if (strcmp(strGet+1, "on" )==0) dhcp= true ; |
262 | if (strstr(str, "NTP" )!=NULL) |
264 | strGet=strchr(str, '=' ); |
266 | if (strcmp(strGet+1, "on" )==0) ntp= true ; |
268 | if (strstr(str, "UPDATE" )!=NULL) |
270 | strGet=strchr(str, '=' ); |
272 | if (strcmp(strGet+1, "on" )==0) _update= true ; |
274 | if (strstr(str, "BEEP" )!=NULL) |
276 | strGet=strchr(str, '=' ); |
278 | if (strcmp(strGet+1, "on" )==0) _beep= true ; |
280 | if (strstr(str, "TEST" )!=NULL) |
282 | strGet=strchr(str, '=' ); |
284 | if (strcmp(strGet+1, "on" )==0) test= true ; |
286 | if (strstr(str, "AUTO" )!=NULL) |
288 | strGet=strchr(str, '=' ); |
290 | if (strcmp(strGet+1, "on" )==0) _auto= true ; |
293 | if (strstr(str, "CONST" )!=NULL) |
295 | strGet=strchr(str, '=' ); |
296 | if (strGet!=NULL){ if (setting.constACS758!=atoi(strGet+1)) {setting.constACS758=atoi(strGet+1);update= true ;}} |
299 | if (strstr(str, "CurMin" )!=NULL) |
301 | strGet=strchr(str, '=' ); |
302 | if (strGet!=NULL){ if (setting.CurMin!=atoi(strGet+1)) {setting.CurMin=atoi(strGet+1);update= true ;}} |
305 | if (strstr(str, "eTIN" )!=NULL) |
307 | strGet=strchr(str, '=' ); |
308 | if (strGet!=NULL){ if (setting.eTIN!=atoi(strGet+1)) {setting.eTIN=atoi(strGet+1);update= true ;}} |
310 | if (strstr(str, "eTOUT" )!=NULL) |
312 | strGet=strchr(str, '=' ); |
313 | if (strGet!=NULL){ if (setting.eTOUT!=atoi(strGet+1)) {setting.eTOUT=atoi(strGet+1);update= true ;}} |
315 | if (strstr(str, "eHIN" )!=NULL) |
317 | strGet=strchr(str, '=' ); |
318 | if (strGet!=NULL){ if (setting.eHIN!=atoi(strGet+1)) {setting.eHIN=atoi(strGet+1);update= true ;}} |
320 | if (strstr(str, "eHOUT" )!=NULL) |
322 | strGet=strchr(str, '=' ); |
323 | if (strGet!=NULL){ if (setting.eHOUT!=atoi(strGet+1)) {setting.eHOUT=atoi(strGet+1);update= true ;}} |
326 | if (strstr(str, "send" )!=NULL) |
328 | strGet=strchr(str, '=' ); |
329 | if (strstr(strGet+1, "%3E%3E" )!=NULL)keyForm= false ; else keyForm= true ; |
336 | if ((!tft_off)&&(GETBIT(setting.flag,fTFT_OFF ))){SETBIT0(setting.flag,fTFT_OFF );update= true ;ChangeTFT= true ;} |
337 | else if ((tft_off)&&(!GETBIT(setting.flag,fTFT_OFF ))){SETBIT1(setting.flag,fTFT_OFF );update= true ;ChangeTFT= true ;} |
339 | if ((!tft_180)&&(GETBIT(setting.flag,fTFT_180))){SETBIT0(setting.flag,fTFT_180);update= true ;ChangeTFT= true ;} |
340 | else if ((tft_180)&&(!GETBIT(setting.flag,fTFT_180))){SETBIT1(setting.flag,fTFT_180);update= true ;ChangeTFT= true ;} |
342 | if ((!dhcp)&&(GETBIT(setting.flag,fDHCP))){SETBIT0(setting.flag,fDHCP);update= true ;} |
343 | else if ((dhcp)&&(!GETBIT(setting.flag,fDHCP))){SETBIT1(setting.flag,fDHCP);update= true ;} |
345 | if ((!ntp)&&(GETBIT(setting.flag,fNTP))){SETBIT0(setting.flag,fNTP);update= true ;} |
346 | else if ((ntp)&&(!GETBIT(setting.flag,fNTP))){SETBIT1(setting.flag,fNTP);update= true ;} |
348 | if ((!_update)&&(GETBIT(setting.flag,fUPDATE))){SETBIT0(setting.flag,fUPDATE);update= true ;} |
349 | else if ((_update)&&(!GETBIT(setting.flag,fUPDATE))){SETBIT1(setting.flag,fUPDATE);update= true ;} |
351 | if ((!_beep)&&(GETBIT(setting.flag,fBEEP))){SETBIT0(setting.flag,fBEEP);update= true ;} |
352 | else if ((_beep)&&(!GETBIT(setting.flag,fBEEP))){SETBIT1(setting.flag,fBEEP);update= true ;} |
354 | if ((!test)&&(GETBIT(setting.flag,fTEST))){SETBIT0(setting.flag,fTEST);update= true ;} |
355 | else if ((test)&&(!GETBIT(setting.flag,fTEST))){SETBIT1(setting.flag,fTEST);update= true ;} |
357 | if ((!_auto)&&(GETBIT(setting.flag,fAUTO))){SETBIT0(setting.flag,fAUTO);update= true ;} |
358 | else if ((_auto)&&(!GETBIT(setting.flag,fAUTO))){SETBIT1(setting.flag,fAUTO);update= true ;} |
363 | if ((!quick)&&(GETBIT(setting.flag,fFULL_WEB))){SETBIT0(setting.flag,fFULL_WEB);update= true ;quick= true ;} |
364 | else if ((quick)&&(!GETBIT(setting.flag,fFULL_WEB))){SETBIT1(setting.flag,fFULL_WEB);update= true ;quick= true ;} |
371 | if (GETBIT(setting.flag,fAUTO))sensors.offsetACS758=sensors.autoACS758; else sensors.offsetACS758=setting.constACS758*10; |
377 | const char constInputText[]= "<tr><td>%s </td><td valign=\"top\"><input maxlength=\"16\" name=\"%s\" required=\"required\" size=\"%d\" type=\"text\" value=\"%s\" pattern=\"%s\" /></td></tr>" ; |
378 | void oneInputText(EthernetClient client, char *label, char *name, char *val, int len, char *pattern) |
382 | strcpy(inBufGet, "<tr><td>" ); |
383 | strcat(inBufGet,label); |
384 | strcat(inBufGet, " </td><td valign=\"top\"><input maxlength=\"16\" name=\"" ); |
385 | strcat(inBufGet,name); |
386 | strcat(inBufGet, "\" required=\"required\" size=\"" ); |
387 | strcat(inBufGet,_itoa(len,tmp)); |
388 | strcat(inBufGet, "\" type=\"text\" value=\"" ); |
389 | strcat(inBufGet,val); |
390 | strcat(inBufGet, "\" pattern=\"" ); |
391 | strcat(inBufGet,pattern); |
392 | strcat(inBufGet, "\" /></td></tr>\r\n" ); |
394 | client.println(inBufGet); |
400 | void oneInputMode(EthernetClient client, char *label, TYPE_MODE mode) |
406 | strcpy(inBufGet, "<br><br> " ); |
407 | strcat(inBufGet,label); |
409 | strcat(inBufGet, "<select name=\"mode\" size=\"1\">" ); |
410 | for (i=0;i<NUM_SETTING;i++) |
412 | if (i==mode) strcat(inBufGet, "<option selected=\"selected\" value=\"" ); |
413 | else strcat(inBufGet, "<option value=\"" ); |
415 | strcat(inBufGet,_itoa(i,tmp)); |
416 | strcat(inBufGet, "\">" ); |
417 | strcat(inBufGet,strMode[i]); |
418 | strcat(inBufGet, "</option>" ); |
421 | strcat(inBufGet, "</select>" ); |
423 | client.println(inBufGet); |
431 | void oneInputCheckbox(EthernetClient client, char *label, char *name, boolean b) |
433 | strcpy(inBufGet, "<tr><td>" );strcat(inBufGet,label);strcat(inBufGet, " </td><td valign=\"top\"><input name=\"" );strcat(inBufGet,name);strcat(inBufGet, "\" type=\"checkbox\"" ); |
434 | if (b) strcat(inBufGet, "checked" ); |
435 | strcat(inBufGet, "/></td></tr>" ); |
437 | client.println(inBufGet); |
442 | void updateData(EthernetClient cl) |
447 | cl.println( "<span style=\"font-size:18px\"><strong>Состояние вентилятора:" ); |
448 | if (FLAG_FAN_CHECK) cl.print( " ВКЛЮЧЕН " ); else cl.print( " ВЫКЛЮЧЕН " ); |
449 | if (FLAG_TEST_CHECK) cl.println( "(исправен)." ); else cl.println( "<font color=\"red\">(отказ мотора!).</font>" ); |
450 | cl.println( "</strong></span>" ); |
456 | cl.print(ChartHeader); |
461 | for (i=0;i<CHART_POINT;i++) |
463 | strcat(inBufGet, "[" );_itoa(CHART_POINT-i,inBufGet);strcat(inBufGet, "," );strcat(inBufGet,ftoa(b,( float )(chartTemp.dataIn[x])/100.0,2));strcat(inBufGet, "," );strcat(inBufGet,ftoa(b,( float )(chartTemp.dataOut[x])/100.0,2));strcat(inBufGet, "]" ); |
464 | if (x<CHART_POINT-1) x++; else x=0; |
465 | if (i<CHART_POINT-1) strcat(inBufGet, "," ); |
478 | for (i=0;i<CHART_POINT;i++) |
480 | strcat(inBufGet, "[" );_itoa(CHART_POINT-i,inBufGet);strcat(inBufGet, "," );strcat(inBufGet,ftoa(b,( float )((chartAbsH.dataIn[x]&0xbfff))/100.0,2));strcat(inBufGet, "," );strcat(inBufGet,ftoa(b,( float )(chartAbsH.dataOut[x])/100.0,2));strcat(inBufGet, "]" ); |
481 | if (x<CHART_POINT-1) x++; else x=0; |
482 | if (i<CHART_POINT-1) strcat(inBufGet, "," ); |
487 | cl.print(ChartBotton); |
492 | #define END_TD_TR "</td></tr>" |
493 | #define TD_TD "</td><td>" |
494 | void Table_Show(EthernetClient cl) |
501 | vdd = 1208*4096.0/adc_read(ADC1,17); |
502 | tempr = (1.43 - (vdd/1000.0/4096.0*adc_read(ADC1,16)))/0.0043 + 25.0; |
504 | strcpy(inBufGet, "<table border=0>" ); |
505 | strcat(inBufGet, "<tr><td>" ); |
506 | strcat(inBufGet, "<table border=1>" ); |
507 | strcat(inBufGet, "<tr><td> Параметр </td><td>Подпол</td><td>Улица</td></tr>" ); |
508 | strcat(inBufGet, "<tr><td>Температура (C°)</td> <td>" );strcat(inBufGet,RED_FONT);strcat(inBufGet,ftoa(buf,( float )(sensors.av_tIn)/100.0,2));strcat(inBufGet,END_FONT);strcat(inBufGet,TD_TD);strcat(inBufGet,GREEN_FONT);strcat(inBufGet,ftoa(buf,( float )(sensors.av_tOut)/100.0,2));strcat(inBufGet,END_FONT);strcat(inBufGet,END_TD_TR); |
509 | strcat(inBufGet, "<tr><td>Относительная влажность (%)</td> <td>" );strcat(inBufGet,RED_FONT);strcat(inBufGet,ftoa(buf,( float )(sensors.av_relHIn)/100.0,2));strcat(inBufGet,END_FONT);strcat(inBufGet,TD_TD);strcat(inBufGet,GREEN_FONT);strcat(inBufGet,ftoa(buf,( float )(sensors.av_relHOut)/100.0,2));strcat(inBufGet,END_FONT);strcat(inBufGet,END_TD_TR); |
510 | strcat(inBufGet, "<tr><td>Абсолютная влажность (г/м<sup>3</sup>)</td><td>" );strcat(inBufGet,RED_FONT);strcat(inBufGet,ftoa(buf,( float )(sensors.av_absHIn)/100.0,2));strcat(inBufGet,END_FONT);strcat(inBufGet,TD_TD);strcat(inBufGet,GREEN_FONT);strcat(inBufGet,ftoa(buf,( float )(sensors.av_absHOut)/100.0,2));strcat(inBufGet,END_FONT);strcat(inBufGet,END_TD_TR); |
511 | if (GETBIT(setting.flag,fFULL_WEB)){ |
512 | strcat(inBufGet, "<tr><td>Код последней ошибки чтения датчика DHT22 </td><td>" ); strcat(inBufGet,uint8ToHex(sensors.inErr));strcat(inBufGet,TD_TD);strcat(inBufGet,uint8ToHex(sensors.outErr));;strcat(inBufGet,END_TD_TR); |
513 | strcat(inBufGet, "<tr><td>Число ошибок чтения датчика DHT22</td><td>" );_itoa(sensors.numErrIn,inBufGet);strcat(inBufGet,TD_TD);_itoa(sensors.numErrOut,inBufGet);strcat(inBufGet,END_TD_TR); |
514 | strcat(inBufGet, "<tr><td>Текущий ток потребления (мА)</td><td colspan=\"2\" align=\"center\">" );_itoa(sensors.CurrentACS758,inBufGet);strcat(inBufGet,END_TD_TR); |
515 | strcat(inBufGet, "<tr><td>Напряжение \"0\" ACS758 (мВ)</td><td colspan=\"2\" align=\"center\">" );_itoa(sensors.offsetACS758/10,inBufGet);strcat(inBufGet,END_TD_TR); |
516 | strcat(inBufGet, "<tr><td>Время последнего сброса</td><td colspan=\"2\" align=\"center\">" ); |
517 | _itoa(rTime.year+1970,inBufGet);strcat(inBufGet, "/" );_itoa(rTime.month,inBufGet);strcat(inBufGet, "/" );_itoa(rTime.day,inBufGet);strcat(inBufGet, " " ); |
518 | _itoa(rTime.hour,inBufGet);strcat(inBufGet, ":" );_itoa(rTime.minute,inBufGet);strcat(inBufGet, ":" );_itoa(rTime.second,inBufGet);strcat(inBufGet,END_TD_TR); |
519 | strcat(inBufGet, "<tr><td>Причина последнего сброса</td><td colspan=\"2\" align=\"center\">" );strcat(inBufGet,whatReset(reg_RCC_CSR));strcat(inBufGet,END_TD_TR); |
520 | strcat(inBufGet, "<tr><td>Напряжение питания stm32 (мВ)</td><td colspan=\"2\" align=\"center\">" );_itoa(vdd,inBufGet);strcat(inBufGet,END_TD_TR); |
521 | strcat(inBufGet, "<tr><td>Температура stm32 (C°)</td><td colspan=\"2\" align=\"center\">" );strcat(inBufGet,ftoa(buf,tempr,2));strcat(inBufGet,END_TD_TR); |
523 | strcat(inBufGet, "</table>" ); |
527 | if (GETBIT(setting.flag,fFULL_WEB)){ |
528 | strcpy(inBufGet, "</td><td>" ); |
529 | strcat(inBufGet, "<p style=\"margin-left: 50px;\"><small><i>" ); |
530 | strcat(inBufGet, "Коды ошибок чтения датчиков DHT22<br>" ); |
531 | strcat(inBufGet, "0x10 - Error to wait for start low signal<br>" ); |
532 | strcat(inBufGet, "0x11 - Error to wait for start high signal<br>" ); |
533 | strcat(inBufGet, "0x12 - Error to wait for data start low signal<br>" ); |
534 | strcat(inBufGet, "0x13 - Error to wait for data read signal<br>" ); |
535 | strcat(inBufGet, "0x14 - Error to wait for data EOF signal<br>" ); |
536 | strcat(inBufGet, "0x15 - Error to validate the checksum<br>" ); |
537 | strcat(inBufGet, "0x16 - Error when temperature and humidity are zero, it shouldn't happen<br>" ); |
538 | strcat(inBufGet, "0x17 - Error when pin is not initialized<br>" ); |
539 | strcat(inBufGet, "</i></small></p></td></tr>" ); |
540 | strcat(inBufGet, "</table>" ); |
549 | const int NTP_PACKET_SIZE= 48; |
550 | byte packetBuffer[NTP_PACKET_SIZE]; |
551 | IPAddress timeServer(88,147,254,235); |
557 | Serial .println( "Update time NTP" ); |
560 | if (!checkNetLink()) { |
562 | Serial .println( "No link ethernet" ); |
567 | digitalWrite(PIN_LED2, LOW); |
568 | while (Udp.parsePacket() > 0) ; |
570 | Serial .println( "Transmit NTP Request" ); |
572 | sendNTPpacket(timeServer); |
573 | uint32_t beginWait = millis(); |
574 | while (millis() - beginWait < 1500) { |
575 | int size = Udp.parsePacket(); |
576 | if (size >= NTP_PACKET_SIZE) { |
578 | Serial .println( "Receive NTP Response" ); |
580 | Udp.read(packetBuffer, NTP_PACKET_SIZE); |
584 | unsigned long highWord = packetBuffer[40]<<8 | packetBuffer[41]; |
585 | unsigned long lowWord = packetBuffer[42]<<8 | packetBuffer[43]; |
588 | unsigned long secsSince1900 = highWord << 16 | lowWord; |
590 | const unsigned long seventyYears = 2208988800UL; |
591 | uint32 epoch = secsSince1900-seventyYears+TZ; |
593 | Serial .print( "NTP ok, unix time = " ); Serial .println(epoch); |
597 | digitalWrite(PIN_LED2, HIGH); |
602 | Serial .println( "No NTP Response :-(" ); |
605 | digitalWrite(PIN_LED2, HIGH); |
610 | void sendNTPpacket(IPAddress &address) |
613 | memset(packetBuffer, 0, NTP_PACKET_SIZE); |
616 | packetBuffer[0] = 0b11100011; |
619 | packetBuffer[3] = 0xEC; |
621 | packetBuffer[12] = 49; |
622 | packetBuffer[13] = 0x4E; |
623 | packetBuffer[14] = 49; |
624 | packetBuffer[15] = 52; |
627 | Udp.beginPacket(address, 123); |
628 | Udp.write(packetBuffer, NTP_PACKET_SIZE); |
tft.ino
002 | #define CHART_FON 0x0883 // цвет фона графика если вентилятор не работает |
003 | #define CHART_FON_FAN 0x39EA // цвет фона графика если вентилятор работает |
004 | #define CHART_GRID 0xD6EE // цвет сетки графика |
005 | #define CHART_AXIS 0x6338 // цвет осей графика |
006 | #define CHART_LABEL 0xDEC4 // цвет надписей графика |
007 | #define ILI9341_GREY 0x6B6D // серый |
009 | const char TIME_LABEL[] = "0m 2m 4m 6m 8m" ; |
011 | const char TIME_LABEL[] = "0h 5h 10h" ; |
013 | #define hRow 18 // высота в пикселях ряда |
015 | static char OutputBuf[maxString + 1] = "" ; |
018 | __attribute__((always_inline)) inline boolean switchTFT() |
020 | if (xSemaphoreTake(xTFTSemaphore, 5000) == pdFALSE) { |
022 | Serial .println( "Error take semaphore" ); |
028 | SPI.setClockDivider(SPI_CLOCK_DIV2); |
033 | __attribute__((always_inline)) inline void switchNET() |
036 | SPI.setClockDivider(SPI_CLOCK_DIV2); |
037 | xSemaphoreGive(xTFTSemaphore); |
041 | void reset_ili9341( void ) |
043 | pinMode(pinTFT_RST, OUTPUT); |
044 | digitalWrite(pinTFT_RST, LOW); |
046 | digitalWrite(pinTFT_RST, HIGH); |
052 | if (GETBIT(setting.flag,fTFT_180)) tft.setRotation(3); else tft.setRotation(1); |
053 | tft.fillScreen(ILI9341_BLACK); |
054 | tft.fillRect(0, 0, 320, 20, ILI9341_BLUE); |
055 | tft.setTextColor(ILI9341_WHITE); |
056 | tft.drawString(utf8rus(( char *) "Ток (мА)" ),2,2,2); |
058 | tft.setTextColor(ILI9341_RED); |
059 | tft.drawString(utf8rus(( char *) "DEMO" ),2+105,2,2); |
063 | for (i=0;i<5;i++) {tft.drawLine(0, (1+i)*hRow+2, 320, (1+i)*hRow+2, ILI9341_GREEN);} |
064 | tft.drawLine(210-2, 1*hRow+2, 210-2, 5*hRow+2, ILI9341_GREEN); |
065 | tft.drawLine(270-2, 1*hRow+2, 270-2, 5*hRow+2, ILI9341_GREEN); |
067 | tft.setTextColor(ILI9341_YELLOW); |
068 | tft.drawString(utf8rus(( char *) "Подпол" ),0+210,3+hRow*1,2); |
069 | tft.drawString(utf8rus(( char *) "Улица" ),0+270,3+hRow*1,2); |
070 | tft.drawString(utf8rus(( char *) "Температура градусы C\xB0" ),0,3+hRow*2,2); |
071 | tft.drawString(utf8rus(( char *) "Относительная влаж. %" ),0,3+hRow*3,2); |
072 | tft.drawString(utf8rus(( char *) "Абсолют. влаж. г/м*3" ),0,3+hRow*4,2); |
075 | tft.setTextColor(CHART_LABEL); |
076 | tft.drawString(utf8rus(( char *) "Температура" ),0+20,3+hRow*5,2); |
077 | tft.drawString(utf8rus(( char *) "Абс. влажность" ),0+170,3+hRow*5,2); |
079 | tft.drawLine(1, 240-5-hRow, 130, 240-5-hRow, CHART_AXIS); |
080 | tft.drawLine(320-130-25, 240-5-hRow, 320-1-25, 240-5-hRow, CHART_AXIS); |
082 | tft.drawLine(1, 240-5-hRow, 1, 240-5-105-hRow, CHART_AXIS); |
083 | tft.drawLine(320-130-25, 240-5-hRow,320-130-25, 240-1-5-105-hRow, CHART_AXIS); |
086 | tft.setTextColor(CHART_LABEL); |
087 | tft.setCursor(0+130,123); tft.print( "+20.0" ); |
088 | tft.setCursor(0+130,162); tft.print( "0.0" ); |
089 | tft.setCursor(0+130,202); tft.print( "-20.0" ); |
091 | tft.setCursor(0+295,112); tft.print( "20.0" ); |
092 | tft.setCursor(0+295,137); tft.print( "15.0" ); |
093 | tft.setCursor(0+295,162); tft.print( "10.0" ); |
094 | tft.setCursor(0+295,187); tft.print( "5.0" ); |
095 | tft.setCursor(0+295,212); tft.print( "0.0" ); |
097 | tft.setTextColor(CHART_LABEL); |
098 | tft.setCursor(2,219); |
099 | tft.print(( char *)TIME_LABEL); tft.setCursor(162,220); tft.print(( char *)TIME_LABEL); |
103 | tft.setTextColor(ILI9341_WHITE); |
104 | tft.setCursor(2,229); |
105 | tft.print( "ver. " ); tft.print(VERSION); tft.print( " IP:" );tft.print(IPAddress2String(realIP)); tft.print( " mac:" ); |
106 | for (i=0;i<6;i++){tft.print(mac[i],HEX); if (i!=5) tft.print( ":" );} |
117 | if (FLAG_FAN_CHECK) setting.hour_motor++; |
119 | if (FLAG_HEAT_CHECK) setting.hour_heat++; |
124 | tft.fillRect(65,2,42,hRow-1, ILI9341_BLUE); |
125 | if (!FLAG_TEST_CHECK) tft.setTextColor(ILI9341_RED); else tft.setTextColor(ILI9341_WHITE); |
126 | tft.drawString(_itoa(sensors.CurrentACS758,buf),65,2,2); |
128 | tft.setTextColor(ILI9341_RED); |
129 | tft.fillRect(0+212,3+hRow*2,55,hRow-1, ILI9341_BLACK); tft.drawString(ftoa(buf,( float )(sensors.av_tIn)/100.0,2),0+212,3+hRow*2,2); |
130 | tft.fillRect(0+212,3+hRow*3,55,hRow-1, ILI9341_BLACK); tft.drawString(ftoa(buf,( float )(sensors.av_relHIn)/100.0,2),0+212,3+hRow*3,2); |
131 | tft.fillRect(0+212,3+hRow*4,55,hRow-1, ILI9341_BLACK); tft.drawString(ftoa(buf,( float )(sensors.av_absHIn)/100.0,2),0+212,3+hRow*4,2); |
134 | tft.setTextColor(ILI9341_GREEN); |
135 | tft.fillRect(0+272,3+hRow*2,55,hRow-1, ILI9341_BLACK); tft.drawString(ftoa(buf,( float )(sensors.av_tOut)/100.0,2),0+272,3+hRow*2,2); |
136 | tft.fillRect(0+272,3+hRow*3,55,hRow-1, ILI9341_BLACK); tft.drawString(ftoa(buf,( float )(sensors.av_relHOut)/100.0,2),0+272,3+hRow*3,2); |
137 | tft.fillRect(0+272,3+hRow*4,55,hRow-1, ILI9341_BLACK); tft.drawString(ftoa(buf,( float )(sensors.av_absHOut)/100.0,2),0+272,3+hRow*4,2); |
149 | chartTemp.dataIn[posChart]=sensors.av_tIn; |
150 | chartTemp.dataOut[posChart]=sensors.av_tOut; |
151 | chartAbsH.dataIn[posChart]=sensors.av_absHIn; |
152 | if (ChartMotor== true ) chartAbsH.dataIn[posChart]=chartAbsH.dataIn[posChart]+0x4000; |
154 | chartAbsH.dataOut[posChart]=sensors.av_absHOut; |
158 | for (i=0;i<CHART_POINT;i++) |
161 | if (posChart<i) x=120+posChart-i; else x=posChart-i; |
163 | if (chartAbsH.dataIn[x]&0x4000){tft.drawLine(3+i,240-6-hRow,3+i,240-6-105-hRow,CHART_FON_FAN);tft.drawLine(320-130-23+i,240-6-hRow,320-130-23+i,240-6-105-hRow,CHART_FON_FAN);} |
164 | else {tft.drawLine(3+i,240-6-hRow,3+i,240-6-105-hRow,CHART_FON); tft.drawLine(320-130-23+i,240-6-hRow,320-130-23+i,240-6-105-hRow,CHART_FON);} |
168 | tft.drawPixel(3+i,240-6-hRow-10,CHART_GRID); |
169 | tft.drawPixel(3+i,240-6-hRow-50,CHART_GRID); |
170 | tft.drawPixel(3+i,240-6-hRow-90,CHART_GRID); |
171 | tft.drawPixel(320-130-23+i,240-6-hRow-25,CHART_GRID); |
172 | tft.drawPixel(320-130-23+i,240-6-hRow-50,CHART_GRID); |
173 | tft.drawPixel(320-130-23+i,240-6-hRow-75,CHART_GRID); |
174 | tft.drawPixel(320-130-23+i,240-6-hRow-100,CHART_GRID); |
178 | if (chartTemp.dataIn[x]<=-2500) y=0; |
179 | else if (chartTemp.dataIn[x]>=2500) y=100; |
180 | else y=((2*chartTemp.dataIn[x])+5000)/100; |
181 | if ((y==0)||(y==100)) tft.drawPixel(3+i,240-6-hRow-y,ILI9341_WHITE); else tft.drawPixel(3+i,240-6-hRow-y,ILI9341_RED); |
183 | if (chartTemp.dataOut[x]<=-2500) y=0; |
184 | else if (chartTemp.dataOut[x]>=2500) y=100; |
185 | else y=((2*chartTemp.dataOut[x])+5000)/100; |
186 | if ((y==0)||(y==100)) tft.drawPixel(3+i,240-6-hRow-y,ILI9341_WHITE); else tft.drawPixel(3+i,240-6-hRow-y,ILI9341_GREEN); |
188 | tmp=chartAbsH.dataIn[x]&0xbfff; |
189 | if (tmp>=2000) y=100; |
191 | if (y==100) tft.drawPixel(320-130-23+i,240-6-hRow-y,ILI9341_WHITE); else tft.drawPixel(320-130-23+i,240-6-hRow-y,ILI9341_RED); |
193 | if (chartAbsH.dataOut[x]>=2000) y=100; |
194 | else y=(5*chartAbsH.dataOut[x])/100; |
195 | if (y==100) tft.drawPixel(320-130-23+i,240-6-hRow-y,ILI9341_WHITE); else tft.drawPixel(320-130-23+i,240-6-hRow-y,ILI9341_GREEN); |
198 | if (posChart<120-1) posChart++; else posChart=0; |
203 | #define hLoad 1 // Толщина индикатора |
204 | static uint16_t cpu_old=0; |
208 | cpu = 320 - 320*lastPeriodIdleValue/(1 << periodLen); |
209 | if (cpu==cpu_old) return ; |
211 | tft.fillRect(0, 239-hLoad , 320, hLoad, ILI9341_BLACK); |
212 | tft.fillRect(0, 239-hLoad, cpu, hLoad, ILI9341_WHITE); |
217 | const unsigned char ventLogo [] = { |
218 | 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x01, 0xf8, 0x00, 0x03, 0xf8, 0x00, 0x03, 0xf0, 0x00, 0x01, |
219 | 0xe0, 0x00, 0x71, 0xc0, 0x00, 0xf9, 0x2f, 0x80, 0xfe, 0x1f, 0x80, 0xfe, 0xdf, 0xc0, 0x7e, 0x0f, |
220 | 0xc0, 0x38, 0xc7, 0x80, 0x00, 0xe3, 0x00, 0x01, 0xe0, 0x00, 0x07, 0xf0, 0x00, 0x07, 0xe0, 0x00, |
221 | 0x03, 0xe0, 0x00, 0x01, 0x80, 0x00 |
223 | const unsigned char heatLogo [] = { |
224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x01, 0xc0, 0x00, 0x01, 0xe0, 0x00, 0x11, |
225 | 0xf0, 0x00, 0x1b, 0xf6, 0x00, 0x1f, 0xf6, 0x00, 0x1f, 0xfe, 0x00, 0x1f, 0xbf, 0x00, 0x3f, 0xbf, |
226 | 0x00, 0x3f, 0x9f, 0x00, 0x37, 0x19, 0x00, 0x36, 0x03, 0x00, 0x30, 0x03, 0x00, 0x18, 0x06, 0x00, |
227 | 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 |
229 | const unsigned char netLogo [] = { |
230 | 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x02, 0x10, 0x00, 0x02, 0x10, 0x00, 0x02, 0x10, 0x00, 0x03, |
231 | 0x30, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x1f, 0xfe, 0x00, 0x3f, 0xff, 0x00, 0x20, 0xc1, |
232 | 0x00, 0x30, 0xc3, 0x00, 0x8b, 0x34, 0x40, 0x8a, 0x14, 0x40, 0x8a, 0x14, 0x40, 0x8a, 0x14, 0x40, |
233 | 0xf9, 0xe7, 0xc0, 0x00, 0x00, 0x00 |
235 | #define icoX 210-65 // Положение иконок на панеле управления |
236 | static boolean blinkFan= false ; |
237 | void print_status(boolean net) |
240 | if (!FLAG_TEST_CHECK) |
241 | { if (blinkFan) tft.drawBitmap(icoX, 1, ventLogo, 18, 18, ILI9341_RED); else tft.drawBitmap(icoX, 1, ventLogo, 18, 18, ILI9341_GREY); blinkFan=!blinkFan;} |
243 | if (FLAG_FAN_CHECK) tft.drawBitmap(icoX, 1, ventLogo, 18, 18, ILI9341_WHITE); else tft.drawBitmap(icoX, 1, ventLogo, 18, 18, ILI9341_GREY);} |
245 | if (FLAG_HEAT_CHECK) tft.drawBitmap(icoX+20, 1, heatLogo, 18, 18, ILI9341_WHITE); else tft.drawBitmap(icoX+20, 1, heatLogo, 18, 18, ILI9341_GREY); |
247 | tft.drawBitmap(icoX+20, 1, heatLogo, 18, 18, ILI9341_GREY); |
249 | if (net) tft.drawBitmap(icoX+40, 1, netLogo, 18, 18, ILI9341_WHITE); else tft.drawBitmap(icoX+40, 1, netLogo, 18, 18, ILI9341_GREY); |
253 | #define errX 280-68 // координата Х для кода ошибки |
254 | void print_error_AHT( void ) |
256 | uint16_t err=sensors.outErr+(sensors.inErr<<8); |
261 | tft.fillRect(errX,2,65-1,hRow,ILI9341_BLUE); |
262 | tft.setTextColor(ILI9341_WHITE); |
263 | if (err>0) tft.drawString(uint16ToHex(err),errX,2,2); |
264 | else tft.drawString(( char *) " Ok" ,errX,2,2); |
268 | #define timeX 276 // координата Х для времени |
272 | rt.breakTime(rt.now(),tm); |
274 | if (tm.hour<10)strcpy(OutputBuf, "0" );_itoa(tm.hour,OutputBuf);strcat(OutputBuf, " " ); if (tm.minute<10)strcat(OutputBuf, "0" );_itoa(tm.minute,OutputBuf); |
276 | tft.fillRect(timeX,2,42,hRow,ILI9341_BLUE); |
277 | if (FLAG_NTP_CHECK) tft.setTextColor(ILI9341_WHITE); else tft.setTextColor(ILI9341_PINK); |
278 | tft.drawString(OutputBuf,timeX,2,2); |
279 | if (FLAG_NET_CHECK) tft.drawString(( char *) ":" ,timeX+19,2,2); |
288 | tft.fillRect(0,3+hRow*1,208-1,hRow-1, ILI9341_BLACK); |
289 | tft.setTextColor(ILI9341_WHITE); |
290 | switch (setting.mode) |
292 | case BLOCK_OFF: tft.drawString(utf8rus(( char *)strMode[BLOCK_OFF]),0,3+hRow*1,2); setting.dH_min=255;setting.T_min=255; break ; |
293 | case HOOD_ON: tft.drawString(utf8rus(( char *)strMode[HOOD_ON]),0,3+hRow*1,2); setting.dH_min=0; setting.T_min=0; break ; |
294 | case COOLING: tft.drawString(utf8rus(( char *)strMode[COOLING]),0,3+hRow*1,2); setting.dH_min=500;setting.T_min=1000; break ; |
295 | case DEHUMIDIFIER_T3_H3: tft.drawString(utf8rus(( char *)strMode[DEHUMIDIFIER_T3_H3]),0,3+hRow*1,2); setting.dH_min=30; setting.T_min=300; break ; |
296 | case DEHUMIDIFIER_T3_H6: tft.drawString(utf8rus(( char *)strMode[DEHUMIDIFIER_T3_H6]),0,3+hRow*1,2); setting.dH_min=60; setting.T_min=300; break ; |
297 | case DEHUMIDIFIER_T4_H4: tft.drawString(utf8rus(( char *)strMode[DEHUMIDIFIER_T4_H4]),0,3+hRow*1,2); setting.dH_min=40; setting.T_min=400; break ; |
298 | case DEHUMIDIFIER_T4_H8: tft.drawString(utf8rus(( char *)strMode[DEHUMIDIFIER_T4_H8]),0,3+hRow*1,2); setting.dH_min=80; setting.T_min=400; break ; |
299 | case DEHUMIDIFIER_T5_H8: tft.drawString(utf8rus(( char *)strMode[DEHUMIDIFIER_T5_H8]),0,3+hRow*1,2); setting.dH_min=80; setting.T_min=500; break ; |
300 | default : tft.drawString(utf8rus(( char *)strMode[BLOCK_OFF]),0,3+hRow*1,2); setting.dH_min=255;setting.T_min=255; setting.mode=BLOCK_OFF; break ; |
util.ino
005 | char *ftoa( char *a, double f, int precision) |
007 | long p[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000}; |
009 | long heiltal = ( long )f; |
010 | itoa(heiltal, a, 10); |
011 | while (*a != '\0' ) a++; |
013 | long desimal = abs(( long )((f - heiltal) * p[precision])); |
014 | itoa(desimal, a, 10); |
019 | char * _itoa( int value, char * string ) |
023 | while (* string ) string ++; |
025 | char *pbuffer = string ; |
026 | unsigned char negative = 0; |
035 | *(pbuffer++) = '0' + value % 10; |
046 | uint32_t len = (pbuffer - string ); |
047 | for (uint32_t i = 0; i < len / 2; i++) { |
049 | string [i] = string [len-i-1]; |
055 | boolean parseIPAddress( const char * str, char sep, IPAddress &ip) |
059 | for (i = 0; i < 4; i++) |
062 | x= strtoul(str, NULL, 10); |
063 | if (x>255) return false ; |
064 | if ((x==0)&&(y!= '0' )) return false ; |
066 | str = strchr(str, sep); |
067 | if (str == NULL || *str == '\0' ) { |
073 | if (i<4-1) return false ; else { ip=tmp; return true ; } |
077 | char *IPAddress2String(IPAddress & ip) |
080 | for (uint8_t i = 0; i < 4; i++) { |
081 | _itoa(ip[i], _bufTemp); |
082 | if (i < 3) strcat(_bufTemp, "." ); |
086 | const char codeHex[]={ "0123456789ABCDEF" }; |
088 | char * uint32ToHex(uint32_t f) |
092 | _bufTemp[2]=codeHex[0x0f & (f>>28)]; |
093 | _bufTemp[3]=codeHex[0x0f & (f>>24)]; |
094 | _bufTemp[4]=codeHex[0x0f & (f>>20)]; |
095 | _bufTemp[5]=codeHex[0x0f & (f>>16)]; |
096 | _bufTemp[6]=codeHex[0x0f & (f>>12)]; |
097 | _bufTemp[7]=codeHex[0x0f & (f>>8)]; |
098 | _bufTemp[8]=codeHex[0x0f & (f>>4)]; |
099 | _bufTemp[9]=codeHex[0x0f & (f)]; |
104 | char * uint16ToHex(uint16_t f) |
108 | _bufTemp[2]=codeHex[0x0f & (unsigned char )(highByte(f)>>4)]; |
109 | _bufTemp[3]=codeHex[0x0f & (unsigned char )(highByte(f))]; |
110 | _bufTemp[4]=codeHex[0x0f & (unsigned char )(lowByte(f)>>4)]; |
111 | _bufTemp[5]=codeHex[0x0f & (unsigned char )(lowByte(f))]; |
116 | char * uint8ToHex(uint8_t f) |
120 | _bufTemp[2]=codeHex[0x0f & (unsigned char )(f>>4)]; |
121 | _bufTemp[3]=codeHex[0x0f & (unsigned char )(f)]; |
127 | { digitalWrite(PIN_BEEP, HIGH); |
129 | digitalWrite(PIN_BEEP, LOW); |
132 | char *utf8rus( char *source) |
136 | char m[2] = { '0' , '\0' }; |
138 | strcpy(OutputBuf, "" ); k = strlen(source); i = j = 0; |
147 | if (n == 0x81) { n = 0xA8; break ; } |
148 | if (n >= 0x90 && n <= 0xBF) n = n + 0x30; |
153 | if (n == 0x91) { n = 0xB8; break ; } |
154 | if (n >= 0x80 && n <= 0x8F) n = n + 0x70; |
160 | m[0] = n; strcat(OutputBuf, m); |
161 | j++; if (j >= maxString) break ; |
168 | float calculationAbsH( float t, float h) |
171 | temp=pow(2.718281828,(17.67*t)/(t+243.5)); |
172 | return (6.112*temp*h*2.1674)/(273.15+t); |
177 | char * whatReset(uint32_t reg){ |
179 | if (bitRead(reg,RCC_CSR_LPWRRSTF_BIT)) strcat(bRes, "Low power<br>" ); |
180 | if (bitRead(reg,RCC_CSR_WWDGRSTF_BIT)) strcat(bRes, "Window watchdog<br>" ); |
181 | if (bitRead(reg,RCC_CSR_IWDGRSTF_BIT)) strcat(bRes, "Independent watchdog<br>" ); |
182 | if (bitRead(reg,RCC_CSR_SFTRSTF_BIT)) strcat(bRes, "Software reset<br>" ); |
183 | if (bitRead(reg,RCC_CSR_PORRSTF_BIT)) strcat(bRes, "Power up<br>" ); |
184 | if (bitRead(reg,RCC_CSR_PINRSTF_BIT)) if (strlen(bRes)<1) strcat(bRes, "Reset key<br>" ); |
194 | uint16_t *ptr, i, count, Status; |
195 | ptr=(uint16_t*)&setting; |
196 | for (i=0;i< sizeof (setting)/2;i++) {Status=EEPROM.write(i,ptr[i]); if (Status!=0) break ; } |
198 | EEPROM.count(&count); |
199 | Serial .print( "Save setting, status=" ); Serial .print(Status); Serial .print( " number of variable:" ); Serial .println(count); |
207 | uint16_t *ptr,i,Status,count; |
208 | ptr=(uint16_t*)&setting; |
209 | for (i=0;i< sizeof (setting)/2; i+= 1) {Status=EEPROM.read(i,&ptr[i]); if (Status!=0) break ;} |
211 | EEPROM.count(&count); |
212 | Serial .print( "Load setting, status=" ); Serial .print(Status); Serial .print( " number of variable:" ); Serial .println(count); |
222 | EEPROM.PageBase0 = 0x801F000; |
223 | EEPROM.PageBase1 = 0x801F800; |
224 | EEPROM.PageSize = 0x400; |
225 | Status = EEPROM.init(); |
227 | Serial .print( "EEPROM.init() : " ); Serial .println(Status, HEX); |
233 | uint16_t formatEEPROM() |
236 | Status = EEPROM.format(); |
238 | Serial .print( "EEPROM.format() : " ); Serial .println(Status, HEX); |
webserver.h
009 | const char indexMain0[] = |
013 | "<title>Осушитель 2.0</title>" |
015 | "<link href=\"data:image/x-icon;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQs" |
016 | "NFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0K" |
017 | "xwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQE" |
018 | "BAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqO" |
019 | "kpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD7T+Nnx21Hwjr9j4J8EaUviHx5qCeYkDsTDZRn/lpKQRnpnqOOScYDeSatpPi1fEFpp3iz9oSbSPEt5DJOmnaRbEQRhCgdfkZAQC68FR39Can+Ed9" |
020 | "Pq1x8WPGxkCa9qniM6LFckfNbQKyBQPQBXUf8AX0qP9oHxFonwZ+L/wAHL2HS3kTTxqBuFVkR7uCdYbd1TcQZpg8kcnljkhT0zX0lWp/Z8lh6EVzJatpNt2u907Jbab7s4P4nvSehtW/xY+InwHksLrxtf23xB+H11IsJ8SadHtubMk4DSBRyM8dyem7OFP1BY31tqlj" |
021 | "b3lnNHc2lxGssM0RDJIjDKsMdQQQcduteT+IfB+mza/c+HJIF/sPxRYXEd1ZqBsSVAv71R0UkN27gGsX9ifXLrV/gRYWt05lOl3txYRyFiSyKwdeT0A37R7KBXNXUMVhniVFRnFpOysmneztsndNO2jNabcZ8j2PPdQW0+B3xd8XeGfE0jaf4G8dTnU9N1c8RWd2W3Mr" |
022 | "N0ADEc9AFjJwCxHu3ir4e6V8QtP8ADJ1O5muG0XUbXWbS7tnVS88OSrE4IKtk5A6g9a6vxf4M0Tx9oU+jeINNh1TTZuWgmQ8MOjLjBVh7EEdc14ef2MdL0t3i8O+PPF/h3THOW0+01H90MnkKQBx7nPNOVXDY1KdabhNJJ6XTtpfTVO2/R7goypt8quif48fEXT/h3cT" |
023 | "SWl7/AGh411S1Gm6PpKEEwNIcGYgchc4OT1xge179nnS4vhXpNh4QL7o5YxK0mP8Al4YbiSP9oY47fL6VZ8P/ALMPhP4c6bd3ui2VzrPiFyrPqOqTeddSAMC6qcAKSMggDOOpNI2k32s+L/NsY5vnnWXzHiZPIGcjdkcY6fhxXq4eOEnhZ0Kcrrq3pqttOiWtu+p4mNq" |
024 | "16VenKK+S633P/9k=\" rel=\"icon\" " |
025 | "type=\"image/x-icon\" />" |
029 | "<table border=0><tr><td>" |
031 | "<img alt=\"\" src=\"data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABmCAIAAACySKMIAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAABU8SURBVHhe5V0JmBTVne+qvu/umWY4BoZ7gBlAdICIgr" |
032 | "eJu4lk4xGzJq7gmd14JMaga9S4qF8+D2LcZDVRdI3EfN7m84hARFBBDoHhGmEuYBjmoGf6mL7q6qraX3XVzPRMn9Pd0zSb39fMV6+OV+/93v/9j3cUhCiKqtMEQVSxgkhFxQgvhjmhjxXoqHQgKNdVejVhVBNmHenUkRYtiWOcIQnlavFRbLJA0CmKPxGKNge4xgDXHu" |
033 | "a9NO/nBIoXSYIgUSDlRgUgjhdFNaGyasgxBrXLSE63aGbYtLPt2vEmjUlTVOaKRBbDiw0+dnsPs8/D9tC8hxGiogoyAnZGCtAHxnWkCtzVOLR1Lv1F4wx2pEcfo0sWzYunIvzbx8PrOymWF0EQJKGwwoA81aRqWYX+0vHGC8YbdKPZS0eLrO4IX+9l3z8R2edl0YmK0F" |
034 | "t4UTXeqF4yVn91lWmKTTsabyw8WaBpQwf1SSfVHIxCpRSBpnigMmibi8cbVs6wVlkLrNIKSRYU019PRNDpOiN8MVRIashVummmZWW1tYB8FYYseABNfm71fr+b5qNCsaUpEahSpVn9zOJydEyicKUpAFnwAz5qj7x+LAwjVQpAKcYYyN+fW15p1iinCoR8ydrcRa1rCR" |
035 | "/p46ApSgRg6uEFzgXlOiVdOOROFieIzx0OQknhoGSIUmlIYvXZjmXjDEq6oMiRrAAnPL7P//kpprgudAYgGFoxw/KjGRYlXWjkYrUa+7gVX/RudZcWU/DsLxlvuG6aWUmPAkZM1rZu+nFYPeo0OweJQLR4xxybtnQ8+F09zEP1/hAnlBRTqIBJS/5xSdlUq1Y5NToYQa" |
036 | "0/76Z/vtsLfV5qMqUhVbdXW0abKSBbyfrSzTxS76MQtmYCdAd6QpVZ49STcojG8Ko+TvAxfA8tcKKqsDEQnLvLJhgeXODIuQN6ad6mI2FGlXRqZEXWET/70F5/N8Ur6dSAu3zNZNPllaZKk9qoIeA+4wzewIsiHRVDUfF4kNvv4/Z5mXovp47FcXlijEH9/HnlY43ILE" |
037 | "e80hSkBPH2WbaMdGUm63gouuorL8K9jPXSqonHz3EuqdAr6bQAdzt7GMTbO3uZECeioLnwRqgeO9t54fjcvSrU/ue7vDt6mPvm279bZVLOpkAG/QOHc21jMBumgKUV+iyZAgwaApV8tM65btmYe2pttQ4t5DYrjdAPXlRdONaQD1NAKCoc9kuDSL9p6GvwscrZFMhA1i" |
038 | "vNoU+76GyYQtHnOXOJMMaa1NdMNT93nuvZxWWXjDOoSSIpZci/yqKBQpSBe6ZYNLfPtirpXAH77uWkXAVB9fiBvkhapZyOLLhUrx8NZ6lWcBtUkpIYOfD4ojH61XXO1y5wXTvFjP4VnxeOv1lpfGmp62c1NnkUAfdfP808Me9QeUMHpe0fl2gLRp886E+jllKS1R6O/u" |
039 | "5wgB3JSMKxIKcc5YFKs+buWtt7l1Qsn2TS9UsZSnHFBINBTUAGfzDVDClb5NJfMdGYXTumBAq8vYcZyAR685NO+sP2iJJOQHKywNG6llB7JLP5i8c+Hxst0DCNy6BeNd/+x/PKLxxnQCeBHFX1u1ErZ1qnWjW3z7JmY+zT42/tMIPKsQzk+KeWkIdOXvHkZDX4uC3ddA" |
040 | "Z9lgA/I7SFokqiEJhh164+x3lvrQ3+mra/NPBInlzonGnP1wVtDXDrO6nEOnZR/HNHgkpiKJIQAgsI05Be1SUFWunjk5SSKBAgU9+bYv7dueXxPmf+o3qo3brWMFpXSccBjHzQHjngTWIZk5D1UTvVHOByEHE8srmLDrJJSpAnptm0joLODH7tYz/tStmuepKAvk7U9M" |
041 | "NL0McK77SFBwzESNFBRb/qZZREqaIjHH3sQDqrBxzycTvctJLox3CyPjgRORnOXe+A5T80BhHcKOnSQ4gTHt3f10tnEH90/7XNIRZ2Nw5DyPIxwoZOKuaj5Y4TYX5De4E1VwGB6M3DZA5IcEODnx3WS4aQBXe2JRDNsQf2Q0uoXmgOojsr6RLDXKdu3QVj7qqx2XVk+i" |
042 | "JqCOLPreH4XjJIFmzZ305GIH75o4cWXmoKlmxXhHN77VTzK8tc851aLnUpwUS9lzkeHFRKg2TBZa/3soXgSsr0nbbI7p6S1vTwe59b4rqt2jJULw2BmiDWdwyqlEGyNnZQaR4bKZDvY/uzGgI7jYDNXzHT+ujZDiWdANTigzgvXyELNMFFGmSuEPAwwn/u9sH6KOmSBF" |
043 | "zdSyuNvzzLYUgxVUXzQr1H6SIKP0f8bEekkJEKgJe3BLg1h/oQEiinShWIyf9tmiVpzBIVVFtPKQ6XQtZuD5vH+Eo6bOyk79nlDZa2fAE3zLQsKEs+HvfZKYaJaSiJLDQ8lHFBVHsi8IK9HvaO7Z7DmcYhTzvunWtjE9xp0AL3Ux4gkMhyU3xbOF/3Kg3wjtZg9O5d3r" |
044 | "WNpet/AZMtmppkgxkQqyN90lCdRNbJSHQ0ot94oCWoqPhyc+jaze5H6n1/aQ3BAS41VaYhiUUufSIRMALoHNIB/rUGosnGKgoPeLygbFMn/ezXAej+vAfvCo8qsyaxCVHMo0EO8kXiUvHLXevQwYdWEqWEVCMAHlpAM5McL57IbqarUECEcUu1ZVRXcOSMzkhU6msJCH" |
045 | "ACLYgk3PY+pnh+NlpunkO7eEy204upEGClpsbBER8bLpBfgg54wM+lGcojWUFE3KukRh8o0OUTjPnPNRzxc62xyaRyo3rVbh9dCC/xZDi6x5MuOiYhVeECxoSZYNQQ+YsVsL2XaYqZc6uWjETFJw7686/Eqy2h9MvzSC/DF3Ngs8qiGWfKfRGHDPACo7TdLTkfBjVxVp" |
046 | "lufQf1+H5/PhNxcMs3d2eYeyepqFDIpeJpgbrMt2tRPSWdKyJRodHPHfSzvpi2Pa8CzhGxoYN6pD5Hvnpp/r+/DsgxTRqQLC/5EcUBVONUWwGWnEFhBaJiHyse9Ek9cZJZY9dI2+8+7aJ/uss70iDBzwovNgVbQ5ljGEnBK4ejD2gElyGpaR4Z9niktb/4fdgeQemdOt" |
047 | "Kml7KFyO73sCu39h72Z7uQgBPEV5qDH55IMtuaCCj44q1ix4vy74MAtJWcy/YexkvzOjUBvmInJPRQ/D27vO+1Zd7xEeSEX9X73z4eydI4k7AmRRMtuKPhvG08tFVL/7g46vjxSQoqt0w3pBYhTnj6YGDlFz2IQJNqItywuYu6dWvvF5mUejyK6kfjXR15L4bY0j0494" |
048 | "kM322LwDvVJNgoVOxoMHrXTu+Pv/S83BTc2cM093EtfVy9h0UY/5Mdngf2+E+OcOULsdNNI8dR2cuYADQxnKw1i8pyNr/oYiht/DQw+tpts6w7e5kDqWdboPBxmylm9aOiyAiSvhsp3rqkQuqGRfOzUML9XjbnWQz0p02dVNfQ4W9I0AuNwda0izOgz8AOTBkcM2SSA1" |
049 | "MySIeeTJTh0QO6DFSvkhgh4A29dixJuAG+cljzkwNICGeZrnhkwRi+cSycdEFPekBPP3Ggz1ucgbcUIPVqwqbLN/4YEaA+Ht3n7xyJcoU39Ov9/h09TAGctDwgkTXOqC6S0upHF8X/8DP3X9vCfCZfCJc7I9E7dni3uZlCuGg5AgYQL5c2DTx/OPDno+HiNxq0zzSr5l" |
050 | "uVxvMr9ONMGvirsiMDghDiBVgBpn1LF/V+O1VMzzkpKgzql5e5JLL+jhB0n/90STgoE1RipSm210dDaknpuxY+TgixQkdsCPf00gSg8c4q1/12cZlE1tEAd/O23ujpVJ0KBvrkaScoHlAVN0w3/3iOTZKnSRaNy1BUHZ8KshyVFFMAlENNbPOIRJaWJGrt2gya9h8Ydh" |
051 | "05Ozb5qmiqpWMNRRwuPZMAVqb09zyFLIRsqdbc/IMDZJ1XoZfNtEKWTUcuGOGeLgSVZXopWkKwNGAbYNq41D+8GHfGn4k3KsMuxQMp5Awrmcotk59NjIQKAnQ7+WBwc+aWTuqBvf6Mjh/uHm9SXz/NPN+pk4fc/Kyw1c2sbQqiJueU666bZkmVx5vHQl5WvLXaIo/648" |
052 | "/rx8J7+1dT1rn0100zy8XBnz8cCcjrOVEk6NdzXXq06CmK/3sX1RXm5aYG8NKZdk1duX6SWc3wqq96md0eho9vhPxwVpnu90vK5eNBsuAEfn+zO+PgHEr89KKyOY7hQ+mNfu6mbb3fcOnXwB9JwdazDX07PeyrS10D84bwOR/YI7UQhOL2WdYbZyrfr0AhHtjt3XpKGr" |
053 | "m7pdoCEmGFwpxgj0VmT+z3f9RBIQtw8s0JxrtqbPDRcCuiEVzd08vcs8ubKTTICqwoPnKW458mKTtclW4IWHXkP08ypX8FmLxuqllm6pCPfXivb/U+v7yyfpZDC0fcy/LNQa45wJ3sZx1hXUtQ+sIffokzCbUOXTTWWrxKrEloAAAnV8y09lDCTV/0Xrrx1IrPe8JRAS" |
054 | "6PPIxs0xI/mWMFRWsO9X1746mrP3W3BjhI6FWTTQWRrYlG9QVxO2UHyUKjfGeSMX03xNXaWJXQbm8dC2/qouH9v9OmbNDDpcN93PWf9fzrZz03b/N4YuNW8HV/uceHM/jhzoHuI0+UlBvUzth+Lx1BTLVK25fkSXkZOJpbJn2YblMXdTQYNZNEUzDa4OMsWqLGIWnY2Q" |
055 | "4dcjjoY988HmYEEZ302a8DyBjilv9EDGRg2TiDWTNI0eARMM0qrUJI8xLUyxJ7GFWOxOI13LyhI/JOW/it42HUR6MijKT0ix96xVOJJztDUWldCiGFh0jCPNu0UldqDw1OzCBztSh9mQt9fIBlH8ND5Zk0BNiYEGvcw34O78Ul/OukeCoq2PUFmFiA+Vo+dIv5ELKAH6" |
056 | "ZYhyqD5lXyEjRopRtnWOTJjpZAdM3BwDOHAp900QNVikeyc6peRuiN7YGsjvnDEy0aKDIfI7ipwQ6Ewr17IvLv2z3Q2XIm4GaCtIRK9NAC3rX9FH3fLu/mLmnOQoZOisaJEJdv4I1CXDbBMNkyZK/ecLIWlOsWuXSp6EL5BpbuznXq3r+s4v559ukQDUK6NDyvfiTNLc" |
057 | "yLRwKSEM116NBl5tqlNUiQixNDR43Ri3GVE1QWLQl5uXqyCZ3945OU/GwPI3zZw5wIK0umkMVFYw1GDbG5m87zs5LI5DsT5VH7QSSp4C/m2lO9CHd/2E7tcCvGHoW7ssr04lLXEwuds+zaVG5OKu1xKDZeCssAAcNfHH/tSznp8ORC55sXjvnZXDve/nRDX2K58XbwCJ" |
058 | "/GQ/PrT0ZStVw2QHmvnGiakbC+NEmeVRbNFZXGVMIV5IQ7d3pebAzKnQhAGy4ba1i71DWvLHmAmYr6/X4OlhBWf7ZVC+2DZyEvqdyOt9vC646GG3zskrEGmPNhggOmrp1ieqzOiYb5TUPAnd8iKkjxDdOTLExM3gB31Nggh0oiDqgPfnDa/9QSWr7JvWqXd1OnsrUFd9" |
059 | "9ba08qRCmqL62HCnACzM3CMXqnXs3xYlMfR6a4/dNO+tWW0G3bPDtO0RdPMMY3J5Q9HN1bZllBNCzvdndeo89ohTtmW8uSDcMkzxaGadVce6Kmh9c3z6mFU4soHJlt72H+a5//pSZl+zWiTRh6+TgeyQiU4GOFrojki1850YjItJfhoX2Ua/1AGQaKgayh4F87Bk9LXD" |
060 | "rOIIll7IbLK40rqq1dFL/yi956L5vPhg4IJCLByyqNSnooUrYBSnDRuOHrnE1a4slFZf+zpPyZb5RVxJZ4oGA7+xdpo9pJNzKnKjxE6GBMbU23S04FXIRhM5hwoP9jtvX++fby2LoPGfKiInkzPoq3bKz+7hrbAS+7ut4PPyuVFGcJxEy3VFtTLchISRbw0AInfA0lEQ" |
061 | "PH4yeV1aQhx5ukVdD4TUQilnkoKkILSUdDkaoCKNJer2Qr5Bv2+rhhe7PRJaGzl08ywQtTTsUiDYIgvLRASA6M6tZqK9yIZxsCx7JYM5QejCh+f6p5eupFUenIgi5Ys6gs3sYhftwXWxKFesIC3lljvW+e/Rfz7PLVbd100l14Q3XxEMAdH3jgSMJ+Fbzlo9i6D0Q86K" |
062 | "e4E2HOcsmiq7a6aShVODqoW2dEoqnWrp0T91OyyBoo+I3TLFdNTrfgPB1ZAIqyap5tQDZQ7b+0htyxOAah7Q+mWb472SSbgl09zIvNwaRjYqm6IYBIWf48R4gTGuP2jMpAZtvc9N5eBqSsPd/1q7MdzywuQ7C28SS1pZtGrlMRTxCqc1z6l5a5Xlg6+HsawbySR1ZAVv" |
063 | "Bdbq7O8BmgwVGHNPhtQ987xwe/0AJ2fjTdMsemtWoJuIsdFP+lm0ZcHb/qGXW4ZooZNlhQievbqYH1DQYtcd0UM5w9eB7vtUVQpX+ZbIJlAFkImEBrXbluQbm0Qnenm26Q16QRcAvMS8borRoC6vHzU/RnXZIIo9ywNovHJPkkVIQX3mgNZ65YDLgNfvXDCxxpOqCMrM" |
064 | "iCiN67ywvZGehQYAV9QUNIXYMXRDCBK8MaEzWXs8ZT8ZcGeipyAAZuk5M4liURvW9A7PE6HCOUQaDDCoPnB25OhJxbNnAZyAcXOOpiLZQeWZEFwB7fucML4zXA1/8PIAh5apGzzpXVavMMOmsAyPSxcxwLXbpkGvyMBOoBLfFonSNLpoBsJUsGw4v370Z/POPlC3WG77" |
065 | "Zqnv38/vH1bDAysgDw9Ui9b0t3aX0reERAhe068qlFZYhDRtTqIyYLwAP/2xR8vjFoOAMFDGoE4dqv65yOof52NsiFLBkbO6inDvUVZIdR0QCv7LLxBvhTuW2JyZ0soCMcfXCvrymQfI9eCeLuWtu3JypedA7IiywAkvXa0dCrLSGId2n2SVQP5Mwt091ba5uS3/eX8y" |
066 | "ULwPMI+p8/Ejjo40pNxODNIvC+aYZleZUp/80dBSBLBnJ5ozX0SmsoyImlQBnKgxjgqirT96aY4wct8kHByJJBxXrl+yci8uzLaQGkCR7B2WW6n9bYKozS97CVC3mjwGTJ8DLCR+0RxMldFA/ZLxppeJFRSyxw6m6qts7K+9uciRgVsmT4GGFnD/1uW6QpwLH8CCLbkQ" |
067 | "KihHC6yqJeWmH4VqVxxqj93wyjSJYMVAMexsZOarubaeyTxllRk4LUBVkJKnGcQb3Qpb94gmGGRTs27w3F6THqZA0AdfPQ/J5eZo+XbfZzzeEolDBMwYiIk0SGkL6GO8+hrSuXvqg+3qTRq4nRE9t4FI+seOCVAVY4GuC6RzjBZ1QT062aSvPAmqWi4vSQdYbiTAlUSg" |
068 | "Aq1f8BMr8ZSHtbbjwAAAAASUVORK5CYII=\" />" |
072 | "<span style=\"font-size:28px\"><strong> Осушитель 2.0</strong></span>" ; |
076 | const char indexMain1[] = |
078 | "<form action=\"/get\"enctype=\"text/plain\"id=\"network\"method=\"get\"name=\"Настройки\">" |
079 | " <table rules=\"none\"cellspacing=\"0\"cellpadding=\"2\"border=\"0\"width=\"640\">" |
080 | "<caption>Настройки</caption>" |
082 | "<th align=\"left\">Наименование параметра</th>" |
083 | "<th align=\"left\">Значение</th>" |
087 | const char indexMain2[] = |
090 | "<p><input name=\"send\" type=\"submit\"value=\"Применить\" /></p>" |
094 | const char indexMain3[] = |
101 | const char ChartHeader[] = |
104 | "<script type=\"text/javascript\" src=\"<a href=" https: |
105 | "<script type=\"text/javascript\">" |
106 | "google.charts.load('current', {'packages':['corechart']});" |
107 | "google.charts.setOnLoadCallback(drawTemp);" |
108 | "google.charts.setOnLoadCallback(drawAbsH);" ; |
110 | const char startTemp[] = |
111 | "function drawTemp(){" |
112 | "var data=google.visualization.arrayToDataTable([" |
113 | "['Время','Подпол','Улица']," ; |
114 | const char endTemp[] = |
117 | "title:'Температура C°'," |
118 | "titleTextStyle:{fontSize:16}," |
120 | "legend:{position:'bottom'}," |
121 | "colors:['red','green']," |
122 | "chartArea:{left:40,top:20,width:'99%',height:'80%',backgroundColor:'#FAFAF5'}" |
124 | "var chart=new google.visualization.LineChart(document.getElementById('Temp_chart'));" |
125 | "chart.draw(data,options);" |
128 | const char startAbsH[] = |
129 | "function drawAbsH() {" |
130 | "var data=google.visualization.arrayToDataTable([" |
131 | "['Время','Подпол','Улица']," ; |
132 | const char endAbsH[] = |
135 | "title:'Абсолютная влажность г/м*3'," |
136 | "titleTextStyle:{fontSize:16}," |
138 | "legend:{position:'bottom'}," |
139 | "colors:['red','green']," |
140 | "chartArea:{left:40,top:20,width:'99%',height:'80%',backgroundColor:'#FAFAF5'}" |
142 | "var chart=new google.visualization.LineChart(document.getElementById('AbsH_chart'));" |
143 | "chart.draw(data,options);" |
146 | const char ChartBotton[] = |
150 | "<table class=\"columns\">" |
152 | "<td><div id=\"Temp_chart\" style=\"width:500px;height:300px\" \"border: 1px solid #ccc\"></div></td>" |
153 | "<td><div id=\"AbsH_chart\" style=\"width:500px;height:300px\" \"border: 1px solid #ccc\"></div></td>" |
DHT.h
035 | #define simpleDHTCombileError(t, err) ((t << 8) & 0xff00) | (err & 0x00ff) |
036 | #define SimpleDHTErrSuccess 0 // Success. |
037 | #define SimpleDHTErrStartLow 0x10 // Error to wait for start low signal. |
038 | #define SimpleDHTErrStartHigh 0x11 // Error to wait for start high signal. |
039 | #define SimpleDHTErrDataLow 0x12 // Error to wait for data start low signal. |
040 | #define SimpleDHTErrDataRead 0x13 // Error to wait for data read signal. |
041 | #define SimpleDHTErrDataEOF 0x14 // Error to wait for data EOF signal. |
042 | #define SimpleDHTErrDataChecksum 0x15 // Error to validate the checksum. |
043 | #define SimpleDHTErrZeroSamples 0x16 // Error when temperature and humidity are zero, it shouldn't happen. |
044 | #define SimpleDHTErrNoPin 0x17 // Error when pin is not initialized. |
048 | long levelTimeout = 5000000; |
063 | virtual int read( byte * ptemperature, byte * phumidity, byte pdata[40]); |
064 | virtual int read( int pin, byte * ptemperature, byte * phumidity, byte pdata[40]); |
067 | virtual int read2( float * ptemperature, float * phumidity, byte pdata[40]) = 0; |
068 | virtual int read2( int pin, float * ptemperature, float * phumidity, byte pdata[40]) = 0; |
072 | void setPin( int pin ); |
080 | virtual long levelTime( byte level, int firstWait = 10, int interval = 6); |
083 | virtual byte bits2byte( byte data[8]); |
088 | virtual int sample( byte data[40]) = 0; |
091 | virtual int parse( byte data[40], short * ptemperature, short * phumidity); |
106 | class SimpleDHT11 : public SimpleDHT { |
109 | SimpleDHT11( int pin); |
111 | virtual int read2( float * ptemperature, float * phumidity, byte pdata[40]); |
112 | virtual int read2( int pin, float * ptemperature, float * phumidity, byte pdata[40]); |
114 | virtual int sample( byte data[40]); |
129 | class SimpleDHT22 : public SimpleDHT { |
132 | SimpleDHT22( int pin); |
134 | virtual int read2( float * ptemperature, float * phumidity, byte pdata[40]); |
135 | virtual int read2( int pin, float * ptemperature, float * phumidity, byte pdata[40]); |
137 | virtual int sample( byte data[40]); |
DHT.ino
024 | SimpleDHT::SimpleDHT() { } |
026 | SimpleDHT::SimpleDHT( int pin) { setPin(pin);} |
028 | int SimpleDHT::read( byte * ptemperature, byte * phumidity, byte pdata[40]) { |
029 | int ret = SimpleDHTErrSuccess; |
030 | if (pin == -1) { return SimpleDHTErrNoPin; } |
031 | float temperature = 0; |
033 | if ((ret = read2(&temperature, &humidity, pdata)) != SimpleDHTErrSuccess) { return ret; } |
034 | if (ptemperature) { *ptemperature = ( byte )( int )temperature; } |
035 | if (phumidity) { *phumidity = ( byte )( int )humidity; } |
039 | int SimpleDHT::read( int pin, byte * ptemperature, byte * phumidity, byte pdata[40]) { |
041 | return read(ptemperature, phumidity, pdata); |
044 | void SimpleDHT::setPin( int pin) { this ->pin = pin;} |
047 | long SimpleDHT::levelTime( byte level, int firstWait, int interval) { |
048 | unsigned long time_start = micros(); |
051 | for ( int i = 0 ; loop ; i++) { |
052 | if (time < 0 || time > levelTimeout) { return -1; } |
055 | if (firstWait > 0) {delayMicroseconds(firstWait); } |
056 | } else if (interval > 0) {delayMicroseconds(interval); } |
061 | time = micros() - time_start; |
062 | loop = (digitalRead(pin) == level); |
067 | byte SimpleDHT::bits2byte( byte data[8]) { |
069 | for ( int i = 0; i < 8; i++) { v += data[i] << (7 - i); } |
073 | int SimpleDHT::parse( byte data[40], short * ptemperature, short * phumidity) { |
074 | short humidity = bits2byte(data); |
075 | short humidity2 = bits2byte(data + 8); |
076 | short temperature = bits2byte(data + 16); |
077 | short temperature2 = bits2byte(data + 24); |
078 | byte check = bits2byte(data + 32); |
079 | byte expect = ( byte )humidity + ( byte )humidity2 + ( byte )temperature + ( byte )temperature2; |
080 | if (check != expect) { return SimpleDHTErrDataChecksum; } |
081 | *ptemperature = temperature<<8 | temperature2; |
082 | *phumidity = humidity<<8 | humidity2; |
083 | return SimpleDHTErrSuccess; |
086 | SimpleDHT11::SimpleDHT11() {} |
088 | SimpleDHT11::SimpleDHT11( int pin) : SimpleDHT (pin) {} |
090 | int SimpleDHT11::read2( float * ptemperature, float * phumidity, byte pdata[40]) { |
091 | int ret = SimpleDHTErrSuccess; |
092 | if (pin == -1) { return SimpleDHTErrNoPin; } |
094 | if ((ret = sample(data)) != SimpleDHTErrSuccess) { return ret; } |
095 | short temperature = 0; |
097 | if ((ret = parse(data, &temperature, &humidity)) != SimpleDHTErrSuccess) { return ret; } |
098 | if (pdata) { memcpy(pdata, data, 40); } |
099 | if (ptemperature) { *ptemperature = ( int )(temperature>>8); } |
100 | if (phumidity) { *phumidity = ( int )(humidity>>8); } |
102 | if (temperature == 0 && humidity == 0) { return SimpleDHTErrZeroSamples; } |
106 | int SimpleDHT11::read2( int pin, float * ptemperature, float * phumidity, byte pdata[40]) { |
108 | return read2(ptemperature, phumidity, pdata); |
111 | int SimpleDHT11::sample( byte data[40]) { |
124 | pinMode(pin, OUTPUT); |
125 | digitalWrite(pin, LOW); |
131 | digitalWrite(pin, HIGH); |
133 | pinMode(pin,INPUT_PULLUP); |
134 | delayMicroseconds(25); |
139 | long t = levelTime(LOW); |
141 | return simpleDHTCombileError(t, SimpleDHTErrStartLow); |
146 | return simpleDHTCombileError(t, SimpleDHTErrStartHigh); |
154 | for ( int j = 0; j < 40; j++) { |
157 | return simpleDHTCombileError(t, SimpleDHTErrDataLow); |
162 | return simpleDHTCombileError(t, SimpleDHTErrDataRead); |
164 | data[ j ] = (t > 40 ? 1 : 0); |
171 | return simpleDHTCombileError(t, SimpleDHTErrDataEOF); |
174 | return SimpleDHTErrSuccess; |
177 | SimpleDHT22::SimpleDHT22() {} |
179 | SimpleDHT22::SimpleDHT22( int pin) : SimpleDHT (pin) {} |
181 | int SimpleDHT22::read2( float * ptemperature, float * phumidity, byte pdata[40]) { |
182 | int ret = SimpleDHTErrSuccess; |
183 | if (pin == -1) { return SimpleDHTErrNoPin; } |
185 | if ((ret = sample(data)) != SimpleDHTErrSuccess) { return ret; } |
187 | short temperature = 0; |
189 | if ((ret = parse(data, &temperature, &humidity)) != SimpleDHTErrSuccess) { return ret; } |
190 | if (pdata) {memcpy(pdata, data, 40); } |
191 | if (ptemperature) {*ptemperature = ( float )((temperature & 0x8000 ? -1 : 1) * (temperature & 0x7FFF)) / 10.0; } |
192 | if (phumidity) {*phumidity = ( float )humidity / 10.0; } |
196 | int SimpleDHT22::read2( int pin, float * ptemperature, float * phumidity, byte pdata[40]) { |
198 | return read2(ptemperature, phumidity, pdata); |
201 | int SimpleDHT22::sample( byte data[40]) { |
209 | pinMode(pin, OUTPUT); |
210 | digitalWrite(pin, LOW); |
216 | digitalWrite(pin, HIGH); |
218 | pinMode(pin, INPUT_PULLUP); |
219 | delayMicroseconds(40); |
224 | if ((t = levelTime(LOW)) < 30) { |
225 | return simpleDHTCombileError(t, SimpleDHTErrStartLow); |
227 | if ((t = levelTime(HIGH)) < 50) { |
228 | return simpleDHTCombileError(t, SimpleDHTErrStartHigh); |
235 | for ( int j = 0; j < 40; j++) { |
238 | return simpleDHTCombileError(t, SimpleDHTErrDataLow); |
244 | return simpleDHTCombileError(t, SimpleDHTErrDataRead); |
246 | data[ j ] = (t > 40 ? 1 : 0); |
253 | return simpleDHTCombileError(t, SimpleDHTErrDataEOF); |
255 | return SimpleDHTErrSuccess; |
Конструктивная критика приветствуется, особенно по коду.
Классно, конечно, но интернет зачем? Имхо без нета кошернее.
Мне проще сделать управление и настройку прибора через веб морду, чем на экране менюшки городить. И кнопок не надо-)))
Скорость разработки выше, плюс бонусом удалённый мониторинг.
Это не код, это лютый писец какой-то.
А чем код то не нравиться?
за printf(...), dtostrf() и другие стандартные функции слышал чонить?
да что printf ...
Pv2000 - вы в курсе, что для вывода на печать шестнадцатиричных чисел достаточно написать
Serial.print(value, HEX) ?
К чему у вас там эти зубодробительные функции типа uint32_to_HEX ? :)
Маленькое задание для шибко умных
Сделайте маленькую программу со стандартными функциями и потом с моими.
Выпишите на листок размер кода и максимальный размер стека для обоих вариантов.
Медитируете на эти числа и наступит Вам просветление, зачем это сделано.
По поводу вывода hEX посмотрите что выводит ваш вариант и что мой, если разницы нет то конечно все равно, но разница есть.
Ихмо Вот как раз использование стандартной printf в микроконтроллерах это боль.
какая то доля истины в ваших словах конечно есть, но писать три функции uintXXToHex вместо одной мне кажется перебор
01
void
writeLOGhex(
const
unsigned
long
inHex){
// преобразует число в шестнадцатеричную строку и кладет на отправку
02
unsigned
long
tmHex = inHex;
// сохраняем число во временную переменную
03
char
hexBuf[20];
// строковый буфер где мы будем сохранять текст
04
unsigned
char
i = 0;
// позиция строкового буфера
05
do
{
06
unsigned
char
k = tmHex % 16;
// остаток от деления на 16 временного числа
07
if
(k > 9) hexBuf[i++] = k +
'7'
;
else
hexBuf[i++] = k +
'0'
;
// кладем в строковый буфер цифру или букву, если число больше 9
08
}
09
while
((tmHex /= 16) > 0);
// до тех пор, пока деленное на 16 временная переменная больше нуля
10
if
(i % 2) hexBuf[i++] =
'0'
;
// если коичество символов не четное - добавлем нолик слева (на самом деле справа буфера)
11
hexBuf[i] =
'\0'
;
// заканчиваем строку нулем
12
for
(unsigned
char
j=i; j>0; --j) {
// бежим циклом по строке в обратном порядке
13
writeLOGbyte(hexBuf[j-1]);
// и кидаем байты в отправляемый буфер
14
}
15
}
По поводу вывода hEX посмотрите что выводит ваш вариант и что мой, если разницы нет то конечно все равно, но разница есть.
а поподробнее? что там стандартный принт не выводит? "0x" в начале числа не ставит? :)
нолик в начале не выводит если количество символов не четное и нолик перед x тоже не выводит
ЗЫ. И то не факт, может я ей просто пользоваться не умею
нолик в начале не выводит если количество символов не четное и нолик перед x тоже не выводит
беда :)
и ради этого надо писать отдельное преобразование для каждого hex разряда? (8 одинаковых строк для uint32 ?) Циклы уже не модны?
Конструктивная критика приветствуется, особенно по коду.
просили - получите
и ради этого надо писать отдельное преобразование для каждого hex разряда? (8 одинаковых строк для uint32 ?) Циклы уже не модны?
ну может человеку каждый такт и байт МК на вес золота, не хочет цикл делать :)
ну может человеку каждый такт и байт МК на вес золота, не хочет цикл делать :)
а не проще было написать что-нить типа
1
void
hex_to_print(uint32_t val) {
2
Serial
.print(
"0x"
);
3
Serial
.print(val, HEX);
4
}
ну может человеку каждый такт и байт МК на вес золота, не хочет цикл делать :)
а не проще было написать что-нить типа
1
void
hex_to_print(uint32_t val) {
2
Serial
.print(
"0x"
);
3
Serial
.print(val, HEX);
4
}
Так вам уже писали - попробуйте и сравните результат.
Так вам уже писали - попробуйте и сравните результат.
что я должен там увидеть?
У меня сейчас нет под рукой ардуины. но предположу, что всей разницы то
print("0x"); print(255, HEX);
выдаст на выходе 0xFF. а функция ТС - 0x00FF в случае uint16
Вы правда считаете, что ради этого надо было городить три отдельных функции с повторяющимися строчками?
Что мешало написать нормальный вывод с нужным число нулей, независмый, кстати, от типа входящей переменной?
Неужели вы на полном серьезе считаете реплики DetSemen конструктивной критикой?
ну может быть резковато, но вообще все по теме. Человек просил покритиковать код - критикуем.
Даже такая критика, хоть и обидная - дает (умному) человеку пищу для ума Может быть он не подозревает, что существуют иные пути решения каких-то задач. Например в случае с преобразованием HEX - это очевидно из кода
DetSemen - это вообще не критика а просто балаган. По поводу hex критику принимаю, перепишу функцию.
по hex -мне нужно три варианта работы 1,2,4 (3,5 байт не интересно) байта с результатом в буфере.
Вариант andycat не нравится, тоже далеко до оптимальности, размер большой и скорость. Мой вариант точно быстрее и скорее всего по размеру может оказаться меньше.
Вариант b707 не подходит мне нужно в буфер
По поводу printf добавлю (в стиле DetSemen без пояснений) посмотрите механизм распределение памяти задач для free RTOS, и тогда поймете вредность функций с большим стеком.
А в этой rtos всё по честному со всякими там потоками, семафорами и тд?
далеко до оптимальности, размер большой и скорость. Мой вариант точно быстрее и скорее всего по размеру может оказаться меньше.
посмотрите механизм распределение памяти задач для free RTOS, и тогда поймете вредность функций с большим стеком.
особенно понравился util.ino. До слёз пробирает.
ПыСы: Ты за printf(...), dtostrf() и другие стандартные функции слышал чонить?
Вот смех смехом, а я недавно попытался в одном из своих проектов воспользоваться printf(). Прошивка сразу увеличилась на 14к и вылезла за пределы 64к. В общем, от printf() я отказался и заменил его самописной функцией на 300 байт, которая делает ровно то, что мне нужно, и ничего сверх этого.
Так что использование в МК написанных для ПК "стандартных функций" не всегда целесообразно, а иногда и совершенно невозможно.
pav2000, Вы не обижайтесь - подскажите, какой у вас опыт в программировании на Си вообще и микроконтроллеров в частности? По коду я бы сделал предположение, что вы любитель, освоивший Си не так давно.
На критику не обижаюсь она весьма полезна но она должна быть обоснованной и корректной.
Опыт написания на Си более 10 лет, микроконтроллеры 4-5 лет, но не в очень интенсивном режиме. Да мой стиль далек от идеала. И я допустил ошибку портируя старый проект в новый, надо было с нуля писать (хотелось просто побыстрее написать код).
Размер кода можно оценить по изменению бинарника, (с нужным кодом и без) именно так и был выявлен объем кода printf.
Размер стека можно оценить отладочными средствами ОС. Вот пример (фрагмент вебморды с четырех поточным web сервером) правда из другого проекта но он отражает возможности отладки freeRTOS
Быстродейстие - на глазок.
-NMi-
"А в этой rtos всё по честному со всякими там потоками, семафорами и тд?"
Да это присутствует, есть еще и очереди. Более того скажу что без семафоров и мютексов не обойтись при делении аппаратных ресурсов (в этом проекте spi делится между двумя задачами).
andriano
"Вот смех смехом, а я недавно попытался в одном из своих проектов воспользоваться printf(). Прошивка сразу увеличилась на 14к и вылезла за пределы 64к. В общем, от printf() я отказался и заменил его самописной функцией на 300 байт, которая делает ровно то, что мне нужно, и ничего сверх этого."
Вот и я про это, у меня тоже есть самописный принтф который реализует только то что мне нужно и имеет размер 1-1.5кб и стек бережно расходует.
Для понимания еще добавлю о распределении памяти в rtos.
1. Каждая задача имеет свой стек. Размер которого задается при создании задачи:
1
xTaskCreate(vReadSensor,
"ReadSensor"
,150,NULL,4,&hReadSensor);
150 это размер стека в 4 байтных словах. Размер стека определяется опытным путем, и надо понимать что это сложная задача т.к. алгоритм может быть сложным и по некоторым веткам при отладке можно не пройтись. По этому нужен запас.
2. Если стек по факту получается больше отведенного то все падает или есть не адекватное поведение.
3. В RTOS есть механизм контроля стека (включается отдельно) и при отладке можно получить минимальный размер (зарезервировано-максимальный стек по факту) стека (включается отдельно) см. картинку выше.
4. Из все выше сказанного получается следующее: Допустим есть три задачи с требуемыми объемами стеков 100 слов (4 байта). Есть функция printf которая требует 250-300 слов на стек. Мы эту функцию используем для вывода отладочных сообщений и используем во всех трех задачах. Как итог получается что требуемый объем стеков для всех трех задач 100+250 слов как минимум.
Уж если мы полезли в такие дебри скажу что реализация spi в ардуиновской версии не совсем адекватная.
Если посмотреть на схему то у меня сеть висит на одном spi а дисплей на втором spi, это сделано специально -я хотел работать параллельно. т.е делать вывод одновременно (конечно переключаясь) в оба устройства. Это возможно. Но в ардуиновской версии библиотек при каждом использовании spi надо указывать с каким spi работать будем, что есть не гуд т.е надо переключать spi.
DetSimen
"Ладно, pav-лик, я больше не буду лезть с бессмысленными комментариями кода, извини."
принимается.
Подскажите пожалуйста как можно приобрести плату для сборки вашего устройства?
Пишите на почту nscalp@mail.ru, договоримся
Аппаратная часть полностью переделана. Теперь используется STM32 и сетевой чип wiznet w5500.
Для начала были бы не плохо описать, а что именно вы собираетесь делать?
Обсуждать равно ли 2+2 четыре, неинтересно и некоструктивно. Что касается кода. Если скетч комилируется, значит код верный что тут обсуждать.?
То есть подвал сухой силами одного вентелятора и датчика DHT? ;) И это тоже возможно, я просто уточняю:)