// Подключаем библиотеки
#include <Wire.h> // Библиотека для работы с I2C
#include <OneWire.h> // Библиотека для работы с 1-Wire устройствами (например, DS18B20)
#include <DallasTemperature.h> // Библиотека для работы с датчиками температуры Dallas
#include <LiquidCrystal.h> // Библиотека для работы с LCD дисплеем
// подключение дисплея
/*
The LCD circuit:
* LCD R/W pin to ground
* LCD VSS pin to ground
* LCD VCC pin to 5V
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
*/
#define D7_PIN 19 // пин LCD D7
#define D6_PIN 18 // пин LCD D6
#define D5_PIN 17 // пин LCD D5
#define D4_PIN 16 // пин LCD D4
#define EN_PIN 15 // пин LCD Enable
#define RS_PIN 14 // пин LCD RS
// Определяем пины и устройства
#define ONE_WIRE_BUS 2 // Пин, к которому подключен датчик температуры
#define BUTTON_PIN 3 // Пин, к которому подключена кнопка переключения режима
#define BUTTON_MANUAL_PIN 4 // Пин, к которому подключена кнопка для ручного управления клапаном
#define VALVE_PIN 5 // Пин, к которому подключен клапан
#define FEEDBACK_PIN 6 // Пин, к которому подключен сигнал обратной связи
#define EMERGENCY_LED_PIN 7 // Пин, к которому подключен светодиод аварийного сигнала
#define LED_STATE_PIN 8 // Пин, к которому подключен светодиод, указывающий на состояние клапана
#define LED_PROCESS_PIN 10 // Пин, к которому подключен светодиод, указывающий на процесс открытия/закрытия клапана
// Создаем объекты для работы с температурным датчиком и LCD дисплеем
OneWire oneWire(ONE_WIRE_BUS); // Создаем объект OneWire для работы с 1-Wire устройствами
DallasTemperature sensors(&oneWire); // Создаем объект для работы с датчиками температуры Dallas
LiquidCrystal lcd(RS_PIN, EN_PIN, D4_PIN, D5_PIN, D6_PIN, D7_PIN); // Создаем объект для работы с LCD дисплеем
// Глобальные переменные для состояния клапана, режима работы и времени последнего изменения состояния клапана
boolean butt_flag = 0; // Последнее состояние кнопки на вкл(выкл) клапана
boolean butt; // Текущее состояние кнопки на вкл(выкл) клапана
bool valveState = false; // Изначальное состояние клапана - закрыт
bool mode = false; // Изначальный режим работы - автоматический
uint32_t valveChangeTime; // Время последнего изменения состояния клапана
void setup() {
// Устанавливаем пины в нужный режим
pinMode(BUTTON_PIN, INPUT_PULLUP); // Кнопка переключения режима - вход
pinMode(BUTTON_MANUAL_PIN, INPUT_PULLUP); // Кнопка для ручного вкл(выкл) клапана - вход
pinMode(VALVE_PIN, OUTPUT); // Клапан - выход
pinMode(FEEDBACK_PIN, INPUT_PULLUP); // Сигнал обратной связи - вход
pinMode(EMERGENCY_LED_PIN, OUTPUT); // Светодиод аварийного сигнала - выход
pinMode(LED_STATE_PIN, OUTPUT); // Светодиод, указывающий на состояние клапана - выход
pinMode(LED_PROCESS_PIN, OUTPUT); // Светодиод, указывающий на процесс открытия/закрытия клапана - выход
// Запускаем датчик и LCD дисплей
sensors.begin(); // Запускаем датчик температуры
lcd.begin(20, 4); // Инициализируем LCD дисплей
// Запуск серийного порта для отладочных сообщений
Serial.begin(9600);
}
void checkEmergency() {
// Если состояние клапана не соответствует состоянию обратной связи и прошло больше 2 минут, то включаем аварийную сигнализацию
if (valveState != digitalRead(FEEDBACK_PIN) && millis() - valveChangeTime > 120000) { // Если состояние клапана не соответствует состоянию обратной связи и прошло больше 2 минут...
digitalWrite(EMERGENCY_LED_PIN, HIGH); // ... то включаем светодиод аварийного сигнала
lcd.setCursor(0, 3); // Устанавливаем курсор на начало четвертой строки
lcd.blink(); // Включаем мигание курсора
lcd.print("EMERGENCY!!!"); // Выводим на LCD дисплей надпись "EMERGENCY!!!"
} else { // Если состояние клапана соответствует состоянию обратной связи или прошло меньше 2 минут...
digitalWrite(EMERGENCY_LED_PIN, LOW); // ... то выключаем светодиод аварийного сигнала
lcd.noBlink(); // Выключаем мигание курсора
lcd.setCursor(0, 3); // Устанавливаем курсор на начало четвертой строки
lcd.print(" "); // Очищаем четвертую строку
}
}
// Функция для управления сигнальными лампами
void controlLeds() {
// Если состояние клапана изменилось...
if (valveState != digitalRead(FEEDBACK_PIN)) {
digitalWrite(LED_STATE_PIN, LOW);
digitalWrite(LED_PROCESS_PIN, HIGH); // ... то включаем светодиод, указывающий на процесс открытия/закрытия клапана
} else { // Если состояние клапана не изменилось...
digitalWrite(LED_PROCESS_PIN, LOW); // ... то выключаем светодиод, указывающий на процесс открытия/закрытия клапана
digitalWrite(LED_STATE_PIN, HIGH);
}
}
void loop() {
// Считываем текущее состояние кнопки на вкл(выкл) клапана
butt = !digitalRead(BUTTON_MANUAL_PIN);
// Запрашиваем данные с датчика и выводим температуру на LCD дисплей
sensors.requestTemperatures(); // Запрашиваем данные с датчика температуры
float temperature = sensors.getTempCByIndex(0); // Получаем температуру первого датчика в градусах Цельсия
lcd.setCursor(0, 0); // Устанавливаем курсор на начало первой строки
lcd.print("\240AK \244A\250O\247. HA-"); // Выводим на LCD дисплей надпись "БАК ЗАПОЛ. НА -"
lcd.setCursor(15, 0);
lcd.print(temperature,0); // Выводим на LCD дисплей значение температуры
lcd.setCursor(19, 0);
lcd.print("%"); // Выводим на LCD дисплей знак %
// Проверяем состояние кнопки для переключения режима
if (digitalRead(BUTTON_PIN)) { // Если кнопка нажата...
mode = false; // ... то режим работы ручной
delay(200); // Пауза для исключения дребезга контактов кнопки
} else { // Если кнопка отжата...
mode = true; // ... то режим работы автоматический
delay(200); // Пауза для исключения дребезга контактов кнопки
}
// Выводим текущий режим на LCD дисплей
lcd.setCursor(0, 1); // Устанавливаем курсор на начало второй строки
lcd.print("PE\243\245M PA\240OT\256 -"); // Выводим на LCD дисплей надпись "РЕЖИМ -"
lcd.print(mode ? " P\251\253H." : " ABTO"); // Выводим на LCD дисплей текущий режим работы
// В автоматическом режиме открываем и закрываем клапан в зависимости от температуры
if (mode == false) { // Если режим работы - автоматический...
if (temperature >= 20.0 && valveState == false) { // ... и температура больше или равна 20 градусам, а клапан закрыт...
valveState = true; // ... то открываем клапан
} else if (temperature < 19.0 && valveState == true) { // ... и температура меньше 19 градусов, а клапан открыт...
valveState = false; // ... то закрываем клапан
}
}
// В ручном режиме открываем и закрываем клапан по нажатию кнопки
if (mode == true && butt == true && butt_flag == false) { // Если режим работы - ручной и нажата кнопка для ручного управления клапаном...
valveState = !valveState; // ... то меняем состояние клапана на противоположное
delay(200); // Пауза для исключения дребезга контактов кнопки
butt_flag = 1;
Serial.println ("Button pressed");
}
if (mode == true && butt == false && butt_flag == true) { // Если режим работы - ручной и отжата кнопка для ручного управления клапаном...
butt_flag = 0;
Serial.println ("Button released");
}
// Управляем клапаном
digitalWrite(VALVE_PIN, valveState ? HIGH : LOW); // Если клапан должен быть открыт, то подаем на пин клапана высокий уровень, иначе - низкий
// Выводим состояние клапана на LCD дисплей
lcd.setCursor(0, 2); // Устанавливаем курсор на начало третьей строки
lcd.print("KPAH -"); // Выводим на LCD дисплей надпись "KPAH -"
if (digitalRead(VALVE_PIN) == HIGH) {
lcd.print(" OTKP.");
}
if (digitalRead(VALVE_PIN) == LOW) {
lcd.print(" \244AKP.");
}
// Проверяем состояние аварийной сигнализации
checkEmergency(); // Вызываем функцию для проверки аварийной сигнализации
// Управляем сигнальными лампами
controlLeds(); // Вызываем функцию для управления сигнальными лампами
}