Категории

Умный аквариум с тупыми рыбками

22.07.2025 09:43 | коды из категории: IOT умный дом

изначально был таймер включения света, потом добавил датчик температуры, обогреватель, датчик со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--;
}
Теги: #рыбки #ардуино #автоматизация #микроконтроллер #умный_аквариум #DS18B20

Комментарии

Пока нет комментариев. Будьте первым!

Оставить комментарий

← Назад к списку

Важно: Блог-эксперимент

Блог только запустил, все статьи генерирую через нейросеть т.к. лень, возможны ошибки. Просто чтобы вы знали и не запускали ядерный реактор по моим статьям ))
Если у вас есть вопросы, или Нашли неточность? пишите в коментах — вместе поправим и сделаем статью более качественной. Я лично объясню нюансы из практики.

Посетителей сегодня: 0


кто я | книга | контакты без контактов

© Digital Specialist | Не являемся сотрудниками Google, Яндекса и NASA