Контроль влажности подвала Arduino pro mini
- Войдите на сайт для отправки комментариев
3. Конструктив.
Корпус напечатан на 3Д принтере (нижняя часть склеена из двух частей). Очень удобно, все отверстия сразу сделаны, только заусецы счистить и можно использовать. Получилось достаточно компактно. Вся электроника кроме входных цепей распаена на макетке, проводом (по времени один вечер).
Замечанные косяки -
1. На дисплее появляются "не штатные" точки на графике (скоре всего помехи по SPI после перерисовке экрана они проподают),
2. Кнопка иногода "не четко" срабатывает проблемы с длительным нажатием.
3. nrf24 в блоке ожидает "квитанции" о приеме пакета иногда "квиатнция" не приходит (30-40%) но пакет доставляется до приемного устройства.
4. Уличный датчик DHT-22 показания влажности прыгают утром (ветер, солнце?). Датчик менял.
Конструктивная критика приветсвуется, особенно по коду.
Фото готового устройсва для пояснения:
Код программы:
#include <SPI.h> #include <EEPROM.h> #include <avr/wdt.h> #include <leOS.h> // Шедуллер задач #include <dht.h> // Дачик влажности и температуры #include "Ucglib.h" // справка https://code.google.com/p/ucglib/wiki/ #include "rusFont.h" // Русские шрифты #include "nRF24L01.h" // Беcпроводной модуль #include "RF24.h" // Беcпроводной модуль //#define DEBUG // Отладочную информацию в ком порт посылает //#define DEMO // Признак демонстрации - данные с датчиков генерятся данные #define BEEP // Использовать пищалку #define RADIO // Признак использования радио модуля #define dH_OFF 15 // Гистерезис абсолютной влажности в сотых грамма на куб #define dT_OFF 25 // Гистерезис температуры в сотых градуса #define TIME_SCAN_KEY 120 // Время опроса кнопок мсек #ifdef DEMO // Для демо все быстрее и случайным образом #define NUM_SAMPLES 2 // Число усреднений измерений датчика #define TIME_SCAN_SENSOR 2000 // Время опроса датчиков мсек, для демки быстрее #define TIME_PRINT_CHART 8000 // Время вывода точки графика мсек, для демки быстрее #define TIME_HOUR 50000 // Число мсек в часе, для демки быстрее #else #define NUM_SAMPLES 5 // Число усреднений измерений датчика #define TIME_SCAN_SENSOR 3000 // Время опроса датчиков мсек #define TIME_PRINT_CHART 300000 // Время вывода точки графика мсек #define TIME_HOUR 3600000 // Число мсек в часе #endif #define VERSION "Version: 0.51 03/08/15" // Текущая версия #define ID 0x22 // уникально Идентификатор устройства - старшие 4 бита, вторые (младшие) 4 бита серийный номер устройства #define NUM_SETTING 6 // Число вариантов настроек - 1 #define MOTOR_OFF 0 // Мотор выключен #define MOTOR_ON 1 // Мотор включен #define LONG_KEY 2000 // Длительное нажатие кнопки мсек, появляется Экран инфо #define SHORT_KEY 100 // Короткое нажатие кнопки более мсек #define NRF24_CHANEL 100 // Номер канала nrf24 // СИСТЕМАТИЧЕСКИЕ ОШИБКИ ДАТЧИКОВ для ID 0x21 #define TOUT_ERR 40 // Ошибка уличного датчика температуры в сотых долях градуса #define TIN_ERR 40 // Ошибка домового датчика температуры в сотых долях градуса #define HOUT_ERR -30 // Ошибка уличного датчика влажности в сотых долях % #define HIN_ERR +30 // Ошибка домового датчика влажности в сотых долях % // НОГИ к которым прицеплена переферия (SPI используется для TFT и NRF24 - 11,12,13) #ifdef BEEP #define PIN_BEEP 15 // Ножка куда повешена пищалка #endif #define PIN_RELAY 14 // Ножка на которую повешено реле (SSR) вентилятора - аналоговый вход A0 через резистор 470 ом #define PIN_CS 10 // TFT дисплей spi #define PIN_CD 9 // TFT дисплей spi #define PIN_RESET 8 // TFT дисплей spi #define PIN_CE 7 // nrf24 ce #define PIN_CSN 6 // nrf24 cs #define PIN_DHT22a 5 // Первый датчик DHT22 IN ДОМ #define PIN_DHT22b 4 // Второй датчик DHT22 OUT УЛИЦА #define PIN_KEY 3 // Кнопка, повешена на прерывание, что бы ресурсов не тратить #define PIN_IRQ_NRF24 2 // Ножка куда заведено прерывание от NRF24 (не используется) // АЦП ---------------------------------------- const long ConstADC=1126400; // Калибровка встроенного АЦП (встроенный ИОН) по умолчанию 1126400 дальше измеряем питание и смотрим на дисплей Ucglib_ILI9341_18x240x320_HWSPI ucg(/*cd=*/PIN_CD, /*cs=*/PIN_CS, /*reset=*/PIN_RESET); // Аппаратный SPI на дисплей ILI9341 leOS myOS; // многозадачность dht DHT; // Датчики bool infoScreen=false; // Признак отображениея иформационного экрана 1 - на экран ничего не выводится кроме информационного экрана bool flagKey=false; // Флаг нажатия клавиши bool pressKey=false; // Флаг необходимости обработки кнопки unsigned long time_key=0; // Время нажатия копки byte last_error=100; // Предыдущая ошибка<packet.error struct type_setting_eeprom // Структура для сохранения данных в eeprom { byte fStart = 0; // Какой набор настроек используется unsigned long hour_unit; // мото часы блок измеряется в интервалах вывода графика TIME_PRINT_CHART unsigned long hour_motor; // мото часы мотор измеряется в интервалах вывода графика TIME_PRINT_CHART }; volatile type_setting_eeprom settingRAM; // Рабочая копия счетчиков в памяти type_setting_eeprom settingEEPROM EEMEM; // Копия счетчиков в eeprom - туда пишем // пакет передаваемый, используется также для хранения результатов. struct type_packet_NRF24 // Структура передаваемого пакета 32 байта - это максимум { byte id=ID; // Идентификатор типа устройства - старшие 4 бита, вторые (младшие) 4 бита серийный номер устройства int tOut=-5000,tIn=-5000; // Текущие температуры в сотых градуса !!! место экономим int absHOut=55555,absHIn=55555; // Абсолютные влажности в сотых грамма на м*3 !!! место экономим int relHOut=55555,relHIn=55555; // Относительные влажности сотых процента !!! место экономим byte error; // Ошибка разряды: 0-3 первый датчик (00-ок) 4-7 второй датчик (00-ок) byte dH; // Порог включения вентилятора по абсолютной влажностив сотых грамма на м*3 int T; // Порог выключения вентилятора по температуре в сотых градуса bool motor=false; // Статус вентилятора char note[12] = "Arduino Pro"; // Примечание не более 11 байт + 0 } packet; struct type_sensors // структура для усреднения { int num; // сколько отсчетов уже сложили не болле NUM_SAMPLES long sum_tOut=-5000,sum_tIn=-5000; // Сумма для усреднения Текущие температуры в сотых градуса !!! место экономим long sum_relHOut=55555,sum_relHIn=55555; // Сумма для усреднения Относительные влажности сотых процента !!! место экономим int tOut=-5000,tIn=-5000; // Текущие температуры в сотых градуса !!! место экономим int absHOut=55555,absHIn=55555; // Абсолютные влажности в сотых грамма на м*3 !!! место экономим int relHOut=55555,relHIn=55555; // Относительные влажности сотых процента !!! место экономим } sensors; // Массивы для графиков byte tOutChart[120]; byte tInChart[120]; byte absHOutChart[120]; byte absHInChart[120]; byte posChart=0; // Позиция в массиве графиков - начало вывода от 0 до 120-1 byte TimeChart=0; // Время до вывода очередной точки на график. #ifdef RADIO // Радио модуль NRF42l RF24 radio(PIN_CE, PIN_CSN); //определение управляющих ног const uint64_t pipes[2] = { 0xF0F0F0F0E1LL,0xF0F0F0F0D2LL}; bool send_packet_ok=false; // признак удачной отправки последнего пакета #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////// // ПРОГРАММА /////////////////////////////////////////////////////////////////////////////////////////////////////////// void setup(){ #ifdef DEBUG Serial.begin(9600); Serial.println(F("DEBUG MODE")); #ifdef BEEP Serial.println(F("BEEP ON")); #else Serial.println(F("BEEP OFF")); #endif #ifdef RADIO Serial.println(F("RADIO ON")); #else Serial.println(F("RADIO OFF")); #endif #endif reset_sum(); #ifdef RADIO // Радио модуль NRF42l radio.begin(); radio.setDataRate(RF24_250KBPS); // выбор скорости radio.setPALevel(RF24_PA_MAX); radio.setChannel(NRF24_CHANEL); //тут установка канала radio.setCRCLength(RF24_CRC_16); // radio.setAutoAck(false); // выключить аппаратное потверждение // radio.enableDynamicPayloads(); // разрешить Dynamic Payloads // radio.enableAckPayload(); // разрешить AckPayload radio.setRetries(15,15); radio.openWritingPipe(0xF0F0F0F0E1LL); radio.openReadingPipe(1,0xF0F0F0F0D2LL); radio.startListening(); #endif #ifdef BEEP pinMode(PIN_BEEP, OUTPUT); // Настройка ноги для динамика digitalWrite(PIN_BEEP, LOW); #endif pinMode(PIN_KEY, INPUT); // Включена кнопка digitalWrite(PIN_KEY, HIGH); pinMode(PIN_RELAY, OUTPUT); // Реле digitalWrite(PIN_RELAY, LOW); pinMode(PIN_DHT22a, OUTPUT); // Датчик 1 digitalWrite(PIN_DHT22a, HIGH); pinMode(PIN_DHT22b, OUTPUT); // Датчик 2 digitalWrite(PIN_DHT22b, HIGH); reset_ili9341(); // сброс дисплея readEeprom(); // Прочитать настройки if (digitalRead(PIN_KEY)==0) // Если при включении нажата кнопка то стираем все { int i; settingRAM.fStart=0; settingRAM.hour_unit=0; settingRAM.hour_motor=0; ucg.setColor(255, 255, 255); print_StrXY(10,50,F("Сброс настроек и счетчиков")); for(i=0;i<3;i++) { delay(1000); ucg.print(F(" .")); } writeEeprom(); // Запись в EEPROM delay(1000); ucg.clearScreen(); } wdt_enable(WDTO_8S); // Сторожевой таймер Для тестов не рекомендуется устанавливать значение менее 8 сек. // Запуск задач по таймеру myOS.begin(); myOS.addTask(measurement,TIME_SCAN_SENSOR); // Измерение attachInterrupt(1, scanKey, CHANGE); // КНОПКА Прерывания по обоим фронтам print_static(); // распечатать таблицу Setting(); // Применить настройки measurement(); // Считать данные #ifdef BEEP beep(100); #endif } void loop() { // Обработка нажатия кнопки if (pressKey==true) // Кнопка { myOS.pauseTask(measurement); // Остановить задачи if (time_key > LONG_KEY) // Длительное нажатие кнопки printInfo(); // Вывод информационного экрана else if (time_key > SHORT_KEY) // Короткое нажатие кнопки { #ifdef BEEP beep(30); // Звук нажатия на клавишу #endif if (infoScreen==true) clearInfo(); // если информационный экран то стереть его else { if (settingRAM.fStart >= NUM_SETTING) settingRAM.fStart=0; // Кольцевой счетчик настроек else settingRAM.fStart++; // В противном случае следующая настройка Setting(); } } flagKey=false; // Подготовка к следующему нажатию time_key=0; pressKey=false; myOS.restartTask(measurement); // Запустить задачи } } void print_static() // Печать статической картинки { cli(); // Заголовок ucg.setColor(0, 0, 180); // ucg.drawBox(0, 0, 320-1, 23); ucg.setColor(250, 250, 250); ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT); print_StrXY(2,19,F("ОСУШИТЕЛЬ ID: 0x")); ucg.print( hex(packet.id >> 4)); ucg.print( hex(packet.id&0x0f)); #ifdef DEMO ucg.print(F(" demo")); #endif // Таблица для данных ucg.setColor(0, 200, 0); ucg.drawHLine(0,25,320-1); ucg.drawHLine(0,25+23*1,320-1); ucg.drawHLine(0,25+23*2,320-1); ucg.drawHLine(0,25+23*3,320-1); ucg.drawHLine(0,25+23*4,320-1); ucg.drawVLine(200-4,25,24+23*3); ucg.drawVLine(260,25,24+23*3); // Заголовки таблиц ucg.setColor(255, 255, 0); print_StrXY(180+30,25+0+18,F("Дом")); print_StrXY(250+20,25+0+18,F("Улица")); print_StrXY(0,25+23*1+18,F("Температура градусы C")); print_StrXY(0,25+23*2+18,F("Относительная влаж. %")); print_StrXY(0,25+23*3+18,F("Абсолют. влаж. г/м*3")); // Графики ucg.setColor(200, 200, 200); ucg.drawHLine(1,240-1,130); ucg.drawVLine(1,135,105); ucg.drawHLine(10+150,240-1,130); ucg.drawVLine(10+150,135,105); print_StrXY(10,135+0,F("Температура")); print_StrXY(20+150,135+0,F("Абс. влажность")); // надписи на графиках print_StrXY(128,154,F("+20")); print_StrXY(135,194,F("0")); print_StrXY(128,233,F("-20")); print_StrXY(296,164,F("15")); print_StrXY(296,194,F("10")); print_StrXY(296,223,F("5")); sei(); } void print_status() // Печать панели статуса Значки на статус панели { if (infoScreen==true) return; // если отображен информационный экран то ничего не выводим cli(); // 1. печать ошибки чтения датчиков print_error_DHT(); // 2. Признак включения мотора if (packet.motor==true) ucg.setColor(0, 240, 0); else ucg.setColor(0, 40, 0); ucg.drawBox(290-32, 5, 14, 14); #ifdef RADIO // 3. Признак удачной передачи информации по радиоканалу if (send_packet_ok==true) ucg.setColor(0, 240, 0); else ucg.setColor(0, 40, 0); ucg.setPrintDir(3); ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT); print_StrXY(290-40,20,F(">>")); ucg.setPrintDir(0); ucg.setFontMode(UCG_FONT_MODE_SOLID); #endif sei(); } void print_error_DHT() // Печать ошибки чтения датчиков выводится при каждом чтении датчика { if (infoScreen==true) return; // если отображен информационный экран то ничего не выводим // 1. печать ошибки чтения датчиков if (packet.error!=last_error) // если статус ошибки поменялся то надо вывести если нет то не выводим - экономия время и нет мерцания { cli(); last_error=packet.error; ucg.setColor(0, 0, 180); // Сначала стереть ucg.drawBox(290, 0, 26, 18); ucg.setPrintPos(290,18); ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT); if (packet.error>0) { ucg.setColor(255, 100, 100); print_StrXY(280,19,F("0x")); ucg.print( hex(packet.error >> 4)); ucg.print( hex(packet.error & 0x0f)); } else { ucg.setColor(200, 240, 0); ucg.print(F("ok")); } sei(); } } // вывод на экран данных (то что меняется) void print_data() { if (infoScreen==true) return; // если отображен информационный экран то ничего не выводим cli(); // Печать значений для дома ucg.setFontMode(UCG_FONT_MODE_SOLID); ucg.setColor(250, 0, 100); // Цвет ДОМА print_floatXY(200+0,25+23*1+18,((float)packet.tIn)/100); print_floatXY(200+0,25+23*2+18,((float)packet.relHIn)/100); print_floatXY(200+0,25+23*3+18,((float)packet.absHIn)/100); ucg.setColor(0, 250, 100); // Цвет УЛИЦЫ print_floatXY(260+4,25+23*1+18,((float)packet.tOut)/100); print_floatXY(260+6,25+23*2+18,((float)packet.relHOut)/100); print_floatXY(260+6,25+23*3+18,((float)packet.absHOut)/100); sei(); } // Печать графика на экране, добавляется одна точка и график сдвигается void printChart() { byte i,x=0; byte tInLast,absHInLast,tOutLast,absHOutLast; // Статистика по моточасам, время ведется в тиках графика а потом пересчитывается в часы при выводе. settingRAM.hour_unit++; if (packet.motor==true) settingRAM.hour_motor++; // Работаем через кольцевой буфер // Добавить новую точку в кольцевой буфер // Температура в доме. диапазон -25 . . . +25 растягиваем на 100 точек tInLast=tInChart[posChart]; // Сохранить точку для стирания на графике if (packet.tIn<=-2500) tInChart[posChart]=0; // Если температура меньше -25 то округляем до -25 if (packet.tIn>=2500) tInChart[posChart]=100; // Если температура больше 25 то округляем до 25 if ((packet.tIn>-2500)&&(packet.tIn<2500)) tInChart[posChart]=((2*packet.tIn)+5000)/100; // внутри -25...+25 растягиваем в два раза // Температура на улице. диапазон -25 . . . +25 растягиваем на 100 точек tOutLast=tOutChart[posChart]; // Сохранить точку для стирания на графике if (packet.tOut<=-2500) tOutChart[posChart]=0; // Если температура меньше -25 то округляем до -25 if (packet.tOut>=2500) tOutChart[posChart]=100; // Если температура больше 25 то округляем до 25 if ((packet.tOut>-2500)&&(packet.tOut<2500)) tOutChart[posChart]=((2*packet.tOut)+5000)/100; // внутри -25...+25 растягиваем в два раза // Абсолютная влажность в доме диапазон от 0 до 20 грамм на кубометр, растягиваем на 100 точек absHInLast=absHInChart[posChart]; // Сохранить точку для стирания на графике if (packet.absHIn>=2000) absHInChart[posChart]=100; else absHInChart[posChart]=(5*packet.absHIn)/100; // внутри 0...20 растягиваем в пять раз // Абсолютная влажность на улицу диапазон от 0 до 20 грамм на кубометр, растягиваем на 100 точек absHOutLast=absHOutChart[posChart]; // Сохранить точку для стирания на графике if (packet.absHOut>=2000) absHOutChart[posChart]=100; else absHOutChart[posChart]=(5*packet.absHOut)/100; // внутри 0...20 растягиваем в пять раз if (infoScreen==false) // если отображен информационный экран то ничего не выводим { cli(); for(i=0;i<120;i++) // График слева на право { // Вычислить координаты текущей точки x в кольцевом буфере. Изменяются от 0 до 120-1 if (posChart<i) x=120+posChart-i; else x=posChart-i; ucg.setColor(0, 0, 0); // Стереть предыдущую точку if (x-1<0) ucg.drawPixel(5+120-i,237-tInLast); else ucg.drawPixel(5+120-i,237-tInChart[x-1]); if (x-1<0) ucg.drawPixel(5+120-i,237-tOutLast); else ucg.drawPixel(5+120-i,237-tOutChart[x-1]); if (x-1<0) ucg.drawPixel(6+120-i+158,237-absHInLast); else ucg.drawPixel(6+120-i+158,237-absHInChart[x-1]); if (x-1<0) ucg.drawPixel(6+120-i+158,237-absHOutLast); else ucg.drawPixel(6+120-i+158,237-absHOutChart[x-1]); // Вывести новую точку if ((tInChart[x]==0)||(tInChart[x]==100)) ucg.setColor(255, 255, 255); else ucg.setColor(250, 0, 100); ucg.drawPixel(5+120-i,237-tInChart[x]); if (absHInChart[x]==100) ucg.setColor(255, 255, 255); else ucg.setColor(250, 0, 100); ucg.drawPixel(6+120-i+158,237-absHInChart[x]); if ((tOutChart[x]==0) || (tOutChart[x]==100)) ucg.setColor(255, 255, 255); else ucg.setColor(0, 250, 100); ucg.drawPixel(5+120-i,237-tOutChart[x]); if (absHOutChart[x]==100) ucg.setColor(255, 255, 255); else ucg.setColor(0, 250, 100); ucg.drawPixel(6+120-i+158,237-absHOutChart[x]); } // Пунктирные линии графика ucg.setColor(100, 100, 100); for(i=1;i<=120;i=i+5) { ucg.drawPixel(5+120-i,237-10); ucg.drawPixel(5+120-i,237-50); ucg.drawPixel(5+120-i,237-90); ucg.drawPixel(6+120-i+158,237-25); ucg.drawPixel(6+120-i+158,237-50); ucg.drawPixel(6+120-i+158,237-75); } sei(); } if (posChart<120-1) posChart++; else posChart=0; // Изменили положение в буфере и Замкнули буфер } // ---ПЕРЕДАЧА ДАННЫХ ЧЕРЕЗ РАДИОМОДУЛЬ ----------------------------- void send_packet() { #ifdef RADIO // Радио модуль NRF42l radio.stopListening(); // Остановить приемник send_packet_ok = radio.write(&packet,sizeof(packet)); #ifdef BEEP if (send_packet_ok==true) beep(40); #endif #ifdef DEBUG if (send_packet_ok==true) Serial.println(F("Packet sending ++++++++++")); else Serial.println(F("Packet NOT sending -----------")); #endif radio.startListening(); // Включить приемник #endif } // Чтение датчика возвращает код ошибки: // DHTLIB_OK 0 // DHTLIB_ERROR_CHECKSUM 1 // DHTLIB_ERROR_TIMEOUT 2 // DHTLIB_ERROR_CONNECT 3 // DHTLIB_ERROR_ACK_L 4 // DHTLIB_ERROR_ACK_H 5 byte readDHT(byte pin) { delay(5); cli(); byte err=-1*DHT.read22(pin); // Чтение датчика sei(); return err; } // Измерение и обработка данных чтение датчиков -------------------------------------------------------------------------------- void measurement() { myOS.pauseTask(measurement); // Обязательно здесь, а то датчики плохо читаются мешает leos wdt_reset(); // Сбросить сторожевой таймер packet.error=readDHT(PIN_DHT22a); // ПЕРВЫЙ ДАТЧИК ДОМ Новый пакет, сбросить все ошибки и прочитать первый датчик #ifdef DEMO DHT.temperature=packet.tIn/100+random(-20,25)/10.0; if (DHT.temperature>20) DHT.temperature=19; if (DHT.temperature<-10) DHT.temperature=-9; DHT.humidity=packet.relHIn/100+(float)random(-5,7); if (DHT.humidity>96) DHT.humidity=90; if (DHT.humidity<1) DHT.humidity=10; packet.error=0; // в Демо режиме // DHT.temperature=3.0; // DHT.humidity=21.0; #endif sensors.tIn=(int)(DHT.temperature*100.0)+TIN_ERR; // Запомнить результаты для суммирования sensors.relHIn=(int)(DHT.humidity*100.0)+HOUT_ERR; #ifdef DEBUG Serial.print(F("Sensor read samples:")); Serial.println(sensors.num); Serial.print(F("IN T="));Serial.print(sensors.tIn);Serial.print(F(" H=")); Serial.print(sensors.relHIn); Serial.print(F(" error=")); Serial.println(packet.error); #endif packet.error=packet.error+16*readDHT(PIN_DHT22b);// ВТОРОЙ ДАТЧИК УЛИЦА ошибки в старшие четыре бита #ifdef DEMO DHT.temperature=packet.tOut/100+random(-40,45)/10.0; if (DHT.temperature>30) DHT.temperature=29; if (DHT.temperature<-30) DHT.temperature=-29; DHT.humidity=packet.relHOut/100+random(-10,12); if (DHT.humidity>96) DHT.humidity=90; if (DHT.humidity<1) DHT.humidity=10; packet.error=0; // в Демо режиме // DHT.temperature=-10.0; // DHT.humidity=40.0; #endif sensors.tOut=(int)(DHT.temperature*100.0)+TOUT_ERR; // Запомнить результаты для суммирования sensors.relHOut=(int)(DHT.humidity*100.0)+HOUT_ERR; #ifdef DEBUG Serial.print(F("OUT T="));Serial.print(sensors.tOut);Serial.print(F(" H=")); Serial.print(sensors.relHOut); Serial.print(F(" error=")); Serial.println(packet.error); #endif print_error_DHT(); // Вывод ошибки чтения датчика при каждом чтении контроль за качеством связи с датчиком if (packet.error==0)// Если чтение без ошибок у ДВУХ датчиков копим сумму для усреднения { sensors.sum_tIn=sensors.sum_tIn+sensors.tIn; sensors.sum_relHIn=sensors.sum_relHIn+sensors.relHIn; sensors.sum_tOut=sensors.sum_tOut+sensors.tOut; sensors.sum_relHOut=sensors.sum_relHOut+sensors.relHOut; sensors.num++; } // набрали в сумме нужное число отсчетов рассчитываем усреднение и выводим if (sensors.num>=NUM_SAMPLES) // Пора усреднять и выводить значения { // вычисление средних значений packet.tIn=sensors.sum_tIn/NUM_SAMPLES; packet.relHIn=sensors.sum_relHIn/NUM_SAMPLES; packet.tOut=sensors.sum_tOut/NUM_SAMPLES; packet.relHOut=sensors.sum_relHOut/NUM_SAMPLES; reset_sum(); // Сброс счетчиков и сумм // вычисление абсолютной влажности packet.absHIn=(int)(calculationAbsH((float)(packet.tIn/100.0),(float)(packet.relHIn/100.0))*100.0); packet.absHOut=(int)(calculationAbsH((float)(packet.tOut/100.0),(float)(packet.relHOut/100.0))*100.0); #ifdef DEBUG Serial.println(F("Average value >>>>>>>>>>")); Serial.print(F("IN T="));Serial.print(packet.tIn);Serial.print(F(" H=")); Serial.print(packet.relHIn); Serial.print(F(" abs H=")); Serial.println(packet.absHIn); Serial.print(F("OUT T="));Serial.print(packet.tOut);Serial.print(F(" H=")); Serial.print(packet.relHOut); Serial.print(F(" abs H=")); Serial.println(packet.absHOut); #endif #ifdef RADIO // Радио модуль NRF42l send_packet(); // Послать данные #endif CheckON(); // Проверка статуса вентилятора print_status(); // панель состояния print_data(); // вывод усредненных значений if ((long)((long)TimeChart*TIME_SCAN_SENSOR*NUM_SAMPLES)>=(long)TIME_PRINT_CHART) // проврека не пора ли выводить график { printChart(); TimeChart=0; // Сдвиг графика и вывод новой точки #ifdef DEBUG Serial.println(F("Point add chart ++++++++++++++++++++")); #endif #ifdef BEEP // beep(50); #endif } else TimeChart++; } myOS.restartTask(measurement); // Пустить задачи } // Функция переводит относительную влажность в абсолютную // t-температура в градусах Цельсия h-относительная влажность в процентах float calculationAbsH(float t, float h) { float temp; temp=pow(2.718281828,(17.67*t)/(t+243.5)); return (6.112*temp*h*2.1674)/(273.15+t); } // Сканирование клавиш ------------------------------------------ void scanKey() { byte key; cli(); key=digitalRead(PIN_KEY); // Прочитать кнопку 0 - нажата if ((key==0)&&(flagKey==false)) // Если кнопка была нажата запомнить время и поставить флаг нажатия { flagKey=true; // Кнопка нажата ждем обратного фронта time_key=millis(); // Время нажатия запомнили } if ((key==1)&&(flagKey==true)) // Если кнопка была отжата { time_key=millis()-time_key; // Рассчитать время нажатия pressKey=true; } sei(); } // Проверка статуса вытяжки, не пора ли переключится void CheckON() { cli(); if (packet.motor==false) // Вентилятор выключен { if (settingRAM.fStart!=MOTOR_OFF) if (settingRAM.fStart==MOTOR_ON) {packet.motor=true; digitalWrite(PIN_RELAY, HIGH);} // Все время включен else if (( packet.tIn>=packet.T )&& ((packet.absHIn-packet.dH)> packet.absHOut)) {packet.motor=true; digitalWrite(PIN_RELAY, HIGH);} // ВКЛЮЧЕНИЕ } else // Вентилятор включен { if (settingRAM.fStart!=MOTOR_ON) if (settingRAM.fStart==MOTOR_OFF) {packet.motor=false; digitalWrite(PIN_RELAY, LOW);} // Все время выключен else if((packet.tIn<=packet.T-dT_OFF)||(packet.absHIn-packet.absHOut<packet.dH-dT_OFF)) {packet.motor=false; digitalWrite(PIN_RELAY, LOW);} // ВЫКЛЮЧЕНИЕ } sei(); } // Вывод информации о настройках и сохрание индекса настроек в eeprom --------------------------------- void Setting() { // Настройка cli(); ucg.setColor(0, 100, 255); ucg.setPrintPos(0,25+0+18); switch (settingRAM.fStart) { case MOTOR_OFF: ucg.print(F("Выключено ")); packet.dH=255;packet.T=255; break; case MOTOR_ON: ucg.print(F("Режим вытяжки ")); packet.dH=0; packet.T=0; break; case 2: ucg.print(F("Включение T>+2 dH>0.2")); packet.dH=20; packet.T=200; break; case 3: ucg.print(F("Включение T>+2 dH>0.4")); packet.dH=40; packet.T=200; break; case 4: ucg.print(F("Включение T>+3 dH>0.3")); packet.dH=30; packet.T=300; break; case 5: ucg.print(F("Включение T>+3 dH>0.5")); packet.dH=50; packet.T=300; break; case 6: ucg.print(F("Включение T>+4 dH>0.6")); packet.dH=30; packet.T=600; break; } writeEeprom(); // Запись в EEPROM CheckON(); // Возможно надо включить мотор print_status(); // панель состояния sei(); } // Вывод float с одним десятичным знаком в координаты x y // для экономии места void print_floatXY(int x,int y, float v) { ucg.setPrintPos(x,y); ucg.print(v,2); ucg.print(" "); // Стереть хвост от предыдущего числа } // Вывод строки константы в координаты x y // для экономии места void print_StrXY(int x,int y, const __FlashStringHelper* b) { ucg.setPrintPos(x,y); ucg.print(b); } void printInfo() // Окно с информацией о блоке, появляется при длительном нажатии на кнопку { infoScreen=true; cli(); ucg.setColor(250, 250, 250); // ucg.drawBox(10, 10, 320-1-20, 240-1-20); ucg.setColor(0, 50, 250); ucg.drawFrame(10+5, 10+5, 320-1-20-10, 240-1-20-10); ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT); ucg.setColor(0, 150, 10); print_StrXY(35,18+15,F("ОСУШИТЕЛЬ на Arduino Pro Mini")); ucg.setColor(0, 50, 50); print_StrXY(10+10,15+17*2,F("1 Напряжение питания В.")); print_floatXY(10+230,15+17*2,readVcc()/1000.0); print_StrXY(10+10,15+17*3,F("2 Температура блока гр.")); print_floatXY(10+230,15+17*3,GetTemp()); print_StrXY(10+10,15+17*4,F("3 Свободная память байт")); ucg.setPrintPos(10+230,15+17*4); ucg.print(freeRam()); print_StrXY(10+10,15+17*5,F("4 Мото часы блока")); ucg.setPrintPos(10+230,15+17*5); ucg.print(settingRAM.hour_unit/(TIME_HOUR/TIME_PRINT_CHART)); print_StrXY(10+10,15+17*6,F("5 Мото часы вентилятора")); ucg.setPrintPos(10+230,15+17*6); ucg.print(settingRAM.hour_motor/(TIME_HOUR/TIME_PRINT_CHART)); print_StrXY(10+10,15+17*7,F("6 Канал NRF24l01+")); ucg.setPrintPos(10+230,15+17*7); ucg.print(NRF24_CHANEL); print_StrXY(10+10,15+17*8,F("7 Гистерезис абс. влажности")); print_floatXY(10+255,15+17*8,(float)dH_OFF/100.0); print_StrXY(10+10,15+17*9,F("8 Гистерезис температуры")); print_floatXY(10+255,15+17*9,(float)dT_OFF/100.0); print_StrXY(10+10,15+17*10,F("9 ERR Т/Н in:")); ucg.print(TIN_ERR); ucg.print(F("/")); ucg.print(HIN_ERR); ucg.print(F(" out:")); ucg.print(TOUT_ERR); ucg.print(F("/")); ucg.print(HOUT_ERR); ucg.setColor(0, 0, 150); print_StrXY(10+10,16+17*11,F("СБРОС - Вкл. при нажатой кнопке.")); ucg.setColor(250,80,80); print_StrXY(10+10,20+21+18*10,F(VERSION)); sei(); } void clearInfo() // Стереть информационный экран { infoScreen=false; last_error=100; // Признак обновления ошибки cli(); ucg.setColor(0, 0, 0); // залить черным ucg.drawBox(10, 10, 320-1-20, 240-1-20); print_static(); Setting(); printChart(); sei(); } // Чтение свободной памяти -------------------------------------------------------------------- int freeRam () { extern int __heap_start, *__brkval; int v; return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); } // Чтение внутреннего датчика температуры --------------------------------------- double GetTemp(void) { unsigned int wADC; double t; sei(); // Должны быть разрешены прерывания ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3)); ADCSRA |= _BV(ADEN); delay(20); ADCSRA |= _BV(ADSC); while (bit_is_set(ADCSRA,ADSC)); wADC = ADCW; t = (wADC - 324.31 ) / 1.22; return (t); } // Чтение напряжения питания ---------------------------------------------- long readVcc() { long result; // Read 1.1V reference against AVcc ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); delay(2); // Wait for Vref to settle ADCSRA |= _BV(ADSC); // Convert while (bit_is_set(ADCSRA,ADSC)); result = ADCL; result |= ADCH<<8; result = ConstADC / result; // Back-calculate AVcc in mV return result; } // Запись счетчиков в Eeprom -------------------------------------------------- void writeEeprom() { cli(); eeprom_write_block((const void*)&settingRAM, (void*) &settingEEPROM, sizeof(settingRAM)); sei(); } // Чтение счетчиков из Eeprom -------------------------------------------------- void readEeprom() { cli(); eeprom_read_block((void*)&settingRAM, (const void*) &settingEEPROM, sizeof(settingRAM)); sei(); } void reset_sum() // Сброс счетчиков накоплений { sensors.num=0; // Рассчитать величину усреднения sensors.sum_tOut=0; sensors.sum_tIn=0; sensors.sum_relHOut=0; sensors.sum_relHIn=0; } char hex(byte x) // Функция для вывода в hex { if(x >= 0 && x <= 9 ) return (char)(x + '0'); else return (char)('a'+x-10); } bool reset_ili9341(void) { pinMode(PIN_RESET, OUTPUT); // Сброс дисплея сигнал активным является LOW // digitalWrite(PIN_RESET, HIGH); digitalWrite(PIN_RESET, LOW); delay(100); digitalWrite(PIN_RESET, HIGH); // Дисплей ucg.begin(UCG_FONT_MODE_TRANSPARENT); ucg.setFont(my14x10rus); // ucg.setFont(myfont); // ucg.setRotate90(); ucg.setRotate270(); ucg.clearScreen(); } #ifdef BEEP void beep(int x) // Пищать х мсек { digitalWrite(PIN_BEEP, HIGH); delay(x); digitalWrite(PIN_BEEP, LOW); } #endif
файл фонтов
/ Русский шрифт 10х14 ------------------------------------------------------ const ucg_fntpgm_uint8_t my14x10rus[4157] UCG_SECTION(".progmem.my14x10") = { 0,11,15,0,255,14,3,35,6,248,32,255,0,15,255,14, 0,0,0,0,8,0,0,2,14,14,4,1,0,64,192,192, 192,192,192,192,192,192,128,0,64,192,128,6,5,5,7,0, 9,68,204,204,204,136,10,14,28,11,0,0,8,128,8,128, 17,0,17,0,127,192,17,0,17,0,34,0,34,0,255,128, 34,0,34,0,68,0,68,0,9,14,28,10,0,0,8,0, 8,0,59,128,123,0,200,0,200,0,232,0,107,0,11,128, 9,128,9,128,111,0,238,0,8,0,8,14,14,9,0,0, 97,179,214,102,12,12,24,24,48,48,102,107,205,134,9,14, 28,10,0,0,56,0,124,0,108,0,108,0,108,0,56,0, 56,128,109,128,199,0,194,0,199,0,237,128,124,128,56,0, 2,5,5,3,0,10,128,192,192,192,64,5,14,14,6,0, 0,24,48,96,96,192,192,192,192,192,192,96,96,48,24,5, 14,14,6,0,0,192,96,48,48,24,24,24,24,24,24,56, 48,96,192,7,7,7,8,0,4,146,214,124,16,124,214,146, 8,10,10,10,0,1,8,24,24,24,127,254,24,24,24,16, 4,6,6,5,0,0,112,96,96,64,192,192,8,2,2,9, 0,5,127,254,3,3,3,4,0,0,224,160,224,8,14,14, 9,0,0,3,3,6,6,12,12,24,24,48,48,96,96,192, 192,9,14,28,10,0,0,62,0,127,0,227,128,197,128,197, 128,197,128,201,128,201,128,209,128,209,128,209,128,227,128,127, 0,62,0,9,14,28,10,0,0,12,0,28,0,60,0,124, 0,8,0,4,0,12,0,12,0,8,0,4,0,12,0,12, 0,127,128,255,128,9,14,28,10,0,0,126,0,255,0,195, 128,193,128,1,128,3,128,63,0,126,0,224,0,192,0,192, 0,192,0,223,128,191,0,9,14,28,10,0,0,126,0,255, 0,195,128,1,128,1,128,3,0,58,0,119,0,3,128,1, 128,1,128,3,128,255,0,126,0,9,14,28,10,0,0,2, 0,6,0,14,0,30,0,62,0,118,0,230,0,198,0,251, 128,247,0,6,0,6,0,6,0,4,0,9,14,28,10,0, 0,127,128,127,128,96,0,96,0,96,0,110,0,111,0,3, 128,1,128,1,128,1,128,195,0,255,0,124,0,9,14,28, 10,0,0,31,0,127,0,96,0,192,0,192,0,192,0,222, 0,223,0,195,128,193,128,193,128,227,0,127,0,60,0,9, 14,28,10,0,0,127,128,255,128,0,0,3,0,3,0,6, 0,6,0,12,0,12,0,24,0,24,0,48,0,48,0,32, 0,9,14,28,10,0,0,58,0,119,0,227,128,193,128,193, 128,99,0,54,0,111,0,227,128,193,128,193,128,227,128,119, 0,46,0,9,14,28,10,0,0,60,0,255,0,231,0,195, 128,193,128,193,128,225,128,253,128,125,128,1,128,3,128,7, 0,127,0,252,0,3,11,11,4,0,2,224,160,224,0,0, 0,0,0,224,160,224,4,13,13,5,0,0,112,80,112,0, 0,0,0,0,112,80,112,96,192,9,11,22,10,0,1,1, 128,3,128,15,0,28,0,120,0,224,0,120,0,28,0,15, 0,3,128,1,128,9,6,12,10,0,4,127,128,255,0,0, 0,0,0,127,128,255,0,9,11,22,10,0,1,192,0,224, 0,120,0,60,0,15,0,3,128,15,0,60,0,120,0,224, 0,192,0,8,14,14,9,0,0,116,238,135,3,3,6,14, 56,48,48,0,0,48,48,9,11,22,10,0,1,62,0,65, 0,128,128,154,128,166,128,162,128,162,128,166,128,155,0,64, 0,63,128,9,14,28,10,0,0,252,0,254,0,199,0,195, 128,193,128,193,128,193,128,253,128,253,128,193,128,193,128,193, 128,193,128,129,0,9,14,28,10,0,0,94,0,223,0,195, 128,193,128,193,128,195,128,255,0,255,0,195,128,193,128,193, 128,195,128,223,0,190,0,9,14,28,10,0,0,14,0,63, 0,115,128,97,128,192,0,192,0,192,0,192,0,192,0,192, 0,96,0,112,0,63,128,15,0,9,14,28,10,0,0,238, 0,111,0,99,128,97,128,97,128,97,128,97,128,97,128,97, 128,97,128,97,128,99,128,111,0,238,0,9,14,28,10,0, 0,95,128,223,0,192,0,192,0,192,0,192,0,223,0,222, 0,192,0,192,0,192,0,192,0,223,128,191,0,9,14,28, 10,0,0,95,128,223,0,192,0,192,0,192,0,192,0,223, 0,222,0,192,0,192,0,192,0,192,0,192,0,128,0,9, 14,28,10,0,0,63,128,127,128,225,128,192,0,192,0,192, 0,192,0,207,128,223,128,193,128,193,128,225,128,127,128,62, 0,9,14,28,10,0,0,129,0,193,128,193,128,193,128,193, 128,193,128,223,128,223,128,193,128,193,128,193,128,193,128,193, 128,64,128,8,14,14,10,1,0,254,127,24,24,24,24,24, 24,24,24,24,24,254,127,9,14,28,10,0,0,31,128,63, 128,1,128,1,128,1,128,1,128,1,128,1,128,1,128,1, 128,1,128,195,128,255,0,62,0,9,14,28,10,0,0,65, 128,195,128,199,0,206,0,220,0,216,0,216,0,216,0,216, 0,220,0,206,0,199,0,195,128,65,128,9,14,28,10,0, 0,64,0,192,0,192,0,192,0,192,0,192,0,192,0,192, 0,192,0,192,0,192,0,192,0,255,128,255,0,9,14,28, 10,0,0,193,128,227,128,247,128,247,128,213,128,193,128,213, 128,221,128,221,128,201,128,193,128,193,128,193,128,129,0,9, 14,28,10,0,0,225,0,225,128,241,128,241,128,249,128,217, 128,221,128,205,128,205,128,197,128,197,128,193,128,193,128,128, 128,9,14,28,10,0,0,46,0,111,0,227,128,193,128,193, 128,193,128,193,128,193,128,193,128,193,128,193,128,227,128,123, 0,58,0,9,14,28,10,0,0,254,0,255,0,195,128,193, 128,193,128,195,128,223,0,222,0,192,0,192,0,192,0,192, 0,192,0,128,0,10,15,30,10,0,255,46,0,111,0,227, 128,193,128,193,128,193,128,193,128,193,128,193,128,193,128,193, 128,227,0,123,128,58,192,0,192,9,14,28,10,0,0,126, 0,255,0,195,128,193,128,193,128,195,128,223,0,220,0,206, 0,199,0,195,128,193,128,193,128,129,0,9,14,28,10,0, 0,62,0,127,0,224,0,192,0,192,0,224,0,118,0,27, 0,3,128,1,128,1,128,3,128,255,128,127,0,9,14,28, 10,0,0,255,0,127,128,0,0,12,0,12,0,12,0,12, 0,12,0,12,0,12,0,12,0,12,0,12,0,4,0,9, 14,28,10,0,0,64,128,193,128,193,128,193,128,193,128,193, 128,193,128,193,128,193,128,193,128,193,128,99,0,127,0,62, 0,9,14,28,10,0,0,227,128,99,0,99,0,99,0,34, 0,54,0,54,0,54,0,20,0,28,0,28,0,28,0,8, 0,8,0,10,14,28,11,0,0,64,64,192,192,192,192,192, 192,192,192,192,192,204,192,204,192,204,192,222,192,222,192,211, 192,193,192,128,192,9,14,28,10,0,0,193,128,193,128,193, 128,99,0,99,0,50,0,56,0,28,0,14,0,103,0,99, 0,193,128,193,128,193,128,10,14,28,10,0,0,192,192,192, 192,97,128,97,128,51,0,63,0,30,0,12,0,8,0,4, 0,12,0,12,0,12,0,8,0,9,14,28,10,0,0,127, 128,255,128,1,128,3,128,7,0,6,0,4,0,16,0,48, 0,112,0,224,0,192,0,255,128,255,0,5,14,14,6,0, 0,248,192,192,192,192,192,192,192,192,192,192,192,192,248,9, 14,28,10,0,0,192,0,96,0,96,0,48,0,48,0,24, 0,24,0,12,0,12,0,6,0,6,0,3,0,3,0,1, 128,5,14,14,6,0,0,248,24,24,24,24,24,24,24,24, 24,24,24,24,248,9,6,12,10,0,8,8,0,28,0,54, 0,99,0,193,128,128,128,10,1,2,10,0,255,255,192,4, 3,3,5,0,12,224,96,48,8,11,11,9,0,0,124,127, 3,3,59,123,227,195,199,255,123,9,13,26,10,0,0,64, 0,192,0,192,0,192,0,192,0,222,0,223,0,195,128,193, 128,193,128,195,0,255,0,222,0,8,11,11,9,0,0,30, 63,115,224,192,192,192,224,240,127,30,9,13,26,10,0,0, 0,128,1,128,1,128,1,128,1,128,61,128,125,128,225,128, 193,128,193,128,227,128,127,128,61,128,8,11,11,9,0,0, 60,126,231,195,195,223,222,192,227,127,62,7,13,13,8,0, 0,62,124,96,96,252,248,96,96,96,96,96,96,32,8,13, 13,9,0,0,63,127,227,195,195,195,227,123,51,3,3,127, 254,8,13,13,9,0,0,64,192,192,192,222,223,195,195,195, 195,195,195,130,2,13,13,3,0,0,64,192,128,64,192,192, 192,192,192,192,192,192,128,5,14,14,6,0,255,16,24,24, 8,48,120,24,24,24,24,24,24,120,240,8,13,13,9,0, 0,64,192,192,198,198,204,216,216,216,204,198,199,131,2,14, 14,3,0,0,64,192,192,192,192,192,192,192,192,192,192,192, 192,128,9,11,22,10,0,0,91,0,219,128,201,128,201,128, 201,128,201,128,201,128,201,128,201,128,193,128,129,0,8,11, 11,9,0,0,94,223,195,195,195,195,195,195,195,195,130,8, 11,11,9,0,0,52,118,227,195,195,195,195,195,227,118,52, 8,11,11,9,0,0,252,254,199,195,199,222,220,192,192,192, 128,9,13,26,9,0,255,63,0,127,0,227,0,195,0,195, 0,195,0,251,0,123,0,3,0,3,0,3,128,3,128,3, 128,7,11,11,8,0,0,92,222,224,224,192,192,192,192,192, 192,128,8,11,11,9,0,0,62,127,192,192,240,102,15,3, 3,254,124,6,13,13,7,0,0,32,96,96,252,248,96,96, 96,96,96,96,124,60,8,11,11,9,0,0,65,195,195,195, 195,195,195,195,227,123,58,8,11,11,9,0,0,129,129,195, 195,102,102,102,36,60,24,24,9,11,22,10,0,0,128,128, 193,128,201,128,201,128,201,128,201,128,193,128,221,128,247,128, 227,128,65,0,8,11,11,9,0,0,195,102,102,52,24,24, 24,52,102,102,195,8,12,12,9,0,255,193,227,99,102,110, 44,12,24,24,48,240,224,8,11,11,9,0,0,127,255,7, 6,12,0,48,96,224,255,254,7,14,14,8,0,0,14,28, 24,24,24,48,224,224,48,24,24,24,28,14,2,16,16,5, 1,255,192,192,192,192,192,192,192,192,192,192,192,192,192,192, 192,192,8,14,14,9,0,0,224,112,24,24,24,12,7,7, 12,24,24,24,112,224,10,5,10,11,0,4,48,192,120,192, 204,192,199,128,195,0,5,13,13,6,0,1,248,136,136,136, 136,136,136,136,136,136,136,136,248,8,11,11,9,0,0,252, 254,199,195,199,222,220,192,192,192,128,8,11,11,9,0,0, 30,63,115,224,192,192,192,224,240,127,30,8,11,11,9,0, 0,127,254,24,24,24,24,24,24,24,24,16,8,12,12,9, 0,255,193,227,99,102,110,44,12,24,24,48,240,224,8,12, 12,9,0,255,126,255,219,219,219,219,90,24,24,24,24,16, 8,11,11,9,0,0,195,102,102,52,24,24,24,52,102,102, 195,8,12,12,9,0,255,132,198,198,198,198,198,198,198,198, 254,255,3,8,11,11,9,0,0,65,195,195,195,231,127,63, 3,3,3,2,8,11,11,9,0,0,130,195,195,211,219,219, 219,219,219,203,255,8,12,12,9,0,255,130,195,195,211,219, 219,219,219,218,200,255,3,8,11,11,9,0,0,192,224,96, 96,108,110,103,99,103,126,124,8,11,11,9,0,0,130,195, 195,195,219,221,207,199,207,253,251,8,11,11,9,0,0,64, 192,192,192,220,222,199,195,199,254,252,8,11,11,9,0,0, 124,254,198,3,27,59,3,3,6,254,120,9,11,22,10,0, 0,71,0,207,128,205,128,205,128,221,128,221,128,205,128,205, 128,205,128,207,128,135,0,8,11,11,9,0,0,63,127,227, 195,227,123,59,51,51,115,226,9,14,28,10,0,0,252,0, 254,0,199,0,195,128,193,128,193,128,193,128,253,128,253,128, 193,128,193,128,193,128,193,128,129,0,9,14,28,10,0,0, 223,128,223,0,192,0,192,0,192,0,192,0,222,0,223,0, 195,128,193,128,193,128,195,128,255,0,254,0,9,14,28,10, 0,0,94,0,223,0,195,128,193,128,193,128,195,128,255,0, 255,0,195,128,193,128,193,128,195,128,223,0,190,0,9,14, 28,10,0,0,223,0,223,128,192,0,192,0,192,0,192,0, 192,0,192,0,192,0,192,0,192,0,192,0,192,0,128,0, 9,14,28,10,0,0,11,0,27,0,59,0,115,0,99,0, 99,0,99,0,99,0,99,0,99,0,123,0,251,128,193,128, 193,128,9,14,28,10,0,0,95,128,223,0,192,0,192,0, 192,0,192,0,223,0,222,0,192,0,192,0,192,0,192,0, 223,128,191,0,10,14,28,11,0,0,64,64,192,192,196,192, 204,192,204,192,109,128,109,128,109,128,109,128,204,192,204,192, 204,192,200,192,128,128,9,14,28,10,0,0,122,0,251,0, 131,128,1,128,1,128,3,0,58,0,123,0,3,128,1,128, 1,128,131,128,251,0,120,0,9,14,28,10,0,0,67,128, 195,128,199,128,199,128,199,128,205,128,205,128,205,128,217,128, 217,128,217,128,209,128,209,128,193,0,9,14,28,10,0,0, 91,128,219,128,215,128,199,128,199,128,205,128,205,128,205,128, 217,128,217,128,217,128,209,128,209,128,193,0,9,14,28,10, 0,0,65,128,195,128,199,0,206,0,220,0,216,0,216,0, 216,0,216,0,220,0,206,0,199,0,195,128,65,128,9,14, 28,10,0,0,220,0,222,0,199,0,195,128,193,128,193,128, 193,128,193,128,193,128,193,128,193,128,193,128,193,128,193,128, 9,14,28,10,0,0,193,128,227,128,247,128,247,128,213,128, 193,128,213,128,221,128,221,128,201,128,193,128,193,128,193,128, 129,0,9,14,28,10,0,0,129,0,193,128,193,128,193,128, 193,128,193,128,223,128,223,128,193,128,193,128,193,128,193,128, 193,128,64,128,9,14,28,10,0,0,46,0,111,0,227,128, 193,128,193,128,193,128,193,128,193,128,193,128,193,128,193,128, 227,128,123,0,58,0,9,14,28,10,0,0,223,128,223,128, 193,128,193,128,193,128,193,128,193,128,193,128,193,128,193,128, 193,128,193,128,193,128,129,0,9,14,28,10,0,0,254,0, 255,0,195,128,193,128,193,128,195,128,223,0,222,0,192,0, 192,0,192,0,192,0,192,0,128,0,9,14,28,10,0,0, 14,0,63,0,115,128,97,128,192,0,192,0,192,0,192,0, 192,0,192,0,96,0,112,0,63,128,15,0,9,14,28,10, 0,0,255,0,127,128,0,0,12,0,12,0,12,0,12,0, 12,0,12,0,12,0,12,0,12,0,12,0,4,0,9,14, 28,10,0,0,129,0,193,128,193,128,193,128,193,128,125,128, 61,128,1,128,1,128,1,128,193,128,225,128,127,0,62,0, 10,14,28,11,0,0,63,0,127,128,237,192,204,192,204,192, 237,192,109,128,45,0,12,0,12,0,12,0,12,0,12,0, 4,0,9,14,28,10,0,0,193,128,193,128,193,128,99,0, 99,0,50,0,56,0,28,0,14,0,103,0,99,0,193,128, 193,128,193,128,10,15,30,10,0,255,130,0,195,0,195,0, 195,0,195,0,195,0,195,0,195,0,195,0,195,0,195,0, 195,0,223,0,223,128,1,192,9,14,28,10,0,0,129,0, 193,128,193,128,193,128,193,128,193,128,225,128,125,128,61,128, 1,128,1,128,1,128,1,128,0,128,10,14,28,11,0,0, 128,128,192,192,192,192,192,192,200,192,204,192,204,192,204,192, 204,192,204,192,196,192,192,64,223,128,95,192,11,15,30,11, 0,255,128,128,192,192,192,192,192,192,200,192,204,192,204,192, 204,192,204,192,204,192,196,192,192,64,223,128,95,192,0,224, 9,14,28,10,0,0,224,0,224,0,96,0,96,0,96,0, 96,0,110,0,111,0,99,128,97,128,97,128,99,128,127,0, 62,0,10,14,28,11,0,0,128,128,192,192,192,192,192,192, 192,192,192,192,220,192,222,192,199,64,195,64,195,64,199,64, 254,192,124,192,9,14,28,10,0,0,128,0,192,0,192,0, 192,0,192,0,192,0,222,0,223,0,195,128,193,128,193,128, 195,128,255,0,254,0,9,14,28,10,0,0,62,0,127,0, 227,128,193,128,193,128,1,128,29,128,29,128,1,128,1,128, 193,128,227,128,127,0,62,0,10,14,28,11,0,0,71,0, 207,128,221,192,216,192,216,192,216,192,248,192,248,192,216,192, 216,192,216,192,221,192,207,128,135,0,9,14,28,10,0,0, 63,128,127,128,225,128,193,128,193,128,225,128,125,128,61,128, 29,128,57,128,113,128,225,128,193,128,129,0,8,11,11,9, 0,0,124,127,3,3,59,123,227,195,199,255,123,8,11,11, 9,0,0,7,31,56,112,102,207,195,195,231,126,60,8,11, 11,9,0,0,92,222,198,198,220,222,195,195,199,222,188,8, 11,11,9,0,0,254,255,192,192,192,192,192,192,192,192,128, 10,11,22,11,0,0,31,128,31,128,25,128,49,128,49,128, 49,128,1,128,127,192,255,192,192,192,192,192,8,11,11,9, 0,0,60,126,231,195,195,223,222,192,227,127,62,9,11,22, 10,0,0,64,128,201,128,201,128,107,0,54,0,54,0,107, 0,201,128,201,128,201,128,129,0,8,11,11,9,0,0,116, 246,195,7,126,62,6,3,7,254,124,8,11,11,9,0,0, 65,195,195,199,207,223,219,211,195,195,130,8,11,11,9,0, 0,89,219,211,199,207,223,219,211,195,195,130,8,11,11,9, 0,0,71,207,204,220,216,216,216,220,206,199,67,8,11,11, 9,0,0,27,59,115,227,195,195,195,195,195,195,195,9,11, 22,10,0,0,65,0,227,128,247,128,247,128,213,128,213,128, 213,128,213,128,193,128,193,128,129,0,8,11,11,9,0,0, 65,195,195,251,251,195,195,195,195,195,130,8,11,11,9,0, 0,52,118,227,195,195,195,195,195,227,118,52,8,11,11,9, 0,0,95,223,195,195,195,195,195,195,195,195,130,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255}; // ---------------------------------------------------------------------------
Я бы делал wdt_reset в самом начале loop(). А то пока кнопки обрабатываете - оно и перегрузится.
Я бы делал wdt_reset в самом начале loop(). А то пока кнопки обрабатываете - оно и перегрузится.
Не вижу особого смысла сторежевой таймер настроен на 8 сек прерывание по таймеру где сидит его сброс 3 сек запас есть.
Сейчас попробовал Вашу идею тоже все работает -))
как то все слишком просто. нормально оформлено (не считая того что код не свернул), и фото, и код. не к чему придраться вот так сразу, разве что лаком не покрыты платы, условия то не самые лучшие
хорошо получилось
понравилось, классно сделаный домашний проект.
респект автору!
Подпишусь пожалуй
1. Насколько мне известно датчики влажности измеряют абсолютную влажность воздуха, а датчик температуры им нужен только для того, чтобы преобразовать эту абсолютную влажность в относительную. Возможно, можно найти и использовать какой нибудь простой/дешевый датчик абсолютной влажности.
2. Приточный вентилятор хорошо, но, как мне кажется, не очень эффективно. Хотя зимой при низкой температуре и при 100%-й влажности наружного воздуха, заходя и нагреваясь влажность будет, конечно, значительно ниже 100%. Но на подогрев воздуха потребуется расходовать энергию дома. Для подогрева входящего воздуха можно использовать самодельный рекуператор с выходящим воздухом.
3. Можно попробовать высушить воздух/стены осушителем еще до зимы. Зимой при температуре 0-2 градуса, кмк, от осушителя толку не будет никакого. Я себе купил б/у ballu bhd25 (примерно с таким названием) за 4т.р. пару лет назад, с производительностью до 25л/сутки, чтобы высушить погреб под гаражом, и при изучении своего вопроса мне сказали, что на зиму все вентиляционные отверстия нужно закрывать.
4. По вашему графику видно, что влажность в подвале снижается, но! до каких значений ее можно снизить? Пусть на улице минимальная абс. влажность 9г/м3, и до этого значения вы опустите влажность в подвале, но! при опускании температуры до 1-2градусов, относительная влажность 100% установится при 6г/м3, а у вас только 9?
1. Насколько мне известно датчики влажности измеряют абсолютную влажность воздуха, а датчик температуры им нужен только для того, чтобы преобразовать эту абсолютную влажность в относительную. Возможно, можно найти и использовать какой нибудь простой/дешевый датчик абсолютной влажности.
На сколько мне известно большинство датчиков измеряют ОТНОСИТЕЛЬНУЮ влажность (показания %). Конкретно DHT-22 выдает относительную влажность (согласно даташита на него). 0-100% И как раз перевод из относительной в абсолютную является "тонким" моментом и существует несколько эмпирических формул (ссылку на одну я приводил выше).
2. Приточный вентилятор хорошо, но, как мне кажется, не очень эффективно. Хотя зимой при низкой температуре и при 100%-й влажности наружного воздуха, заходя и нагреваясь влажность будет, конечно, значительно ниже 100%. Но на подогрев воздуха потребуется расходовать энергию дома. Для подогрева входящего воздуха можно использовать самодельный рекуператор с выходящим воздухом.
Я рассчитываю не использовать энергию для подогорева приточного воздуха зимой. У меня подвал заглубленный, утепленный по периметру. Измерения прошлого года показали что даже при заботных температурах -30 (в течении 9 часов) у меня в подвале было +1+2. Средняя температура подвала +4+5, это объясняется подогревом подвала грунтом, который имеет температуру около +6 градусов.
Включение вентилятора происходит не только при определенной разнице абсолютных влажностей но и при темперетуре в подвале НЕ МЕНЬШЕ заданной (например +2 - см. надпись синим цветом). Система конечно будет охлаждать подвал но температура в подвале не упадет ниже заданной. В подвале зимой всегда будет теплее чем на улице. По этому конденсат не будет выпадать (поступающий воздух в абсолютных значениях более сухой и попадает в более теплое помещение)
Кстати рекуператор будет здесь мало эффективен - очень малая дельта температур входящего и выходящего воздуха. Либо надо использовать теплообменник лошадиных размеров.
3. Можно попробовать высушить воздух/стены осушителем еще до зимы. Зимой при температуре 0-2 градуса, кмк, от осушителя толку не будет никакого. Я себе купил б/у ballu bhd25 (примерно с таким названием) за 4т.р. пару лет назад, с производительностью до 25л/сутки, чтобы высушить погреб под гаражом, и при изучении своего вопроса мне сказали, что на зиму все вентиляционные отверстия нужно закрывать.
Осушитель - большие энергозатраты + проблема отвода конденсата (если накопитель переполнится). Как раз зимой осушитель будет работать очень эффективно. Допустим - в подвале +4 влажность 7 за бортом -10 влажность 3 грамм (все цифры условны). Осушитель включается, внутри подвала влажность и температура падает допустим до +2 и 5 грамм. По температуре (+2) осушитель выключается но за 5-10 часов подвал нагревается грунтом до +4 (влажность остается 5 грамм), осушитель включается и итерация повторяется. Постепенно влажность уменьшается до 3 при колебаниии температуры +2 +4 градуса.
При использовании осушителя конечно надо закрывать вентиляционные отверстия. Иначе вы будите осушать улицу.
4. По вашему графику видно, что влажность в подвале снижается, но! до каких значений ее можно снизить? Пусть на улице минимальная абс. влажность 9г/м3, и до этого значения вы опустите влажность в подвале, но! при опускании температуры до 1-2градусов, относительная влажность 100% установится при 6г/м3, а у вас только 9?
см предыдущий пост. При уменьшении влажности осушитель включится и доведет влажность до 6 грамм. При абсолютной герметичности подвала (с заслонкой на притоке) в подвале установится за зиму влажность соответсвующая температуре -20 -25 градусов.
Подведем итоги.
Принцип работы моего осушителя с точки зрения энерго затрат очень эффективен. Потребляемая мощность - блок ( 1вт) и вентилятор - 18 вт.
Проблемы с конденсатом будут если уличная температура и влажность выше внутренних длительный промежуток времени ( я думаю 1-2 суток, что маловероятно) тогда за счет не герметичности уличный воздух будет попадать в подвал и возможно выпадение конденсата. Для уменьшения этого эффекта надо ставить управляемую заслонку для вентиляции (сейчас у меня отверстие всегда открыто), которая будет открываться вместе с включением вентилятора.
Немного поправил исходник. В первую очередь это коснулось формата передаваемого пакета. Так как приемник будет на stm32, то в процессе отладки приемника выяснилось, что компилятор stm32 выравнивает переменные с точностью 2 байта и int в stm32 занимает 4 байта. Структура пакета была переделана, чтобы она была одинаковой на обеих платформах.
Итоговый исходник:
Файл фонтов не поменялся.
Также была проведена оптимизация работы с кнопкой по прерыванию. Результат сомнительный.
Сейчас пишу программу для приемника для maple mini в среде arduino (проект https://github.com/rogerclarkmelbourne/Arduino_STM32 форум http://www.stm32duino.com/). Основной функционал работает (дисплей и радиомодуль), проблема с прерываниями радиомодуля.
Портировал библиотеки RF24 и ucglib. Отдельно напишу по этому проекту пост.
Отличная работа!
Уменя подобная схема осушения работает 2 года. Но собрана на китайских котроллерах температуры и влажности.
В подвале гаража стоит вентилятор 9Вт на приточной трубе, без клапана. Управление по влажности настроено на 72% отн. с гистерезисом -5% (при 67%-выкл.). На верхней (выходной трубе), часть её железная, подвешена воронка в которую зимой стекает конденсат и по трубке отводится в закрытую 30л. ёмкость. Набирается за зиму до 20л. конденсата..
Дополнительно стоит тепловентилятор на 1кВт. Он ключается если температура опускается ниже +3 (редкий случай). За 2 зимы ниразу не включился. Хватает тепла от земли.
Но Ваш метод и воплощение намного правильнее...Тоже думал сравнивать влажность снаружи и внутри, только не хватило терпения.. :)
Хочу повторить Вашу разработку, если Вы не против.
Нажал стрелочку вверх. Спасибо за публикацию. Будем изучать, перенимать опыт.
В подвале гаража стоит вентилятор 9Вт на приточной трубе, без клапана. Управление по влажности настроено на 72% отн. с гистерезисом -5% (при 67%-выкл.). На верхней (выходной трубе), часть её железная, подвешена воронка в которую зимой стекает конденсат и по трубке отводится в закрытую 30л. ёмкость. Набирается за зиму до 20л. конденсата..
У Вас немного не правильно сделано. Использовать относительную влажность нельзя, весной/осенью в подвале холоднее и Вы закачиваете более теплый (и более влажный скорее всего) воздух, и в подвале выпадает конденсат. У меня основная тонкость именно в использовании абсолютной влажности. Возможно выключив свою систему Вы уменьшите кондесат в подвале (т.е. система не осушает а увлажняет воздух в Вашем случае).
На счет калорифера тоже думаю, для подвала где хранятся продукты, что бы было +1...+3 градуса. Это можно реализовать на том же устройстве.
По поводу повторения я конечно не против -))
Как ни странно, но до появления моей системы, влажность не опускалась ниже 89%. Теперь по факту за год выше 76% не поднималось. Несколько раз проверял датчик влажности по психрометру (висит на стене, вдали от потоков воздуха ) практически совпадает...
Сегодня утром заехал посмотреть на циферки...в 6:30 утра -72% и 19,4*С .. Этот подвал для хранения продуктов давно не использую...Теперь задача сохранить различное железо (моторы, приборы и т.д.).
Однозначно буду собирать и уже комплектую вашу схему... Ломаю голову - нужна ли мне удаленка...Вот собирать лог на SD карту было бы вернее ( в т.ч. и количество отключений питания). Опять же вопрос по часам реального времени...
Понятно что в Вашем головном устройстве все это будет воплощено.. Этой осенью заканчиваем строительство частного дома. Там удаленка точно понадобиться.
Какой размер кода у Вас получился?
Однозначно буду собирать и уже комплектую вашу схему... Ломаю голову - нужна ли мне удаленка...Вот собирать лог на SD карту было бы вернее ( в т.ч. и количество отключений питания). Опять же вопрос по часам реального времени...
Понятно что в Вашем головном устройстве все это будет воплощено.. Этой осенью заканчиваем строительство частного дома. Там удаленка точно понадобиться.
Какой размер кода у Вас получился?
Размер кода почти на приделе (в начале исходника есть дифайны на опции), В зависимости от их установок код получается 29-31 кБ. Это с перешитым загрузчиком (+1.5 кб места).
Карту прикрутить не получится - места не хватит. Можно использовать мегу там памяти с запасом. Количество отключений питания можно реализовать записью во флеш. Надо только автономное питание для блока сделать и детектор сети. Можно выкитуть радиомодуль, место появится но ИХМО для карточки не хватит. Еще Вариант - выкинуть все что касается дисплея тогда на карту места хватит, а наблюдать все с удаленки. Я думаю что в течении месяца я блок удаленного мониторинга выложу. Причем сейчас я пишу сразу для двух вариантов pro mini и maple mini (условная компиляция). Правда может быть конечный вариант будет только на STM32 maple mini.
Малый размер памяти программ это одна из причин почему я ухожу на STM32. maple mini - 120 кб это гараздо лучше чем 32. Правда код получается более емкий. но выйгрыш есть.
В какой среде вы пишете и компилируете? Может выкинуть загрузчик и грузить код по ISP ? А вообще мне и мегу 2560 под это дело не жалко, с перспективой на расширение...
Собираю пока библиотеки... Недостающее железо едет..
Еще вопрос по расположению наружного датчика? Его показания, в отличие от внутреннего, сильно зависят от ветра и солнца.
П.С.
Я в прошлом, если можно так сказать, писал на АСМЕ под CPM. На СИ так и не смог перейти, после многолетней работы на ПЛ-1 и Фортране..в начале 80х..Теперь вот пытаюсь наверстывать.. STM для меня пока темный лес.. Но чувствую с него и надо было начинать...
Я пишу в Arduino IDE 1.6.1. Выкидывание загрузчика даст 512 байт, это погоды не сделает. Если есть возможность покупать в Китае можно посмотреть типа:
http://www.ebay.com/itm/Mega2560-CORE-mini-2560-Arduino-compatible-3-3V-...
Обратите внимание ucglib не новее 1.02 в более новой библиотеке автор переработал систему шрифтов (со сжатием) исчезла поддержка UTF-8 и изменился формат шрифтов. Адаптировать эту библиотеку наверное буду если получится подключить SPI DMA для STM32.
С датчиком есть проблема. Показания влажности скачут. Пока он висит просто на улице но в тени.
STM32 у меня тоже тяжело идет после avr. Но я использую проект http://www.stm32duino.com он сильно помогает - фактически можно программировать как avr в той же Arduino IDE. По этому я и перехожу на STM32. Портировано уже много библиотек. Я сам "портировал" на STM32 две библиотеки RF24 Uucglib.
я сейчас потихоньку осваиваю АВРы.. Уже пол-года играюсь с Uno, Nano и вот пару дней назад приехала MEGA 2560 за $6,12 отсюда http://www.aliexpress.com/snapshot/6807944392.html?orderId=68405489764729
Вполне рабочий вариант. Зачем платить больше?
У меня лежит давно ucglib_arduino_v1.01.zip
Есть вопрос по скечу: - пин 15 под бипер и пин 14 -реле в строках 49 и 51 соответственно. О каких пинах идет речь?
Тоже осваиваю микроконтроллеры меньше года :=))
Так еще нумеруют аналоговые входы (где то видел.) т.е. А0 и А1 соответственно. Я их перевожу в режим цифровых выходов.
Если в обозначениях портов то это С0 и С1 кажись.
Рекомендую покупать дисплей 2.8 а не как у меня 2.4 программно они одинаковые (spi ili9341) а размер больше. У меня были два дисплея 2.4 я их использовал на два таких устройства. В дальнейшем я буду использовать только 2.8 дюйма. Больше размером на ili9341 со spi я не нашел.
По пинам ясно, спасибо.
У меня уже есть 2 дисплея на ili9341 И оба 2.4". Один из них с тачпадом...+ в обоих ридеры SD.. Проверены в работе по SPI. Маловаты они...Я бы вообще 3,2" брал...
http://ru.aliexpress.com/premium/3.2%2522-tft-ili9341.html?site=rus&grou...
С датчиком есть проблема. Показания влажности скачут. Пока он висит просто на улице но в тени.
У датчика, исключите сквозняки, он на малейшее дуновение реагирует.
Приедут датчики, попробую сконструировать защиту для наружного датчика... Поставлю вентилятор и по наименьшему воздействию на показания, подберу что -то..
Думаю начать с сетки с мелкой ячейкой и в консервной банке..
Приедут датчики, попробую сконструировать защиту для наружного датчика... Поставлю вентилятор и по наименьшему воздействию на показания, подберу что -то..
Думаю начать с сетки с мелкой ячейкой и в консервной банке..
Наиболее подходящее, как на метеостанциях (стационарных) - домик типа скворечника в теньке и наклонные жалюзи на всех стенках.
Да это чтото типа такого-
У меня уже есть 2 дисплея на ili9341 И оба 2.4". Один из них с тачпадом...+ в обоих ридеры SD.. Проверены в работе по SPI. Маловаты они...Я бы вообще 3,2" брал...
http://ru.aliexpress.com/premium/3.2%2522-tft-ili9341.html?site=rus&groupsort=1&SearchText=3.2%22+tft+ili9341&SortType=price_asc&initiative_id=SB_20150825074153&shipCountry=ua&filterCat=202001115,202000349,202000056&isFreeShip=y
Этот дисплей не подойдет (для про мини), Так как он имеет параллельную шину 16 бит - ножек не хватит. На мегу встанет, но надо конфигурировать. Контроллер ili9341 может быть сконфигурирован на SPI, 8 бит и 16 бит. Конечно 16 бит гораздо быстрее, но ног надо много. А как быстро он работает через SPI DMA на stm32 на частоте 46 мГц -))))))) песня, 16 битный интерфейс отдыхает.
С датчиками это понятно, но у меня проблема с размещением - идет цоколь из керамических панелей, что то городить типа скоречника не хотелось бы, и дырки крутить в панелях не гуд. Пока думаю.
На этой неделе допиливал программу (надо завершать проект). Что было сделано:
- оптимизирован код, Функционал стал больше места занимает меньше (около 200 байт)
- реализована "быстрая" работа с GPIO через прямую работу с портами
- в логике работы была ошибка она исправленна, Полностью переписана функция отвечающая за управление вентилятором. Изменены настройки - минимальная температура стала +3 (было +2) при которой включается вентилятор. Боюсь неравномерности температур в подвале а датчик один.
- добавлен еще один режим "охлаждение" когда внутренняя температура больше +10 градусов а с наружи меньше на 2 градуса (по сравнению с внутренней) включается вытяжка. Это режим актуален летом когда ночи холодные и будет проводится охлаждение подвала.
- доработан функционал графиков, Теперь в точках где включена вытяжка (хотя бы на один инетрвал измерения) фон становится темно желтым (обычно он черный) и сразу видно когда работал вентилятор. В график влезает 10 часов, Одна точка 5 минут.
- изменен алгоритм прорисовки графиков теперь"лишние" точки не возникают на графике.
- добавлен калорифер (пока без аппартной поддержки) теперь если температура в подвале опускается ниже +2 градусов включается калорифер
- оптимизирован код работы с nrf24. Успех не достигнут -((
Основное время убил на nrf24. Стабильность увеличилась, но есть проблемы. Бывает что после включения данные не "проходят" на приемник (скорее всего из за передатчика). Начинаюся танцы с бубном и через некоторое время связь восстанавливается, что служило причиной восстановления не выяснял. Все сделано на совесть - отдельный стабилизатор, конденсаторы по питанию, "оптимальный" код. Причем есть несколько вариантов модулей, худшую стабильность показали модули с усилителем и внешней антенной.
Пытался улучшить получение "квитанций" от приемника о приеме (опция setAutoAck). Не получилось. Получение "квитанций" работает на очень маленьком расстоянии.
Вывод: Если рассматривать радио канал как дополнительный бонус, то нормально (типа если не показывает то и ладно, спущусь в подвал если сильно надо), но делать что то серьезное на нем наверное не получится (либо надо все многократно дублировать).
Новая версия кода приведена ниже:
Я еще предыдущий листинг не изучил, а у Вас уже новая работа вышла...Плодотворно!
Жаль железо еще не приехало..
Доброй Ночи!
В Version: 0.58 28/08/15 управление кнопкой PIN_KEY не предусмотрено?
При каких условиях происходит управление кнопкой ? Начиная с версии 0.51, при отсутствии датчиков и радио, на нажатие кнопки (D3) никак не реагирует...
Еще вопрос:- какая версия LeOs используется?
Доброй Ночи!
В Version: 0.58 28/08/15 управление кнопкой PIN_KEY не предусмотрено?
Еще вопрос:- какая версия LeOs используется?
Управление кнопкой предусмотрено. Просто сейчас она читается без использования функции digitalWrite. Используется макрос ReadPort(D,3). Определение PIN_KEY осталось только для того что бы помнить куда кнопку вешать.
LeOS используется первой версии, которая использует таймер.
В субботу тестировал устройство. Нашел одну ошибку (при замене функции digitalWrite не проверил) - не получается обнулить счетчики при нажатой кнопке. Было (строки 210 - 212)
поправить на
После этого обнуление настроек будет происходить
Дальность получается метров 50 + 2 стены бетонные 40 см по диагонале. Плохо что квитанции не приходят и около 5% пакетов теряются. Фото устройства в подвале (подсветка работы вентилятора):
Информационный экран (долгое нажатие на кнопку)
Прототип приемника на stm32 и 2.8 дисплеем:
Не хочет работать кнопка... Строки -210-213 заменил... У меня режим "ДЕМО" т.к. не приехали еще датчики... Может это причина?
Пытаюсть разобраться в коде, но пока не все ясно. Например -кнопка должна быть подтянута к +5 ? Я уже пробовал и к +5 через 10к резистор, и земле - результата увы нет. где я накосячил?
Логика управления кнопкой ? как устанавливать режим? или пока есть только вывод экрана статистики? Эти вопросы возникают, т.к. пока не вижу результата нажатия кнопки..
Может встроить вывод состояния кнопки в Serial port, в режиме "Debug"?
Мне приехал модуль реле с оптопарами - вкл. реле по логическому "0". В результате логика обратная.. Попытка заменить в строках (вер. 0.51) не приводило к изменению логики реле...
На каких модулях "Дальность получается метров 50 " ? Тех, что без наружных антенн?
Заказал maple mini. Уже в пути.
Еще один момент - Судя по-всему в датчиках DHT21 и DHT22 не точный датчик температуры. В моем фабричном контроллере влажности установлено 2 датчика -DHT21 и DS12b20 (или аналогичный) в герметичном исполнении. А в инструкции написано, что этот датчик необходим для более точного определения влажности...
На фото ,см выше, рядом с "скворечником" тоже видно 2 отдельных датчика.
Это мой
http://ru.aliexpress.com/premium/WH8040.html?ltype=wholesale&SearchText=WH8040&d=y&origin=y&initiative_id=SB_20150831002334&isViewCP=y&catId=0
1. Кнопка у меня работает. Через 10к вывод кнопки на +5. Кнопка замыкающая. Активный уровень 0. У меня кнопка повешена на прерывание (пин кнопки менять нельзя). Для кнопки сначала железо проверьте, даю код для проверки (без прерываний)
Логика кнопки следующая:
- при нажатой кнопке включение блока - происходит обнуление счетчиков и настроек (надо делать хотя бы один раз для очистки памяти)
- в работающем блоке короткое нажатие по кругу перебирает заданные режимы (7 шт) режим отображается на дисплее синим
- в работающем блоке длиное нажатие выводит экран информации (есть ложные рабатывания, пока не понял почему)
debug можно поставить, раскоментировать соответсвующий ключ и добавить нужные строчки.
2. По реле - обычно есть на шильде перемычка приводящая к инверсии сигналов. если нет то (в последней версии) поменяйте макросы
на
и в функции setup вызовите MOTOR_OFF один раз что бы при включении вентилятор не работал.
3. Дальность 50 метров это с антеннами и усилителем.
4. По датчику темературы - ds1820 поточнее будет, НО!! Систематическую погрешность можну убрать калибровкой датчиков (нелинейность в узком диапазоне не так значительна). У меня уже есть учет систематической погрешности. см код
Вам для начала надо поставить одни "0" везде. Далее берете датчики и термометр (которому Вы верите, я использую ртутный лабораторный с делением 0.1 С) связываете вместе кладете в банку (что бы небыло скозников) и наблюдаете, 10 измерений в течении 2-3 часов и вычисляете среднюю ошибку и ставите в программу. Влажность берете усредняете если нет гигрометра. После этого Вы будете приятно удивлены полученной точностью.
Кнопку кодом проверил - мигает!. Инвертировал мотор и зодно нагреватель. тут все в порядке. НО!!! Проклятая кнопка никакой реакции в проге... Я сейчас ковыряюсь с УНО, до этого был НАНО, оба 328Р... результат одинаковый. Пищалка срабатывает один раз в конце старта..
Загадка!
Еще заметил, что нагреватель слишком чувствителен...думаю дельту в 1 градус надо.
Стоп! похоже обрыв на плате uno.. Сачс разберусь..
Так и есть! Китай рулит! Мало того, что D3 непропай чипа, так еще и новый провод перемычки на бредборд подорван.
Устранил. РАБОТАЕТ!!!
Теперь жду доставки железа... STM тоже заказан.
Отличный проект!
А такой модуль прицепить? Можно и без кнопок обойтись? Вроде SPI и ili9341
http://ru.aliexpress.com/item/3-2-Inch-TFT-LCD-Screen-240-320-40PIN-QVGA-SPI-For-ILI9341-Drive-IC-3line/32267594735.html?spm=2114.03020208.3.2.BdnW4I&ws_ab_test=201407_3,201444_5,201409_4
А такой модуль прицепить? Можно и без кнопок обойтись? Вроде SPI и ili9341
http://ru.aliexpress.com/item/3-2-Inch-TFT-LCD-Screen-240-320-40PIN-QVGA-SPI-For-ILI9341-Drive-IC-3line/32267594735.html?spm=2114.03020208.3.2.BdnW4I&ws_ab_test=201407_3,201444_5,201409_4
Скорее всего можно, вроде поддерживает три интерфейса 16 и 8 битный параллельный и spi. Последние три провода в шлейфе определяют выбор интерфейса (как контретно не понятно). Паять сложнее. Для разовых поделок нужно самому городить переходную плату. Я так же такие дисплеи смотрел но решил не заморачиваться, слишком много проблем.
Как продвигается проект? Я правильно понимаю -приемник будет принимать данные от нескольких управляющих систем? с переключением экранов?
Я подумал о дополнительно к вентилятору добавить управление заслонкой. Возможно шаговиком.
В зимнее время приточная работает сама по себе и может привести к повышению влажности независимо от системы.
Как продвигается проект? Я правильно понимаю -приемник будет принимать данные от нескольких управляющих систем? с переключением экранов?
Я подумал о дополнительно к вентилятору добавить управление заслонкой. Возможно шаговиком.
В зимнее время приточная работает сама по себе и может привести к повышению влажности независимо от системы.
1. Проект потихоньку продвигается. Было исправлена масса мелких ошибок. Было добавлено (из то что вспомнил)
- моточасы нагревателя. Теперь нагреватель по функционалу не уступает вентилятору.
- долго бился с nrf24. Перешел на библиотеку TMRh20 (http://tmrh20.github.io/RF24/). Эта библиотека наиболее свежая (конец 2014) и учитывает вся исправления. С этой библиотекой немного изменил режим отправки. В результате стабильность отправки возрасла. На расстоянии 50 метров доходит почти все. Квитанции о приеме также почти все доходят. Портировал эту библиотеку для stm32.
- немного поменял отображение графиков. Сделал подсветку синим - работу вентилятора желтым - работу нагревателя.
- сделал режимы в которых управление происходит не только по разнице абсолютных влажностей задаваемых в граммах на куб но и в % от влажности подвала. Наверное это более правильно.
Последняя версия кода
Одновременно делаю код приемника. Пока получается делать одну версию под avr и stm32 (условная компиляция). Приемник будет принимать данные от разных (не однотипных, тут пригодится ID) устройств. Планируется как минимум два осушителя (у меня два подвала), контроль за тепловым насосом отопления, и 2-3 удаленных термометра-гигрометра с автономным питанием. Переключение между устройствами будет происходить либо по энкодеру либо по кнопке (пока не решил).
2. По поводу заслонки. Я тоже думал об управляемой заслонке (подключение параллельно вентилятору). Но потом решил что хватит обратного клапана, входного давления (без вытяжного вентилятора) не хватит для открытия клапана. По этому "паразитная" вытяжка будет стремится к 0. Решение уже реализовано.
3. Сейчас погружаюсь в дебри измерения относительной влажности. Датчик DHT22 конечно лучше чем DHТ11 но его погрешность все равно очень большая. Его надо как минимум калибровать, а лучше заменить на что то более точное типа SHT75 (это дорого) или SHT21 (минус - фиксированный i2c адрес т.е. на одной шине один датчик).
Опробовал 0,64 версию на УНО . Пока нет датчиков, в режиме демо и с отключенным радио. Инвертировал, по Вашему совету, работу реле.
Вроде работает как надо. Но есть несоответствие с индикацией ...Реле ВЫКЛ. - Индикация ВКЛ. Пока не разобрался где логика индикации.
А нет ли возможности прописать индикацию что-бы отображалось 2 квадратика рядом : 1й- Синий вентилятор, 2й -красный калорифер ? Место там вроде есть. Т.к. бывают одновременные включения...
Ну и злая кнопка... режимы переключаются не четко, но более или менее .. А вот экран статистики вызвать удалось только один раз... Держал и 3сек и 10 сек без разницы... Сброс по включению работает четко...
Мжет это проблема дребезга контактов?
Насчет заслонки- я имел ввиду сокращение общего потребления системы за счет природной вентиляции. Т.е. заслонкой можно управлять пошагово и если потока не достаточно -включать вентилятор. Но это еще куча кода.. (на возможную перспективу)...
По поводу DHT. Гдето читал, что основная погрешность именно из-за температурного , встроенного датчика.
Видимо поэтому в регуляторе влажности wk8140t в паре с DHT21 стоит DS18B20. А в инструкции так и написано - для повышения точности измерения.
Вот внутри AM2303 стоит DS18B20.. По даташиту..
Опыт по DHT. Использую AM2301, что в целом аналог. Функции контроллера аналогичны, вместо подвала, термоизолированное помещение для хранения продуктов. Забор воздуха уличный снизу, вытяжка принудительная вверху, подогрев - четыре прожектора по 150 ватт с диммированием. Сделано усреднение температуры по высоте - забор воздуха из под потолка и подача через трубы к полу, гистерезис 3градуса.
Датчик поверял по NaCl, для нижних диапазонов ничего не было под рукой. За год эксплуатации, расхождение с контрольным прибором составляло 2-3% по отн.вл. Соответственно, на медленноидущих процессах вещь достаточно точная, не любит сквозняков и принудительного осаждения влаги (типа подышать). Если выбрать подходящее место, вполне можно юзать. ИМХО.
Я решил, что принудительный наддув, из нижней трубы, предпочтительнее.
1. Т.к. таким образом достигается получение более сухого воздуха и с меньшим содержанием пыли.
Не происходит подсос приземного воздуха (более влажного и пыльного) через неплотности двери, люка т .п.
2. Вентилятор довольно эффективно перемешивает воздух в помещении, тем самым устраняет необходимость усреднять температуру по высоте.
Недостаток - необходимо искать место для датчика, что бы не попадал в поток воздуха ..Таких мест много.
Из моего опыта- вентилятора VA-9 (9Вт), от болгарского дисковода на 29мб 1983г. , вполне достаточно для помещения 10м2 с высотой 2,5м .
Опробовал 0,64 версию на УНО . Пока нет датчиков, в режиме демо и с отключенным радио. Инвертировал, по Вашему совету, работу реле.
Вроде работает как надо. Но есть несоответствие с индикацией ...Реле ВЫКЛ. - Индикация ВКЛ. Пока не разобрался где логика индикации.
А нет ли возможности прописать индикацию что-бы отображалось 2 квадратика рядом : 1й- Синий вентилятор, 2й -красный калорифер ? Место там вроде есть. Т.к. бывают одновременные включения...
Ну и злая кнопка... режимы переключаются не четко, но более или менее .. А вот экран статистики вызвать удалось только один раз... Держал и 3сек и 10 сек без разницы... Сброс по включению работает четко...
Мжет это проблема дребезга контактов?
Насчет заслонки- я имел ввиду сокращение общего потребления системы за счет природной вентиляции. Т.е. заслонкой можно управлять пошагово и если потока не достаточно -включать вентилятор. Но это еще куча кода.. (на возможную перспективу)...
По поводу DHT. Гдето читал, что основная погрешность именно из-за температурного , встроенного датчика.
1. У меня индикация соответствует (значек и вентилятор работают синхронно). Может по факту у Вас реле не с инверсным выходом (поменять обратно как было код). Это единственное что мне приходит в голову.
2. По поводу двух квадратиков - можно но ИХМО не нужно. т.к. одновременое они гореть не будут. Нагреватель включается при температуре ниже +1.5 а вентилятор включается при температуре не ниже +3.0. Поэтому одного индикатора достаточно.
3. Кнопка - основная проблема дребезг контактов. Тут от кнопки много зависит. Можно RC цепь поставить 200 ом и 0.1 мкф между кнопкой и ножкой контроллера, должно помочь (резистор последовательно, конденсатор на ножку и землю). В очередной раз "оптимизировал код", вроде дребезга стало меньше.
4. Заслонка - наверное можно сделать, только без вентилятора воздух "естественным" путем будет плохо перемешиваться и будет большая неравномерность температур. И процесы будут очень медленные.
5. Датчик вызывывает много вопросов. На неделе он три дня показывал влажность 99.6. Думал кирдык ему. Но похоже влажность действительно была близка к 100%. Сейчас вроде показывает правильно. Надо его откалибровать (возможно по нескольким точкам). Тогда и доверия будет больше ему.
Понравился датчик sht21 он будет поточнее. Единственный недостаток нельзя изменить адрес по i2c шины и на шину можно вешать только один датчик, обидно.
6. Активно занимался выяснением качества связи датчик-головное устройство. Сделал счетчики на переданные пакеты и полученные квитанции. На небольших расстояниях теряется менее 1% пакетов, бывает что в течении суток потерь нет вообще и квитанции все доходят. У меня датчик стоит в бетонном подвале (две стены по 40 см), масса железа. Приемник относится на 70-80 метров связь при этом устойчивая. По дому все отлично работает. Но рассчитывать на дальности более 100-150 метров наверное не стоит.
1. модуль реле с оптопарами. на плате 4 шт. срабатывание по лог "0". Проверено, и логично т.к при неподключении входов реле выключено. С этим я разберусь...
2. В режиме "Демо" там включается все подряд..и включение 2х реле одновременно не редкость... Потому и возник вопрос разделения индикации...И вопрос -нет колизии из-за индикации?
3,4,5 тут все ясно..
6. -вполне устраивает такая дальность..
Не пошла компиляция.... Сам пока не разобрался..
Ver._0.66_11-09-15.ino: In function 'void send_packet()':
В демо тоже одновременно не может срабатывать и вентилятор и нагреватель. У вас вентилятор работает с инверсией. Сначала разберитесь с ветилятором, а потом вернетесь к этому вопросу. Проверте вентилятор в режиме выключено и вытяжка. Он работает правильно?
Ошибка компиляции связана с тем что линкер не находит функций библиотеки. Надо ставить не классическую библиотеку rf24 аTMRh20 (http://tmrh20.github.io/RF24/) там эти функции есть. Об этом я писал в предыдущем посте, и то сто ИХМО это лучшая библиотека.
2. "Ошибка компиляции связана с тем что линкер не находит функций библиотеки. Надо ставить не классическую библиотеку rf24 аTMRh20 (http://tmrh20.github.io/RF24/) там эти функции есть. Об этом я писал в предыдущем посте, и то сто ИХМО это лучшая библиотека. "
1. Еще раз проверил - программа работает правильно (и работала).. Проблема в том, что у меня уже смонтирован 4х релейный модуль с гальванической развязкой оптопарами. Срабатывание реле по низкому уровню. Поэтому и хотел инвертировать управление в программе...Но пока неудачно..
2. Перепутал библиотеки...уже их куча. :) вопрос закрыт.
? Появился режим "Охлаждение" ? Какой принцип (Устройство)?
Спасибо за подсказки.
Не могу найти все библиотеки , в часности rusFont , дайте ссылочку. :)
И еще 2 датчика DHT22 ,строки 105 и 106 , один на улице , второй в доме , а подвал где?
Не могу найти все библиотеки , в часности rusFont , дайте ссылочку. :)
И еще 2 датчика DHT22 ,строки 105 и 106 , один на улице , второй в доме , а подвал где?
rusfont весь находится в конце первого скеча. Только поправьте коментарии вначале....
2.В доме и есть -подвал.. :)
Можно поподробней про коментарии вначале...
файл фонтов
http://arduino.ru/sites/all/libraries/syntaxhighlighter/styles/printer.png) !important; background-repeat: no-repeat !important;" title="расечатать">расечататьhttp://arduino.ru/sites/all/libraries/syntaxhighlighter/styles/help.png) !important; background-repeat: no-repeat !important;" title="?">?
001
/ Русский шрифт 10х14 ------------------------------------------------------
002
const
ucg_fntpgm_uint8_t my14x10rus[4157] UCG_SECTION(
".progmem.my14x10"
)
еще одну косую в коментарии добавить //Русский шрифт 10х14 ----------
:)
Спасибо не обратил внимания :))
Добрался до паяльника. Поставил RC цепь на кнопку. После этого кнопка стала работать хорошо. Ставил резистор 220 ом и конденсатор 0.1 мкф.
Режим охлаждения это режим для лета. Влажность вообще не учитывается. Если в подвале больше 10 градусов и тепература на улице меньше не 2 градуса включается вентилятор. По задумке холодные ночи должны охлаждать подвал.
Будем пробовать с рекомендованной RC цепочкой...Схема подключения цепочки? Как у меня?
Спасибо..
П.С.
Приехала часть железа: Радиомодули и Stm32f103rcbt6 ARM Cortex-M3 мини модуль для arduino STM32...
А датчики еще в пути..
Теперь понадобятся билиотеки и остальной софт под STM32. Ну и узнать алгоритм обмена между модулем(ями) и базой...:)