Полив растений в саду

Тема в разделе "Глядите, что я сделал", создана пользователем Evgeniy_, 22 апр 2013.

  1. Evgeniy_

    Evgeniy_ Нуб

    Всем привет!
    Решил автоматизировать полив в саду.
    В этом сезоне, так сказать, пробный вариант: 2 зоны полива - одна теплица и одна под открытым небом.
    Если всё будет работать, то в следующем сезоне добавлю зон полива и функций: управление с телефона, или еще что-нибудь)

    Задачи системы
    Открывать электромагнитные клапаны воды при следующих условиях:
    1. Почва в зоне полива сухая
    2. Вода в баке нагрелась до определенной температуры
    3. Вечернее время (оптимально для полива)

    Система имеет дисплей, где можно посмотреть время/дату по последним 10 поливам, текущую влажность почвы по обеим зонам, температуру воды в баке, влажность почвы при которой осуществляется полив (возможность изменения границы сухости должны присутствовать в интерфейсе)

    Оборудование
    Arduino UNO - 1 шт.
    Датчик влажности почвы - 2 шт.
    2-Channel Relay Module - 1 шт.
    16x2 LCD Display HD44780 - 1 шт.
    Модуль реального времени I2C RTC DS1307 AT24C32 - 1 шт.
    Терморезистор 10К в водонепроницаемом корпусе (для бака с водой) - 1 шт.

    Доп.оборудование:
    Электромагнитные краны 12в - 2 шт.
    Шланги капельного полива с форсунками
    ИБП 220в для поддержки заряда аккума 12в, от которого работает система (при отключении электричества система будет работать несколько дней)


    Это мой первый проект на ардуино, с кодом вроде разобрался, а по схеме вопрос возник:

    В инете нашел 2 схемы подключения модуля реального времени I2C RTC DS1307

    Вариант 1:
    [​IMG]

    Вариант 2:
    То же самое, только с добавлением сопротивлений перед аналоговыми контактами.
    [​IMG]
    Как правильно подключать этот модуль?
    Что за пунктирная линия на второй цифровой пин в верхнем рисунке?

    Знающие люди - выручайте)
     
  2. roggedhorse

    roggedhorse Гик

    Самый лучший способ: заглянуть в даташит http://datasheets.maximintegrated.com/en/ds/DS1307.pdf

    Поскольку это I2C (TWI) устройство, то как правило на шине используются подтягивающие резисторы 10К.
    Кроме того в даташите на странице 6 в таблице Pin Desription написано: "The SDA pin is open drain and requires an external pullup resistor"
    То же самое про SCL

    И про SQW: "The SQW/OUT pin is open drain and requires an external pullup resistor"


    По моему мнению схема №2 корректна


    P.S. Возможно, что схема №1 тоже норм. Но на фотке не видно, какой именно это модуль. А так можно было бы заглянуть в его описание и схему и обоснованно принять решение по первой схеме - казнить или помиловать
     
    Evgeniy_ и Megakoteyka нравится это.
  3. Megakoteyka

    Megakoteyka Оракул Модератор

    Обычно самая правильная схема включения бывает в даташите - в нем резисторы показаны.
     
    Evgeniy_ и roggedhorse нравится это.
  4. Evgeniy_

    Evgeniy_ Нуб

    Спасибо за ответы! Осталось дождаться прихода недостающих модулей и можно собирать) По мере сборки напишу отчет - буду рад советам
     
  5. roggedhorse

    roggedhorse Гик

    Я использовал в качестве погружного термосенсора залитый эпоксидной смолой DS18B20.
    Работал на пятерку с плюсом
     
    Evgeniy_ нравится это.
  6. Evgeniy_

    Evgeniy_ Нуб

  7. Megakoteyka

    Megakoteyka Оракул Модератор

    Evgeniy_ и roggedhorse нравится это.
  8. roggedhorse

    roggedhorse Гик

    По моему мнению DS18 предпочтительнее терморезистора.
     
    Evgeniy_ и Megakoteyka нравится это.
  9. Evgeniy_

    Evgeniy_ Нуб

    Действительно, вижу, что DS18B20 более функциональный, но под задачи проекта даже погрешность в пару градусов не критична. Если вода в бочке не холодная - можно поливать. Поставлю то, что уже купил, но буду иметь ввиду как ресурс для улучшения)
     
  10. Megakoteyka

    Megakoteyka Оракул Модератор

    Главная фишка DS18B20 - однопроводный интерфейс 1-Wire. Датчики в минимальном варианте подключения вешаются на общую шину, состоящую из земли и сигнального провода, и опрашиваются методом обращения к каждому датчику (у датчиков есть адреса). Таким образом, можно опрашивать целую толпу датчиков, висящих на одной ножке контроллера.
     
    Evgeniy_ нравится это.
  11. roggedhorse

    roggedhorse Гик

    еще один плюс: на эту же шину при желании вешаются не только датчики, но и исполнительные устройства

    http://www.maximintegrated.com/pl_list.cfm/filter/21/ln/en
     
    Megakoteyka и Evgeniy_ нравится это.
  12. Evgeniy_

    Evgeniy_ Нуб

    Набросал пробную версию скетча. Пока без дисплея и модуля реального времени (спасибо почте России)... Для отладки настроил вывод в seral-порт. Но столкнулся с такой проблемой: не знаю как вернуться к началу выполнения функции loop() из другой функции.

    У меня функция void editSoilMax() ждет нажатия клавиш. Если клавиша не нажата 5 секунд - вывожу на экран текущее значение переменной soilMax() и хочу вернуться к началу функции loop(), но продолжает крутиться editSoilMax() :(
    добавление строки loop(); не помогает

    PHP:
    // Пины:
    // Дисплей: 2, 3, 4, 5, 11, 12 (13 - подсветка)
    // Реле: 9, 10
    // Модуль времени: А4, А5
    // Датчики влажности почвы: А2, А3
    // Датчик температуры воды: А1
    // Кнопки: А0
     
    int soil1Pin = 2; //пин датчика почвы 1
    int soil2Pin = 3; //пин датчика почвы 2
    int relay1Pin = 9; //пин реле 1
    int relay2Pin = 10; //пин реле 2
     
    //состояния для реле
    int ON = 0;
    int OFF = 1;
     
    double normTemp = 30.0; //допустимая температура воды
    int soilMax = 900; // влажность почвы
    int button = 0; //состояние кнопок
     
    void setup()
    {
      digitalWrite(relay1Pin, OFF);
      digitalWrite(relay2Pin, OFF);
      pinMode(relay1Pin, OUTPUT);
      pinMode(relay2Pin, OUTPUT);
     
      Serial.begin(9600);
    }
     
     
    double GetWaterTemp() //Получение температуры воды в баке
    {
      double temp;
      temp = log(((10240000/analogRead(1)) - 10000));
      temp = 1 / (0.001129148 + (0.000234125 * temp) + (0.0000000876741 * temp * temp * temp));
      temp = temp - 273.15;
      return temp;
    }
     
    void loop()
    {
     
      button=analogRead(0);//считываем сигнал с пина 0
         
        if(button>675&&button<690)
        {
          //действие первой кнопки
          //здесь будет вывод краткой статистики на дисплей
          Serial.println("Knopka 1");
          delay(300);
        }
         
          if(button>845&&button<860)
        {
          // действие второй кнопки
          //здесь будет вывод детальной статистики на дисплей
          Serial.println("Knopka2");
          delay(300);
        }
         
        if(button>923&&button<935)
        {
          // действие третьей кнопки
          editSoilMax();
        }
         
      //кнопки не нажаты - проверяем датчики
      if(analogRead(soil1Pin)>soilMax)
      {
        if(GetWaterTemp()>normTemp)
        {
          //поливаем первую зону
            digitalWrite(relay1Pin, ON);
            delay(10000);
            digitalWrite(relay1Pin, OFF);
        }
      }
     
      if(analogRead(soil2Pin)>soilMax)
      {
        if(GetWaterTemp()>normTemp)
        {
          //поливаем вторую зону
            digitalWrite(relay2Pin, ON);
            delay(10000);
            digitalWrite(relay2Pin, OFF);
        }
      }
     
     
     
    }
     
    void editSoilMax() //изменение soilMsx - ждем нажатия клавиши
    {
      // здесь будет выводиться на экран текущее значение siolMax
      Serial.print("soilMax=");
      Serial.println(soilMax);
      delay(300); //задержка для кнопки
     
      for (int i=0; i <= 50; i++){
        button=analogRead(0);//считываем сигнал с пина 0
     
        if(button>675&&button<690)
        {
          editSoilMinus();
        }
         
        if(button>845&&button<860)
        {
          editSoilPlus();
        }
          delay(100); //задержка для счетчика
      }
      //клавиша не нажата - выводим сообщение о возврате в исходное состояние
      //здесь будет вывод сообщения
      Serial.print("Novoe znachenie soilMax=");
      Serial.println(soilMax);
     
    }
     
    void editSoilPlus()
    {
      soilMax = soilMax + 10;
      editSoilMax();
    }
     
    void editSoilMinus()
    {
      soilMax = soilMax - 10;
      editSoilMax();
    }
     
  13. Не заметил где void editSoilMax() ждет нажатия клавиш 5 секунд?
    К тому же есть подозрение что в LOOP программа возвращается но опять попадает в editSoilMax().
    Поставь перед входом в editSoilMax() вывод в сериал чего нить, будет понятно что происходит.
     
  14. Evgeniy_

    Evgeniy_ Нуб

    Вот цикл из 50 выполнений с задержкой 100мс:

    PHP:
      for (int i=0; i <= 50; i++){
        button=analogRead(0);//считываем сигнал с пина 0
     
        if(button>675&&button<690)
        {
          editSoilMinus();
        }
     
        if(button>845&&button<860)
        {
          editSoilPlus();
        }
          delay(100); //задержка для счетчика
      }
    ок. попробую поставить
     
  15. Не, Так у вас точно не получиться.

    Получается:
    Из editSoilMax() вызывается editSoilPlus() а она опять вызывает editSoilMax() .
    И так по кругу.

    Во первых уберите editSoilMax(); из editSoilPlus() и editSoilMinus().
    Программа и так вернется назад.

    Но и это решение не корректное.

    На мой взгляд решение должно быть примерно таким:

    Нажатие клавишей всегда обрабатывает одна и та же функция.
    Но результат обработки зависит от того в каком режиме находится устройство.

    Т.е.

    Пишите 3 функции Button1, Button2, Button3. И в основном теле программы опрашиваете чего там нажалось.
    Если нажата кнопка 3, то проваливаетесь в Button3 а вот она уже смотрит откуда в каком режиме вы находитесь.

    Насколько я понял, по нажатию на кнопку три должен появиться режим задания параметров.
    Для этого заведите флаг IsSeting = false
    По попаданию в Button3 проверяем флаг если он был false то ставим в true.

    А в функциях Button1 И Butto2 проверяем данный флаг. Если он False то вызываем вывод доп информации ну или чего там вы планировали,
    а если true то вызываете editSoilPlus() или editSoilMinus() .
     
    Megakoteyka и Evgeniy_ нравится это.
  16. Evgeniy_

    Evgeniy_ Нуб

    понял. благодарю!
     
  17. Megakoteyka

    Megakoteyka Оракул Модератор

    А еще это чревато переполнением стека.
     
    Evgeniy_ и roggedhorse нравится это.
  18. Evgeniy_

    Evgeniy_ Нуб

    Переписал скетч. Теперь работает))

    PHP:
    // Пины:
    // Дисплей: 2, 3, 4, 5, 11, 12 (13 - подсветка)
    // Реле: 9, 10
    // Модуль времени: А4, А5
    // Датчики влажности почвы: А2, А3
    // Датчик температуры воды: А1
    // Кнопки: А0
     
    int soil1Pin = 2; //пин датчика почвы 1
    int soil2Pin = 3; //пин датчика почвы 2
    int relay1Pin = 9; //пин реле 1
    int relay2Pin = 10; //пин реле 2
     
    //состояния для реле
    int ON = 0;
    int OFF = 1;
     
    double normTemp = 30.0; //допустимая температура воды
    int soilMax = 900; // влажность почвы
    int button = 0; //состояние кнопок
    int isSettings = 0; //режим настроек
     
    void setup()
    {
      digitalWrite(relay1Pin, OFF);
      digitalWrite(relay2Pin, OFF);
      pinMode(relay1Pin, OUTPUT);
      pinMode(relay2Pin, OUTPUT);
     
      Serial.begin(9600);
    }
     
     
    double GetWaterTemp() //Получение температуры воды в баке
    {
      double temp;
      temp = log(((10240000/analogRead(1)) - 10000));
      temp = 1 / (0.001129148 + (0.000234125 * temp) + (0.0000000876741 * temp * temp * temp));
      temp = temp - 273.15;
      return temp;
    }
     
    void loop()
    {
     
      button=analogRead(0);//считываем сигнал с пина 0
           
        if(button>675&&button<690)
        {
          //действие первой кнопки
          button1();
        }
           
          if(button>845&&button<855)
        {
          // действие второй кнопки
          button2();
        }
           
        if(button>920&&button<935)
        {
          // действие третьей кнопки
          button3();
        }
     
           
      //кнопки не нажаты - проверяем датчики
      if(analogRead(soil1Pin)>soilMax)
      {
        if(GetWaterTemp()>normTemp)
        {
          //поливаем первую зону
            digitalWrite(relay1Pin, ON);
            delay(10000);
            digitalWrite(relay1Pin, OFF);
        }
      }
     
      if(analogRead(soil2Pin)>soilMax)
      {
        if(GetWaterTemp()>normTemp)
        {
          //поливаем вторую зону
            digitalWrite(relay2Pin, ON);
            delay(10000);
            digitalWrite(relay2Pin, OFF);
        }
      }
     
     
     
    }
     
    void button1()
    {
      if(isSettings == 0) {
        //здесь будет вывод краткой статистики на дисплей
        Serial.println("Knopka 1");
        delay(300);
      }
     
      if(isSettings == 1) {
        editSoilMinus();
        delay(300);
      }
     
      if(isSettings == 2) {
        editSoilMinus();
        delay(300);
      }
    }
     
     
    void button2()
    {
      if(isSettings == 0) {
        //здесь будет вывод подробной статистики на дисплей
        Serial.println("Knopka 2");
        delay(300);
      }
     
      if(isSettings == 1) {
        editSoilPlus();
        delay(300);
      }
     
      if(isSettings == 2) {
        editSoilPlus();
        delay(300);
      }
    }
     
     
    void button3()
    {
      if(isSettings == 0) {
        // здесь будет выводиться на экран текущее значение soilMax
        Serial.print("soilMax=");
        Serial.println(soilMax);
        isSettings = 1;
        delay(300);
        loop();
      }
     
      if(isSettings == 2) {
        //здесь будет вывод сообщения о новом значении soilMax
        Serial.print("Novoe znachenie soilMax=");
        Serial.println(soilMax);
        isSettings = 0;
        delay(1000);
      }
    }
     
     
    void editSoilPlus()
    {
      soilMax = soilMax + 10;
      isSettings = 2;
      Serial.println(soilMax);
    }
     
    void editSoilMinus()
    {
      soilMax = soilMax - 10;
        isSettings = 2;
      Serial.println(soilMax);
    }
     
  19. Вот и славно. Тут конечно есть, что оптимизировать.
    И совет, по поводу отладки, очень полезно делать так:

    Код (Text):

    boolean isDebug = true;
     
    void setup()
    {
      if (isDebug) {Serial.begin(9600);}
    }
     
    LOOP
    {
    if (isDebug) { Serial.print("Start watering, Pomp pin: "); Serial.println(nPomp[Pomp]);}
    }
    В этом случае переключив isDebug на false отключаются все выводы в сериал.
     
    Evgeniy_ нравится это.
  20. roggedhorse

    roggedhorse Гик

    а еще можно писать так


    Код (Text):
    #define isDebug true
    что правильнее (компактнее код)
     
    Evgeniy_ и Megakoteyka нравится это.