#include <Wire.h>
#include <DallasTemperature.h>
#include <DHT.h>
#include <Encoder.h>
#include <Bounce2.h>
#include "Adafruit_SSD1306.h"
#define DHTPIN 2
#define DHTTYPE DHT22
#define ENCODER_CLK 3
#define ENCODER_DT 4
#define ENCODER_SW 5
#define RELAY_PIN_plusTemp 9 // Пин, к которому подключено реле
#define RELAY_PIN_minusTemp 8 // Пин, к которому подключено реле
#define RELAY_PIN_plusHumidity 6 // Пин, к которому подключено реле
#define RELAY_PIN_minusHumidity 13 // Пин, к которому подключено реле
#define BUTTON_PIN2 12 // Пин, к которому подключена кнопка
#define BUTTON_PIN 7 // Пин, к которому подключена кнопка
#define LED_MODE_0 10 // Пин для светодиода, отображающего режим 0
#define LED_MODE_1 11 // Пин для светодиода, отображающего режим 1
#define LED_MODE_2 12 // Пин для светодиода, отображающего режим 1
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET 4 // Можно использовать любой цифровой пин
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
DHT dht(DHTPIN, DHTTYPE);
Encoder myEncoder(ENCODER_CLK, ENCODER_DT);
float Temperature; //температура
float targetTemperature; //переменная для целевой температуры
int targetHumidity; //переменная для целевой влажности
int humidity; //влажность
const float decreaseRate = 0.1; // скорость изменения температуры
const float decreaseRateHumidity = 1; // скорость изменения влажности
const int decreaseInterval = 1000;
unsigned long lastDecreaseTime = 0;
int mode; // Режим: 0 - температура, 1 - влажность
bool allowTargetTemperatureChange = false;
float temperatureChange;
float humidityChange;
long encoderPosition;
long newPosition;
Bounce debouncerButton = Bounce();
Bounce debouncerEncoderSW = Bounce();
void setup() {
Serial.begin(9600);
if (!display.begin(SSD1306_INVERSE, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.display();
delay(2000);
display.clearDisplay();
pinMode(LED_MODE_0, OUTPUT);
pinMode(LED_MODE_1, OUTPUT);
pinMode(LED_MODE_2, OUTPUT);
pinMode(ENCODER_SW, INPUT_PULLUP);
// Дебаунсер
debouncerEncoderSW.attach(ENCODER_SW, INPUT_PULLUP);
debouncerEncoderSW.interval(1); // Интервал дебаунсинга в миллисекундах
pinMode(ENCODER_CLK, INPUT);
pinMode(ENCODER_DT, INPUT);
pinMode(RELAY_PIN_plusTemp, OUTPUT);
pinMode(RELAY_PIN_minusTemp, OUTPUT);
pinMode(RELAY_PIN_plusHumidity, OUTPUT);
pinMode(RELAY_PIN_minusHumidity, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
// Дебаунсер
debouncerButton.attach(BUTTON_PIN, INPUT_PULLUP);
debouncerButton.interval(1); // Интервал дебаунсинга в миллисекундах
digitalWrite(RELAY_PIN_plusTemp, LOW);
digitalWrite(RELAY_PIN_minusTemp, LOW);
digitalWrite(RELAY_PIN_plusHumidity, LOW);
digitalWrite(RELAY_PIN_minusHumidity, LOW);
dht.begin();
humidity = dht.readHumidity();
terminalDelay();
}
void loop() {
displayAndDelay(Temperature, humidity); // Вывод данных на OLED дисплей
encoderMode();
rotaryEncoder();
buttonStart();
debouncerButton.update();
debouncerEncoderSW.update();
}
void terminalDelay(){
Serial.print(F("Влажность: "));
Serial.print(humidity);
Serial.print(F("%\nТемпература: "));
Serial.print(Temperature);
Serial.print(F("C"));
Serial.print(F("\nЦелевая температура: "));
Serial.print(targetTemperature);
Serial.print(F("C"));
Serial.print(F("\nЦелевая влажность: "));
Serial.print(targetHumidity);
Serial.print(F("%"));
}
void encoderMode(){
if (debouncerEncoderSW.fell()) {
// Изменение режима при каждом нажатии encoder SW
mode = (mode + 1) % 3; // Обновлено количество режимов
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
digitalWrite(LED_MODE_0, mode == 0 ? HIGH : LOW);
digitalWrite(LED_MODE_1, mode == 1 ? HIGH : LOW);
digitalWrite(LED_MODE_2, mode == 2 ? HIGH : LOW);
switch (mode) {
case 0:
display.print("Mode: Temperature");
allowTargetTemperatureChange = true;
break;
case 1:
display.print("Mode: Humidity");
allowTargetTemperatureChange = false;
break;
case 2:
display.print("Mode: Temperature & Humidity");
allowTargetTemperatureChange = true;
break;
}
display.display();
delay(1000);
}
}
void buttonStart(){
if (debouncerButton.fell()) {
Serial.println(F("\nButton pressed"));
startRelayCycle();
}
}
//Обработка вращения rotary encoder
void rotaryEncoder(){
newPosition = myEncoder.read();
if (newPosition != encoderPosition) {
if (mode == 0 && allowTargetTemperatureChange) {
temperatureChange = (newPosition - encoderPosition) / 40.0;
targetTemperature += temperatureChange;
} else if(mode == 1){
humidityChange = (newPosition - encoderPosition) / 0.4;
targetHumidity += humidityChange;
}
encoderPosition = newPosition;
}
}
void displayAndDelay(float temperature, int humidity) {
// Вывод данных на OLED дисплей
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Temp: ");
display.print(Temperature);
display.print("C");
display.setCursor(0, 10);
display.print("Humidity: ");
display.print(humidity);
display.print("%");
display.setCursor(0, 20);
display.print("Target Temp: ");
display.print(targetTemperature);
display.print("C");
display.setCursor(0, 30);
display.print("Target Humidity: ");
display.print(targetHumidity);
display.print("%");
display.display();
// Задержка для отображения данных
delay(100);
}
void startRelayCycle() {
Serial.println(F("Starting relay cycle"));
while (true) {
switch (mode) {
case 0:
if (Temperature - targetTemperature >= decreaseRate) {
// Уменьшаем температуру
digitalWrite(RELAY_PIN_minusTemp, HIGH);
Temperature -= decreaseRate;
} else if (targetTemperature - Temperature >= decreaseRate) {
// Увеличиваем температуру
digitalWrite(RELAY_PIN_plusTemp, HIGH);
Temperature += decreaseRate;
} else {
// Если цель достигнута, выходим из цикла
digitalWrite(RELAY_PIN_minusTemp, LOW);
digitalWrite(RELAY_PIN_plusTemp, LOW);
goto endCycle;
}
break;
case 1:
if (humidity - targetHumidity >= decreaseRateHumidity) {
// Уменьшаем влажность
digitalWrite(RELAY_PIN_minusHumidity, HIGH);
humidity -= decreaseRateHumidity;
} else if (targetHumidity - humidity >= decreaseRateHumidity) {
// Увеличиваем влажность
digitalWrite(RELAY_PIN_plusHumidity, HIGH);
humidity += decreaseRateHumidity;
} else {
// Если цель достигнута, выходим из цикла
digitalWrite(RELAY_PIN_plusHumidity, LOW);
digitalWrite(RELAY_PIN_minusHumidity, LOW);
goto endCycle;
}
break;
case 2:
// Режим 2: изменение и температуры, и влажности
// Уменьшаем температуру
if (Temperature - targetTemperature >= decreaseRate) {
digitalWrite(RELAY_PIN_minusTemp, HIGH);
Temperature -= decreaseRate;
} else if (targetTemperature - Temperature >= decreaseRate) {
digitalWrite(RELAY_PIN_plusTemp, HIGH);
Temperature += decreaseRate;
}
// Уменьшаем влажность
if (humidity - targetHumidity >= decreaseRateHumidity) {
digitalWrite(RELAY_PIN_minusHumidity, HIGH);
humidity -= decreaseRateHumidity;
} else if (targetHumidity - humidity >= decreaseRateHumidity) {
digitalWrite(RELAY_PIN_plusHumidity, HIGH);
humidity += decreaseRateHumidity;
}
// Проверяем, достигнуты ли цели
if ((Temperature <= targetTemperature + 0.1 && Temperature >= targetTemperature - 0.1) &&
(humidity <= targetHumidity + 1 && humidity >= targetHumidity - 1)) {
// Если цели достигнуты, выходим из цикла
digitalWrite(RELAY_PIN_minusHumidity, LOW);
digitalWrite(RELAY_PIN_plusHumidity, LOW);
digitalWrite(RELAY_PIN_minusTemp, LOW);
digitalWrite(RELAY_PIN_plusTemp, LOW);
goto endCycle;
}
break;
}
displayAndDelay(Temperature, humidity);
}
endCycle:
Serial.print(F("Relay cycle completed"));
}