#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
// Пины для датчика температуры DS18B20
#define ONE_WIRE_BUS 2
// Пины для ультразвукового датчика HC-SR04
#define TRIGGER_PIN 3
#define ECHO_PIN 4
// Пины для светодиодов
#define RED_LED_PIN 5
#define GREEN_LED_PIN 6
#define BLUE_LED_PIN 7
// Пины для шагового двигателя
#define A_PLUS_PIN 8
#define A_MINUS_PIN 9
#define B_PLUS_PIN 10
#define B_MINUS_PIN 11
// Пин для зуммера
#define BUZZER_PIN 12
// Пин для управления сервоприводом
#define SERVO_PIN 13
// Пороговые значения для температуры
#define HIGH_TEMP_CRITICAL 30
#define LOW_TEMP_CRITICAL 15
#define HIGH_TEMP_NON_CRITICAL 29
#define LOW_TEMP_NON_CRITICAL 25
#define HIGH_TEMP_OK 24
#define LOW_TEMP_OK 22
// Инициализация для датчика температуры
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// Инициализация для ЖК-дисплея
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Инициализация сервопривода
Servo myservo;
enum Status {
OK,
NON_CRITICAL_ERROR,
CRITICAL_ERROR
};
enum DisplayMode {
SHOW_STATUS,
SHOW_VALUES
};
// Объявление функции setStatus
void setStatus(Status status, const char* reason, float temperature, float distance);
Status overallStatus = OK;
const char* statusReason = "All OK";
DisplayMode displayMode = SHOW_STATUS;
unsigned long lastDisplaySwitchTime = 0;
const unsigned long displaySwitchInterval = 30000; // 30 секунд
void setup() {
// Инициализация последовательного порта для отладки
Serial.begin(9600);
// Инициализация датчика температуры
sensors.begin();
// Инициализация пинов для светодиодов
pinMode(RED_LED_PIN, OUTPUT);
pinMode(GREEN_LED_PIN, OUTPUT);
pinMode(BLUE_LED_PIN, OUTPUT);
// Инициализация пинов для шагового двигателя
pinMode(A_PLUS_PIN, OUTPUT);
pinMode(A_MINUS_PIN, OUTPUT);
pinMode(B_PLUS_PIN, OUTPUT);
pinMode(B_MINUS_PIN, OUTPUT);
// Инициализация пина для зуммера
pinMode(BUZZER_PIN, OUTPUT);
// Инициализация пинов для ультразвукового датчика
pinMode(TRIGGER_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
// Инициализация сервопривода
myservo.attach(SERVO_PIN);
// Инициализация ЖК-дисплея
lcd.init();
lcd.backlight();
}
void loop() {
overallStatus = OK;
statusReason = "All OK";
// Считывание температуры
sensors.requestTemperatures();
float temperatureC = sensors.getTempCByIndex(0);
// Считывание уровня воды
long duration;
float distanceCM;
digitalWrite(TRIGGER_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIGGER_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIGGER_PIN, LOW);
duration = pulseIn(ECHO_PIN, HIGH);
distanceCM = duration * 0.034 / 2;
// Проверка уровня воды
if (distanceCM > 40) {
setStatus(CRITICAL_ERROR, "Water Level RED", temperatureC, distanceCM);
} else if (distanceCM > 20 && distanceCM <= 40) {
setStatus(NON_CRITICAL_ERROR, "Water Level BLUE", temperatureC, distanceCM);
} else {
setStatus(OK, "Water Level GREEN", temperatureC, distanceCM);
}
// Проверка температуры
if (temperatureC <= LOW_TEMP_CRITICAL || temperatureC >= HIGH_TEMP_CRITICAL) {
setStatus(CRITICAL_ERROR, "Temperature RED", temperatureC, distanceCM);
} else if ((temperatureC > LOW_TEMP_CRITICAL && temperatureC < LOW_TEMP_OK) ||
(temperatureC > HIGH_TEMP_OK && temperatureC < HIGH_TEMP_NON_CRITICAL)) {
setStatus(NON_CRITICAL_ERROR, "Temperature BLUE", temperatureC, distanceCM);
} else {
setStatus(OK, "Temperature OK", temperatureC, distanceCM);
}
// Резюмирующее сообщение
Serial.print("Summary - Temperature: ");
Serial.print(temperatureC);
Serial.print(" C, Distance: ");
Serial.print(distanceCM);
Serial.print(" cm, Status: ");
switch (overallStatus) {
case OK:
Serial.println("OK");
break;
case NON_CRITICAL_ERROR:
Serial.println("WARNING");
break;
case CRITICAL_ERROR:
Serial.println("ERROR");
break;
}
// Управление шаговым двигателем в зависимости от температуры
if (temperatureC > 25.0) { // Включаем шаговый двигатель при температуре выше 25°C
stepMotor(1, 1, 0, 0);
delay(100);
stepMotor(0, 1, 1, 0);
delay(100);
stepMotor(0, 0, 1, 1);
delay(100);
stepMotor(1, 0, 0, 1);
delay(100);
} else { // Останавливаем шаговый двигатель при нормальной температуре
stepMotor(0, 0, 0, 0);
}
// Управление системой аэрации
if (temperatureC > 25.0) { // Включаем аэрацию при температуре выше 25°C
myservo.write(90); // Включить сервопривод
} else {
myservo.write(0); // Выключить сервопривод
}
// Управление зуммером
digitalWrite(BUZZER_PIN, HIGH);
delay(100);
digitalWrite(BUZZER_PIN, LOW);
delay(100);
// Обновление дисплея каждые 30 секунд
if (millis() - lastDisplaySwitchTime >= displaySwitchInterval) {
lastDisplaySwitchTime = millis();
if (displayMode == SHOW_STATUS) {
displayMode = SHOW_VALUES;
} else {
displayMode = SHOW_STATUS;
}
updateDisplay(temperatureC, distanceCM);
}
delay(2000); // Задержка перед обновлением
}
void updateDisplay(float temperature, float distance) {
lcd.clear();
if (displayMode == SHOW_STATUS) {
lcd.setCursor(0, 0);
switch (overallStatus) {
case OK:
lcd.print("Status: OK");
break;
case NON_CRITICAL_ERROR:
lcd.print("Status: WARNING");
break;
case CRITICAL_ERROR:
lcd.print("Status: ERROR");
break;
}
lcd.setCursor(0, 1);
lcd.print(statusReason);
} else if (displayMode == SHOW_VALUES) {
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(temperature);
lcd.print(" C");
lcd.setCursor(0, 1);
lcd.print("Dist: ");
lcd.print(distance);
lcd.print(" cm");
}
}
void setStatus(Status status, const char* reason, float temperature, float distance) {
if (status == CRITICAL_ERROR) {
overallStatus = CRITICAL_ERROR;
statusReason = reason;
} else if (status == NON_CRITICAL_ERROR && overallStatus != CRITICAL_ERROR) {
overallStatus = NON_CRITICAL_ERROR;
statusReason = reason;
}
// Обновляем дисплей сразу при смене статуса
updateDisplay(temperature, distance);
}
void stepMotor(int aPlus, int aMinus, int bPlus, int bMinus) {
digitalWrite(A_PLUS_PIN, aPlus);
digitalWrite(A_MINUS_PIN, aMinus);
digitalWrite(B_PLUS_PIN, bPlus);
digitalWrite(B_MINUS_PIN, bMinus);
}