#include <dht.h> // подключаем библиотеку для датчика
#include <SPI.h>
#include <SD.h>
File myFile;
#define PIN_DHT22a 5 // Первый датчик DHT22 IN ДОМ
#define PIN_DHT22b 4 // Второй датчик DHT22 OUT УЛИЦА
#define ID 0x21 // уникально Идентификатор устройства (тип) - старшие 4 бита, вторые (младшие) 4 бита серийный номер устройства
const int RELAY_PIN = 3; // the Arduino pin, which connects to the IN pin of relay
// СИСТЕМАТИЧЕСКИЕ ОШИБКИ ДАТЧИКОВ для каждого ID свой. ОШИБКИ ДОБАВЛЯЮТСЯ!!
#if ID == 0x21 // ОТКАЛИБРОВАНО не менять
#define TOUT_ERR +10 // Ошибка уличного датчика температуры в сотых долях градуса
#define TIN_ERR +50 // Ошибка домового датчика температуры в сотых долях градуса
#define HOUT_ERR -0 // Ошибка уличного датчика влажности в сотых долях %
#define HIN_ERR +50 // Ошибка домового датчика влажности в сотых долях %
#elif ID == 0x22 // ОТКАЛИБРОВАНО не менять
#define TOUT_ERR +50 // Ошибка уличного датчика температуры в сотых долях градуса +50
#define TIN_ERR +50 // Ошибка домового датчика температуры в сотых долях градуса +50
#define HOUT_ERR -230+60 // Ошибка уличного датчика влажности в сотых долях % -260
#define HIN_ERR +490 // Ошибка домового датчика влажности в сотых долях % +480
#else
#define TOUT_ERR 0 // Ошибка уличного датчика температуры в сотых долях градуса
#define TIN_ERR 0 // Ошибка домового датчика температуры в сотых долях градуса
#define HOUT_ERR 0 // Ошибка уличного датчика влажности в сотых долях %
#define HIN_ERR 0 // Ошибка домового датчика влажности в сотых долях %
#endif
// - ВРЕМЕНА ---------------------------------------
#define NUM_SAMPLES 10 // Число усреднений измерений датчика
#define TIME_SCAN_SENSOR 3000 // Время опроса датчиков мсек ТОЛЬКО целые тысячи для точности часов
#define TIME_PRINT_CHART 300000 // Время вывода точки графика мсек
#define TIME_HOUR 3600000 // Число мсек в часе
dht DHT;
struct type_sensors : public Printable // структура для усреднения измерений
{
int num=0; // сколько отсчетов уже сложили не болле NUM_SAMPLES
long sum_tOut=0,sum_tIn=0; // Сумма для усреднения Текущие температуры в сотых градуса !!! место экономим
long sum_relHOut=0,sum_relHIn=0; // Сумма для усреднения Относительные влажности сотых процента !!! место экономим
int tOut=-5000,tIn=5000; // Текущие температуры в сотых градуса !!! место экономим
int absHOut=55555,absHIn=55555; // Абсолютные влажности в сотых грамма на м*3 !!! место экономим
int relHOut=55555,relHIn=55555; // Относительные влажности сотых процента !!! место экономим
size_t printTo(Print& p) const { // в качестве p нам передадут, например, Serial
size_t res = p.print("SENSOR VALUE: tIn:");
res += p.print(tIn);
res += p.print("C; tOut:");
res += p.print(tOut);
res += p.print("C; HIn:");
res += p.print(absHIn);
res += p.print("%; HOut:");
res += p.print(absHOut);
res += p.print("%; relHIn:");
res += p.print(relHIn);
res += p.print("%; relHOut:");
res += p.print(relHOut);
res += p.print("%");
}
} sensors;
struct type_packet_NRF24 // Версия 2.4!! адаптация для stm32 Структура передаваемого пакета 32 байта - 32 максимум
{
byte id=ID; // Идентификатор типа устройства - старшие 4 бита, вторые (младшие) 4 бита серийный номер устройства
byte DHT_error; // Ошибка разряды: 0-1 первый датчик (00-ок) 2-3 второй датчик (00-ок) 4 - радиоканал
int16_t tOut=-500,tIn=500; // Текущие температуры в сотых градуса !!! место экономим
uint16_t absHOut=123,absHIn=123; // Абсолютные влажности в сотых грамма на м*3 !!! место экономим
uint16_t relHOut=123,relHIn=123; // Относительные влажности сотых процента !!! место экономим
uint8_t flags=0x00; // байт флагов
// 0 бит - мотор включен/выключен
// 1 бит - нагреватель включен/выключен
// 2 бит -[1 - dH_min задается в сотых грамма на м*3] [0 - dH_min задается в ДЕСЯТЫХ процента от absHIn]
// 3-4 - пока пусто
// 5-7 - номер настройки = settingRAM.mode до 8 настроек, надо передавать, что бы на приемнике восстановить
uint8_t dH_min; // Порог включения вентилятора по РАЗНИЦЕ абсолютной влажности в сотых грамма на м*3 или в ДЕСЯТЫХ % см flags:2
uint8_t T_min; // Порог выключения вентилятора по температуре в ДЕСЯТЫХ долях градуса, только положительные значения
uint8_t count=0; // циклический счетчик отправленных пакетов нужен что бы на приемнике проверять качество связи
char note[14] = LABEL; // Примечание не более 13 байт + "0" байт Русские буквы в два раза меньше т.к. UTF-8
} packet;
void setup() {
pinMode(PIN_DHT22a, OUTPUT); // Датчик DHT22 #1
digitalWrite(PIN_DHT22a, HIGH);
pinMode(PIN_DHT22b, OUTPUT); // Датчик DHT22 #2
digitalWrite(PIN_DHT22b, HIGH);
Serial.begin(9600);
//Serial.print(sensors);
// Open serial communications and wait for port to open:
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.print("Initializing SD card...");
if (!SD.begin(10)) {
Serial.println("initialization failed!");
while (1);
}
Serial.println("initialization done.");
// open a new file and immediately close it:
Serial.println("Creating htemp.txt...");
myFile = SD.open("htemp.txt", FILE_WRITE);
myFile.print("millis, ");
myFile.print("22sens2h, ");
myFile.print("22sens2t, ");
myFile.print("22sens3h, ");
myFile.print("22sens3t, ");
myFile.print("11sens4h, ");
myFile.print("11sens4t, ");
myFile.print("11sens5h, ");
myFile.println("11sens5t, ");
myFile.close();
}
void loop() {
if (millis() % 60 == 0) {
// считываем температуру (t) и влажность (h)
sensors.tIn=(int)(DHT.temperature*100.0)+TIN_ERR; // Запомнить результаты для суммирования с учетом ошибок
sensors.relHIn=(int)(DHT.humidity*100.0)+HIN_ERR;
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.DHT_error);
// float h2 = dht2.readHumidity();
// float t2 = dht2.readTemperature();
// выводим температуру (t) и влажность (h) на монитор порта
// Serial.print("Humidity2: ");
// Serial.println(h2);
// Serial.print("Temperature2: ");
// Serial.println(t2);
// считываем температуру (t) и влажность (h)
// float h3 = dht3.readHumidity();
// float t3 = dht3.readTemperature();
// выводим температуру (t) и влажность (h) на монитор порта
// Serial.print("Humidity3: ");
// Serial.println(h3);
// Serial.print("Temperature3: ");
// Serial.println(t3);
// если прошло 5 секунд, то
//REAL_TIME = time.gettime("d-m-Y, H:i:s"); // записываем значение, считанное с часов реального времени, в переменную REAL_TIME
//LOUDNESS = analogRead(SOUND_SENSOR); // записываем значение, считанное с датчика звука, в переменную LOUDNESS
myFile = SD.open("htemp.txt", FILE_WRITE); // создаём файл test.txt для записи значений
myFile.print(millis());
myFile.println(sensors);
myFile.close(); // закрываем файл
}
void printFile(){
File textFile = SD.open("htemp.txt");
if (textFile) {
Serial.print("htemp.txt: ");
while (textFile.available()) {
Serial.write(textFile.read());
}
textFile.close();
} else {
Serial.println("error opening htemp.txt!");
}
}
}
byte readDHT(byte pin)
{
//delay(5);
cli();
byte err=-1*DHT.read22(pin); // Чтение датчика
sei();
return err;
}
void measurement()
{
packet.DHT_error=readDHT(PIN_DHT22a); // ПЕРВЫЙ ДАТЧИК ДОМ Новый пакет, сбросить все ошибки и прочитать первый датчик
sensors.tIn=(int)(DHT.temperature*100.0)+TIN_ERR; // Запомнить результаты для суммирования с учетом ошибок
sensors.relHIn=(int)(DHT.humidity*100.0)+HIN_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.DHT_error);
#endif
packet.DHT_error=packet.DHT_error+16*readDHT(PIN_DHT22b);// ВТОРОЙ ДАТЧИК УЛИЦА ошибки в старшие четыре бита
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.DHT_error);
#endif
print_error_DHT(); // Вывод ошибки чтения датчика при каждом чтении контроль за качеством связи с датчиками
if (packet.DHT_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_data(); // вывод усредненных значений
print_status(); // панель состояния
// Обновляем максимум и минимум температур в EEPROM
// Cделано не честно - обновляем раз в 30 секунд (NUM_SAMPLES*TIME_SCAN_SENSOR) а пишем раз в час, могут пропасть данные при сбросе
if (settingRAM.tInMax<packet.tIn) settingRAM.tInMax=packet.tIn;
else if (settingRAM.tInMin>packet.tIn) settingRAM.tInMin=packet.tIn;
if (settingRAM.tOutMax<packet.tOut) settingRAM.tOutMax=packet.tOut;
else if (settingRAM.tOutMin>packet.tOut) settingRAM.tOutMin=packet.tOut;
// Пишем в EEPROM не каждый раз!! экономим ресурс записей 100000 мин.
settingRAM.tick_eeprom++;
if (((long)settingRAM.tick_eeprom*NUM_SAMPLES*TIME_SCAN_SENSOR)>=(long)TIME_HOUR) // пора писать eeprom
{ writeEeprom(); settingRAM.tick_eeprom=0; }
// Запись статистики в EEPROM
if (FLAG_MOTOR_CHECK) ChartMotor=true; // Признак того что надо показывать включение мотора на графике
if (FLAG_HEAT_CHECK) ChartHeat=true; // Признак того что надо показывать включение нагревателя на графике
TimeChart++;
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
}
}
#ifdef RADIO // Радио модуль NRF42l
// Часы работают если только был получено время от головного блока (хотя бы один раз) в противном случае они даже не показываются на экране
if (tt>0) tt=tt+TIME_SCAN_SENSOR/1000; // Обновить текущее время - что бы часы шли и без связи с базовым блоком
#endif
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 print_error_DHT(void) // Печать ошибки чтения датчиков выводится при каждом чтении датчика
{
if (infoScreen==true) return; // если отображен информационный экран то ничего не выводим
// 1. печать ошибки чтения датчиков
if (packet.DHT_error!=last_error) // если статус ошибки поменялся то надо вывести если нет то не выводим - экономия время и нет мерцания
{
cli();
last_error=packet.DHT_error;
ucg.setColor(0, 0, 180); // Сначала стереть
ucg.drawBox(280, 0, 36, 18);
ucg.setPrintPos(280,18);
ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT);
if (packet.DHT_error>0)
{
ucg.setColor(255, 100, 100);
print_StrXY(280,18,F("0x"));
ucg.print( hex(packet.DHT_error >> 4));
ucg.print( hex(packet.DHT_error & 0x0f));
}
else { ucg.setColor(200, 240, 0); ucg.print(F(" ok ")); }
sei();
}
}