изначально был таймер включения света, потом добавил датчик температуры, обогреватель, датчик со2, датчик кислотности воды.
Описание системы
Этот код управляет аквариумной системой с помощью Arduino, включая следующие функции:
Мониторинг параметров:
Температура воды (2 датчика: DS18B20 и термистор)
Уровень pH воды
Концентрация CO2
Уровень освещенности
Управление системами:
Нагреватель (включение/выключение по температуре)
Освещение (по таймеру)
Подача CO2
Помпа фильтра
Интерфейс
LCD дисплей для отображения информации
Кнопки для навигации и изменения настроек
Логика работы:
Автоматическое поддержание температуры
Работа освещения по расписанию
Регулярный мониторинг параметров воды
Система предназначена для автоматического поддержания оптимальных условий в аквариуме с возможностью ручной настройки параметров через кнопочный интерфейс.
#include <LiquidCrystal.h>
#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
#include <BH1750.h>
#include <OneWire.h>
// Инициализация LCD дисплея (пины RS, Enable, D4, D5, D6, D7)
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// Переменные для кнопок
bool up, down, left, right, select;
// Настройки реле
int8_t display; // Текущий экран дисплея
int8_t tempreleyON = 25; // Температура включения нагревателя
int8_t lightreleyON = 11; // Время включения света (час)
int8_t tempreleyOFF = 25; // Температура выключения нагревателя
int8_t lightreleyOFF = 11; // Время выключения света (час)
int8_t activeid = 0; // Активный элемент меню
// Определение пинов для реле
#define NAGREV 2 // Пин нагревателя
#define SVET 3 // Пин освещения
#define POMPA 4 // Пин помпы
#define KLAPAN 5 // Пин клапана CO2
#define pwmPin 6 // Пин датчика CO2
#define datchiktemp 11 // Пин датчика температуры DS18B20
// Переменные для датчиков
float calibration_value = 29.2; // Калибровочное значение для pH
int phval = 0;
unsigned long int avgval;
int buffer_arr[10], temp;
// Задержки для измерений
long zaderzhka_ph = 0;
long zaderzhka_co = 0;
// Состояния систем
int svetlo = 1; // Состояние света (1-выкл, 0-вкл)
int kislota = 1; // Состояние CO2
int teplo = 1; // Состояние нагревателя
// Переменные для термистора
int ThermistorPin = A1;
int Vo;
float R1 = 10000; // Значение резистора в делителе напряжения
float logR2, R2, T;
// Коэффициенты Штейнхарта-Харта для термистора
float c1 = 0.001129148, c2 = 0.000234125, c3 = 0.0000000876741;
// Инициализация датчика температуры DS18B20
OneWire ds(datchiktemp);
// Инициализация датчика освещенности
BH1750 lightMeter;
void setup() {
// Настройка пинов реле
pinMode(KLAPAN, OUTPUT);
pinMode(POMPA, OUTPUT);
pinMode(SVET, OUTPUT);
pinMode(NAGREV, OUTPUT);
// Начальное состояние реле
digitalWrite(KLAPAN, HIGH); // Клапан CO2 выключен
digitalWrite(POMPA, LOW); // Помпа выключена
digitalWrite(SVET, HIGH); // Свет выключен
digitalWrite(NAGREV, HIGH); // Нагреватель выключен
// Инициализация последовательного порта
Serial.begin(9600);
while (!Serial); // Ожидание подключения Serial Monitor
delay(200);
// Инициализация датчика освещенности
lightMeter.begin();
// Инициализация LCD дисплея
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.setCursor(0,1);
}
void loop() {
// Чтение текущего времени
tmElements_t tm;
RTC.read(tm);
// Измерение освещенности
float lux = lightMeter.readLightLevel();
// Измерение pH
measurePH();
// Измерение CO2
measureCO2();
// Измерение температуры
float temperature = measureTemperature();
// Управление системами
controlSystems(tm, temperature);
// Отображение информации на LCD
updateDisplay(tm, temperature);
// Обработка нажатий кнопок
handleButtons();
}
// Функция измерения pH
void measurePH() {
// Чтение 10 значений для усреднения
for(int i=0; i<10; i++) {
buffer_arr[i] = analogRead(A0);
delay(30);
}
// Сортировка значений для медианного фильтра
for(int i=0; i<9; i++) {
for(int j=i+1; j<10; j++) {
if(buffer_arr[i] > buffer_arr[j]) {
temp = buffer_arr[i];
buffer_arr[i] = buffer_arr[j];
buffer_arr[j] = temp;
}
}
}
// Усреднение 6 средних значений
avgval = 0;
for(int i=2; i<8; i++) {
avgval += buffer_arr[i];
}
// Преобразование в напряжение и расчет pH
float volt = (float)avgval * 5.0 / 1024 / 6;
float ph_act = -5.70 * volt + calibration_value;
// Вывод pH на дисплей
lcd.setCursor(0, 0);
lcd.print("pH:");
lcd.setCursor(4, 0);
lcd.print(ph_act);
}
// Функция измерения CO2
void measureCO2() {
long tt = millis();
int myVal = digitalRead(pwmPin);
// Обнаружение изменения сигнала
if (myVal == HIGH) {
if (myVal != prevVal) {
h = tt;
tl = h - l;
prevVal = myVal;
}
} else {
if (myVal != prevVal) {
l = tt;
th = l - h;
prevVal = myVal;
// Расчет концентрации CO2 в ppm
ppm = 5000 * (th - 2) / (th + tl - 4);
lcd.setCursor(10, 0);
lcd.print("ppm:" + String(ppm) + "*");
}
}
}
// Функция измерения температуры
float measureTemperature() {
// Для DS18B20
byte data[2];
ds.reset();
ds.write(0xCC);
ds.write(0x44); // Команда измерения температуры
delay(1000); // Ожидание измерения
ds.reset();
ds.write(0xCC);
ds.write(0xBE); // Чтение значения температуры
data[0] = ds.read(); // Младший байт
data[1] = ds.read(); // Старший байт
int temperature = ((data[1] << 8) | data[0]) * 0.0625;
// Для термистора
Vo = analogRead(ThermistorPin);
R2 = R1 * (1023.0 / (float)Vo - 1.0);
logR2 = log(R2);
T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
T = T - 273.15;
return temperature; // Возвращаем значение с DS18B20
}
// Функция управления системами
void controlSystems(tmElements_t tm, float temperature) {
// Управление светом по времени
if (tm.Hour > 10 && tm.Hour < 20 && svetlo == 1) {
digitalWrite(SVET, LOW);
lcd.setCursor(0, 3);
lcd.print("*");
svetlo = 0;
}
if (tm.Hour > 20 && svetlo == 0) {
digitalWrite(SVET, HIGH);
lcd.setCursor(0, 3);
lcd.print("x");
svetlo = 1;
}
// Управление нагревателем по температуре
if (temperature < 23 && teplo == 1) {
digitalWrite(NAGREV, LOW);
lcd.setCursor(9, 3);
lcd.print("~");
teplo = 0;
}
if (temperature > tempreley && teplo == 0) {
digitalWrite(NAGREV, HIGH);
lcd.setCursor(9, 3);
lcd.print("-");
teplo = 1;
}
}
// Функция обновления дисплея
void updateDisplay(tmElements_t tm, float temperature) {
switch(display) {
case 0: // Главный экран
lcd.clear();
if (RTC.read(tm)) {
lcd.setCursor(11,0);
lcd.print(tm.Hour);
lcd.print(":");
lcd.print(tm.Minute);
}
lcd.setCursor(0,1);
lcd.print("t:");
lcd.print(tempreley);
break;
case 1: // Настройки света
lcd.clear();
lcd.setCursor(0,1);
lcd.print("L:");
lcd.print(lightreley);
delay(1000);
break;
case 2: // Запасной экран
lcd.setCursor(0,1);
lcd.print("SETTINGS");
delay(1000);
break;
case 3: // Запасной экран
lcd.setCursor(0,1);
lcd.print("OPTIONS");
delay(1000);
break;
case 4: // Возврат к главному экрану
display = 0;
break;
}
}
// Функция обработки кнопок
void handleButtons() {
int x = analogRead(0);
if (x < 60) {
right = 1;
delay(1000);
} else if (x < 200) {
up = 1;
delay(1000);
} else if (x < 400) {
down = 1;
delay(1000);
} else if (x < 600) {
left = 1;
delay(1000);
} else if (x < 800) {
select = 1;
delay(1000);
} else {
select = 0;
left = 0;
up = 0;
down = 0;
right = 0;
}
// Обработка навигации
if (left) display--;
if (right) display++;
if (select) activeid++;
if (activeid == 10) activeid = 0;
// Изменение параметров
if (up && activeid == 1) tempreleyON++;
if (down && activeid == 1) tempreleyON--;
if (up && activeid == 1) tempreleyOFF++;
if (down && activeid == 1) tempreleyOFF--;
if (up && activeid == 2) lightreleyON++;
if (down && activeid == 2) lightreleyON--;
if (up && activeid == 2) lightreleyOFF++;
if (down && activeid == 2) lightreleyOFF--;
}
Блог только запустил, все статьи генерирую через нейросеть т.к. лень, возможны ошибки. Просто чтобы вы знали и не запускали ядерный реактор по моим статьям ))
Если у вас есть вопросы, или Нашли неточность? пишите в коментах — вместе поправим и сделаем статью более качественной. Я лично объясню нюансы из практики.
Комментарии
Пока нет комментариев. Будьте первым!