Загрузка данных
// --- Библиотеки ---
#include <DHT.h>
#include <Servo.h> // Подключаем библиотеку для управления сервоприводом
// --- НАСТРОЙКИ ПИНОВ ---
#define DHTPIN 2 // Пин для датчика температуры DHT11
const int gasSensorPin = A1; // Аналоговый вход для датчика газа KY-026
const int fanRelayPin = 6; // Цифровой выход для реле вентилятора (KY-019)
const int gateLockRelayPin = 7;// Цифровой выход для реле блокировки ворот (мотор)
const int buzzerPin = 8; // Цифровой выход для активного зуммера
const int gateSensorPin = 3; // Цифровой пин для герконового датчика положения ворот
const int buttonGateControlPin = 4; // Кнопка для ручного управления воротами
const int servoPin = 9; // Пин для подключения сервопривода
// --- КОНФИГУРАЦИЯ СИСТЕМЫ ---
#define DHTTYPE DHT11 // Тип датчика DHT
const int GAS_THRESHOLD = 2800;
const float TEMP_THRESHOLD_HIGH = 26.0;
const float TEMP_THRESHOLD_LOW = 25.0;
const unsigned long FAN_DELAY_MS = 10000;
const unsigned long BUZZER_ON_DURATION = 1000;
const unsigned long BUZZER_OFF_DURATION = 1000;
const unsigned long GATE_OPEN_TIME = 3000; // Время открытия ворот мотором (мс)
// --- НОВЫЕ КОНФИГУРАЦИИ ДЛЯ СЕРВОПРИВОДА ---
const int SERVO_POS_CLOSED = 0; // Угол поворота для ЗАКРЫТОГО состояния
const int SERVO_POS_OPENED = 90; // Угол поворота для ОТКРЫТОГО состояния
// --- СОЗДАНИЕ ОБЪЕКТОВ И ПЕРЕМЕННЫЕ СОСТОЯНИЯ ---
DHT dht(DHTPIN, DHTTYPE);
Servo emergencyDoorServo; // Создаем объект Servo
bool isDangerModeActive = false;
unsigned long ventilationEndTime = 0;
float currentTemperature = 0.0;
int currentGasValue = 0;
// Переменные для зуммера
bool isBuzzerActive = false;
bool isBuzzerOn = false;
unsigned long lastBuzzerChangeTime = 0;
// Переменные для ручного управления воротами
bool gateRelayState = false;
unsigned long gateStartTime = 0;
void setup() {
Serial.begin(9600);
delay(1000);
Serial.println("=== ПОЛНАЯ СИСТЕМА БЕЗОПАСНОСТИ ===");
pinMode(fanRelayPin, OUTPUT);
pinMode(gateLockRelayPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
pinMode(gateSensorPin, INPUT_PULLUP);
pinMode(buttonGateControlPin, INPUT_PULLUP); // Используем внутренний резистор
digitalWrite(fanRelayPin, LOW);
digitalWrite(gateLockRelayPin, HIGH); // Изначально ворота не активны
digitalWrite(buzzerPin, LOW);
dht.begin();
// --- НАСТРОЙКА СЕРВОПРИВОДА ---
emergencyDoorServo.attach(servoPin);
emergencyDoorServo.write(SERVO_POS_CLOSED); // Стартовое положение - закрыто
}
void loop() {
// 1. ЧТЕНИЕ ДАТЧИКОВ
currentTemperature = dht.readTemperature();
if (isnan(currentTemperature)) {
Serial.println("Ошибка чтения данных с DHT11!");
return;
}
currentGasValue = analogRead(gasSensorPin);
// 2. ЛОГИКА ПЕРЕХОДОВ МЕЖДУ РЕЖИМАМИ (ГАЗ / ТЕМПЕРАТУРА)
bool shouldActivateAlarm = (currentGasValue >= GAS_THRESHOLD) || (currentTemperature >= TEMP_THRESHOLD_HIGH);
if (shouldActivateAlarm && !isDangerModeActive) {
activateSafetyMeasures();
} else if (!shouldActivateAlarm && isDangerModeActive) {
deactivateSafetyMeasures();
Serial.print("Угроза устранена. Вентиляция продолжит работу еще на ");
Serial.print(FAN_DELAY_MS / 1000);
Serial.println(" секунд.");
}
// 3. РУЧНОЕ УПРАВЛЕНИЕ ВОРОТАМИ (КНОПКА)
handleManualGateControl();
// 4. УПРАВЛЕНИЕ ВЕНТИЛЯТОРОМ ПО ТЕМПЕРАТУРЕ (вне режима опасности)
bool tempControlFanOn = false;
if (!isDangerModeActive) {
bool fanState = digitalRead(fanRelayPin);
if (!fanState && currentTemperature >= TEMP_THRESHOLD_HIGH) {
tempControlFanOn = true;
Serial.println("[АВТО] Вентилятор ВКЛЮЧЕН из-за высокой температуры.");
} else if (fanState && currentTemperature <= TEMP_THRESHOLD_LOW) {
tempControlFanOn = false;
Serial.println("[АВТО] Вентилятор ВЫКЛЮЧЕН. Температура нормализовалась.");
}
}
// 5. ФИНАЛЬНОЕ УПРАВЛЕНИЕ РЕЛЕ ВЕНТИЛЯТОРА
bool shouldTurnFanOnNow = isDangerModeActive || tempControlFanOn;
if (shouldTurnFanOnNow) {
ventilationEndTime = millis() + FAN_DELAY_MS;
Serial.print("Таймер вентиляции сброшен. Будет работать ");
Serial.print(FAN_DELAY_MS / 1000);
Serial.println(" сек.");
}
bool shouldFanBeOn = shouldTurnFanOnNow || (ventilationEndTime > millis());
digitalWrite(fanRelayPin, shouldFanBeOn ? HIGH : LOW);
// 6. УПРАВЛЕНИЕ ЗУММЕРОМ
manageBuzzer();
// 7. ВЫВОД СТАТУСА
printSystemStatus();
delay(2000);
}
// Функции активации/деактивации мер безопасности
void activateSafetyMeasures() {
isDangerModeActive = true;
ventilationEndTime = millis() + FAN_DELAY_MS;
digitalWrite(gateLockRelayPin, HIGH); // Включаем реле мотора ворот
emergencyDoorServo.write(SERVO_POS_OPENED); // Открываем механический засов
isBuzzerActive = true;
lastBuzzerChangeTime = millis();
isBuzzerOn = true;
digitalWrite(buzzerPin, HIGH);
Serial.println("\n!!! ТРЕВОГА: Ворота открываются автоматически !!!");
}
void deactivateSafetyMeasures() {
isDangerModeActive = false;
digitalWrite(gateLockRelayPin, LOW); // Выключаем реле мотора ворот
emergencyDoorServo.write(SERVO_POS_CLOSED); // Закрываем механический засов
isBuzzerActive = false;
digitalWrite(buzzerPin, LOW);
Serial.println("Действие: Автоматическое открытие ворот завершено.");
}
// Функция управления прерывистым звуком зуммера
void manageBuzzer() {
if (isBuzzerActive) {
unsigned long currentMillis = millis();
if ((isBuzzerOn && currentMillis - lastBuzzerChangeTime >= BUZZER_ON_DURATION) ||
(!isBuzzerOn && currentMillis - lastBuzzerChangeTime >= BUZZER_OFF_DURATION)) {
isBuzzerOn = !isBuzzerOn;
digitalWrite(buzzerPin, isBuzzerOn ? HIGH : LOW);
lastBuzzerChangeTime = currentMillis;
}
} else {
digitalWrite(buzzerPin, LOW);
}
}
// Функция ручного управления воротами (МОТОР + СЕРВО)
void handleManualGateControl() {
static bool lastButtonState = HIGH;
bool currentButtonState = digitalRead(buttonGateControlPin);
// Проверяем нажатие кнопки (по спадающему фронту)
if (lastButtonState == HIGH && currentButtonState == LOW) {
if (!gateRelayState) {
// Начинаем процесс открытия
digitalWrite(gateLockRelayPin, HIGH); // Включаем реле мотора
gateRelayState = true;
gateStartTime = millis();
Serial.println("Ворота: ОТКРЫТИЕ начато (кнопкой).");
}
}
lastButtonState = currentButtonState;
// Проверяем время работы мотора и останавливаем его
if (gateRelayState && (millis() - gateStartTime >= GATE_OPEN_TIME)) {
digitalWrite(gateLockRelayPin, LOW); // Останавливаем мотор
gateRelayState = false;
Serial.println("Ворота: СТОП (мотор выключен).");
}
// --- ЛОГИКА СЕРВОПРИВОДА ВРУЧНУЮ ---
// Эта часть работает всегда, но имеет приоритет ниже автоматического режима
// Если нет угрозы, серво управляется кнопкой напрямую
if (!isDangerModeActive) {
// Читаем кнопку снова для мгновенной реакции серво
bool manualButtonPressed = (digitalRead(buttonGateControlPin) == LOW);
if (manualButtonPressed) {
emergencyDoorServo.write(SERVO_POS_OPENED);
} else {
emergencyDoorServo.write(SERVO_POS_CLOSED);
}
}
}
// Функция вывода статуса системы
void printSystemStatus() {
static unsigned long lastPrintTime = 0;
if (millis() - lastPrintTime >= 2000) {
Serial.println("\n=== СТАТУС СИСТЕМЫ ===");
Serial.print("Температура: ");
Serial.print(currentTemperature);
Serial.print(" °C | Авто-включение: ");
Serial.print(TEMP_THRESHOLD_HIGH);
Serial.print(" °C | Выключение: ");
Serial.print(TEMP_THRESHOLD_LOW);
Serial.println(" °C");
Serial.print("Газ [RAW]: ");
Serial.print(currentGasValue);
Serial.print(" | Порог: ");
Serial.println(GAS_THRESHOLD);
Serial.print("Режим опасности: ");
Serial.println(isDangerModeActive ? "АКТИВЕН" : "НЕТ");
Serial.print("Сирена: ");
Serial.println(isBuzzerActive ? "ПРОГРЕВАЕТ" : "ВЫКЛЮЧЕНА");
Serial.print("Вентилятор: ");
Serial.println(digitalRead(fanRelayPin) == HIGH ? "ВКЛЮЧЕН" : "ВЫКЛЮЧЕН");
Serial.print("Мотор ворот: ");
Serial.println(digitalRead(gateLockRelayPin) == HIGH ? "ВКЛЮЧЕН" : "ВЫКЛЮЧЕН");
Serial.print("Серво-засов: ");
Serial.println(emergencyDoorServo.read() == SERVO_POS_OPENED ? "ОТКРЫТ" : "ЗАКРЫТ");
if (ventilationEndTime > millis()) {
unsigned long remainingSec = (ventilationEndTime - millis()) / 1000;
Serial.print("Таймер вентиляции: ");
Serial.print(remainingSec);
Serial.println(" сек осталось");
}
Serial.println("=======================");
lastPrintTime = millis();
}
}