#include <OneWire.h>
#include <DallasTemperature.h>
#include <DHT.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Servo.h>
// Настройка пинов
#define DHTPIN 5 // DHT22 (влажность)
#define ONE_WIRE_BUS 6 // DS18B20 (температура)
#define BUTTON_PIN_UP 4 // + значения
#define BUTTON_PIN_DOWN 2 // - значения
#define BUTTON_PIN_SET 3 // = значение
#define SERVO_PIN 7 // Пин для подключения серво-привода
#define DHTTYPE DHT22
#define SCREEN_WIDTH 128 // Ширина OLED дисплея
#define SCREEN_HEIGHT 64 // Высота OLED дисплея
// Инициализация дисплея и серво-привода
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
Servo myServo;
int currentServoPosition = -1;
DHT dht(DHTPIN, DHTTYPE);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// Психрометрическая таблица ВИТ-1 (усеченная для примера)
int psychrometricTable[21][22] = {
{91, 83, 75, 66, 58, 50, 42, 34, 26, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{92, 84, 76, 67, 60, 52, 45, 37, 30, 22, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{92, 84, 77, 69, 62, 54, 47, 40, 33, 26, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{92, 85, 78, 70, 63, 56, 49, 42, 36, 29, 22, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{93, 86, 79, 71, 65, 58, 51, 45, 38, 32, 25, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{93, 86, 79, 73, 66, 60, 53, 47, 41, 34, 28, 22, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{93, 87, 80, 74, 67, 61, 55, 49, 43, 37, 31, 26, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{93, 87, 81, 75, 69, 63, 57, 51, 45, 40, 34, 28, 23, 18, 0, 0, 0, 0, 0, 0, 0, 0},
{94, 88, 82, 76, 70, 64, 58, 53, 47, 42, 36, 31, 26, 20, 0, 0, 0, 0, 0, 0, 0, 0},
{94, 88, 82, 76, 71, 65, 60, 54, 49, 44, 39, 33, 28, 23, 18, 0, 0, 0, 0, 0, 0, 0},
{94, 88, 83, 77, 72, 66, 61, 56, 51, 46, 41, 36, 31, 26, 21, 18, 0, 0, 0, 0, 0, 0},
{94, 89, 83, 78, 73, 68, 63, 57, 52, 48, 43, 38, 33, 29, 24, 20, 0, 0, 0, 0, 0, 0},
{95, 89, 84, 79, 74, 69, 64, 59, 54, 49, 45, 40, 35, 31, 27, 22, 19, 0, 0, 0, 0, 0},
{0, 90, 84, 79, 74, 70, 65, 60, 55, 51, 47, 42, 37, 33, 29, 24, 21, 17, 0, 0, 0, 0},
{0, 90, 85, 80, 75, 70, 66, 61, 57, 52, 48, 44, 39, 35, 31, 27, 23, 19, 0, 0, 0, 0},
{0, 90, 85, 81, 76, 71, 67, 63, 58, 54, 50, 45, 41, 37, 33, 29, 25, 22, 18, 0, 0, 0},
{0, 90, 85, 81, 77, 72, 68, 64, 59, 55, 51, 47, 43, 39, 35, 31, 28, 24, 21, 17, 0, 0},
{0, 91, 85, 82, 77, 73, 69, 64, 61, 56, 52, 48, 44, 41, 37, 33, 30, 26, 23, 19, 0, 0},
{0, 91, 86, 82, 78, 74, 70, 65, 62, 58, 54, 50, 46, 42, 39, 35, 32, 28, 25, 21, 18, 0},
{0, 91, 87, 83, 78, 74, 70, 66, 62, 59, 55, 51, 48, 44, 40, 37, 33, 30, 27, 24, 20, 0},
{0, 91, 87, 83, 79, 75, 71, 67, 63, 60, 56, 52, 49, 45, 42, 38, 35, 32, 29, 26, 22, 19}
};
// Разности температур для поиска
const float diffValues[] = {0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, 10.5, 11.0};
const int relay1Pin = 51;
// Переменная TR, начальное значение 94%
float TR = 94.0;
// Переменная TRY с начальным значением 94%
float TRY = 94.0;
unsigned long lastButtonPress = 0;
unsigned long lastDisplayUpdate = 0;
float roundToOneDecimal(float value) {
return round(value * 10.0) / 10.0;
}
void setup() {
pinMode(relay1Pin, OUTPUT);
Serial.begin(9600);
dht.begin();
sensors.begin();
pinMode(BUTTON_PIN_UP, INPUT_PULLUP); // +
pinMode(BUTTON_PIN_DOWN, INPUT_PULLUP); // -
pinMode(BUTTON_PIN_SET, INPUT_PULLUP); // TR = TRY
myServo.attach(SERVO_PIN);
myServo.write(0);
// Инициализация OLED дисплея
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("Не удалось найти OLED дисплей"));
for(;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Loading...");
display.display();
}
void loop() {
unsigned long currentMillis = millis();
// Проверка нажатия кнопок с использованием таймера
if (currentMillis - lastButtonPress > 200) { // Задержка для антидребезга кнопок
if (digitalRead(BUTTON_PIN_UP) == LOW) {
TRY = min(TRY + 0.5, 100.0);
lastButtonPress = currentMillis;
}
if (digitalRead(BUTTON_PIN_DOWN) == LOW) {
TRY = max(TRY - 0.5, 0.0);
lastButtonPress = currentMillis;
}
if (digitalRead(BUTTON_PIN_SET) == LOW) {
TR = TRY;
lastButtonPress = currentMillis;
}
}
// Получение температуры и влажности (не чаще одного раза в 2 секунды)
if (currentMillis - lastDisplayUpdate > 2000) {
sensors.requestTemperatures();
float tempDry = sensors.getTempCByIndex(0);
float humidity = dht.readHumidity();
if (!isnan(tempDry) && !isnan(humidity)) {
float tempWet = calculateWetBulbTemp(tempDry, humidity);
float tableHumidity = getHumidityFromTable(tempDry, tempDry - tempWet);
if (tableHumidity <= TR) {
myServo.write(90); // Поворачиваем серво на 90 градусов (открыть)
digitalWrite(relay1Pin,HIGH);
} else {
myServo.write(0); // Поворачиваем серво на 0 градусов (закрыть)
digitalWrite(relay1Pin,LOW);
}
// Отладка
Serial.print("Температура сухого термометра: ");
Serial.print(tempDry, 1);
Serial.println(" C");
Serial.print("Температура влажного термометра: ");
Serial.print(tempWet, 1);
Serial.println(" C");
Serial.print("Влажность воздуха: ");
Serial.print(humidity, 1);
Serial.println(" %");
Serial.print("Оценочная влажность (OV): ");
Serial.print(tableHumidity, 1);
Serial.println(" %");
Serial.println("---------------------------");
// Обновление дисплея
display.clearDisplay();
display.setCursor(0, 0);
display.print("Vl=");
display.print(humidity, 1);
display.println("%");
display.setCursor(0, 10);
display.print("oV=");
display.print(tableHumidity, 1);
display.println("%");
display.setCursor(0, 20);
display.print("TR=");
display.print(TR, 1);
display.println("%");
display.setCursor(0, 30);
display.print("TRY=");
display.print(TRY, 1);
display.println("%");
display.display();
}
lastDisplayUpdate = currentMillis;
}
}
// Функция для расчета температуры влажного термометра
float calculateWetBulbTemp(float tempDry, float humidity) {
// Психрометрическое уравнение для расчета температуры влажного термометра
float tempWet = tempDry * atan(0.151977 * sqrt(humidity + 8.313659)) +
atan(tempDry + humidity) -
atan(humidity - 1.676331) +
0.00391838 * pow(humidity, 1.5) * atan(0.023101 * humidity) - 4.686035;
return tempWet;
}
// Функция для получения влажности с таблицы
float getHumidityFromTable(float tempDry, float deltaTemp) {
int indexDry = constrain(round(tempDry) - 5, 0, 20);
int indexDeltaLower = 0, indexDeltaUpper = 0;
for (int i = 0; i < 22; i++) {
if (deltaTemp <= diffValues[i]) {
indexDeltaUpper = i;
indexDeltaLower = (i > 0) ? i - 1 : 0;
break;
}
}
if (deltaTemp == diffValues[indexDeltaLower]) {
return psychrometricTable[indexDry][indexDeltaLower];
} else if (deltaTemp == diffValues[indexDeltaUpper]) {
return psychrometricTable[indexDry][indexDeltaUpper];
}
float lowerHumidity = psychrometricTable[indexDry][indexDeltaLower];
float upperHumidity = psychrometricTable[indexDry][indexDeltaUpper];
float humidity = lowerHumidity + ((deltaTemp - diffValues[indexDeltaLower]) /
(diffValues[indexDeltaUpper] - diffValues[indexDeltaLower])) *
(upperHumidity - lowerHumidity);
return humidity;
}