Умный террариум

Тема в разделе "Глядите, что я сделал", создана пользователем aleksjet, 4 дек 2012.

  1. aleksjet

    aleksjet Нуб

    неа что то все мерцает и все ничего не могу придумать как раз сейчас разбираюсь с этим
     
  2. dreamerov

    dreamerov Нуб

    Слежу за веткой, тоже интересует меню и задание параметров кнопками.
     
  3. Megakoteyka

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

    Попробуйте код типа такого (только не забудьте поменять номера пинов на свои!):

    Код (Text):
    #include <Bounce.h>
    #include <LiquidCrystal.h>
     
    // состояние нажатой кнопки (зависит от способа подключения кнопки)
    #define BUTTON_PRESSED  HIGH
     
    // макрос для проверки нажатия на кнопку
    #define IS_BUTTON_PRESSED(btn)  (btn.update() && btn.read() == BUTTON_PRESSED)
     
    // количество параметров в меню
    #define OPTIONS_COUNT  3
     
    // структура описывает пункт меню
    typedef struct {
      byte value;// значение параметра
      char* name;// название параметра
    } MENU_ITEM;
     
    // номер текущего параметра
    int _itemIndex;
     
    // этот массив описывает меню
    MENU_ITEM _menuItems[] = {
      { 10, "Item 1" },
      { 20, "Item 2" },
      { 30, "Item 3" }
    };
     
    // дисплей
    LiquidCrystal _lcd(4, 5, 6, 7, 8, 9);
     
    // давилки дребезга для кнопок "ВЛЕВО", "ВПРАВО", "ПЛЮС" и "МИНУС"
    Bounce _bouncerLeft = Bounce(3, 40);
    Bounce _bouncerRight = Bounce(2, 40);
    Bounce _bouncerPlus = Bounce(10, 40);
    Bounce _bouncerMinus = Bounce(11, 40);
     
    // флаг "обновить дисплей"
    boolean _updateDisplay = true;
     
    void setup()
    {
      _itemIndex = 0;
     
      Serial.begin(9600);
     
      pinMode(2, INPUT);
      pinMode(3, INPUT);
      pinMode(10, INPUT);
      pinMode(11, INPUT);
     
      _lcd.begin(16, 2);
     
      UpdateDisplay();
    }
     
    void loop()
    {
      // левая кнопка
      if(IS_BUTTON_PRESSED(_bouncerLeft))
        ButtonHandlerL();
     
      // правая кнопка
      if(IS_BUTTON_PRESSED(_bouncerRight))
        ButtonHandlerR();
     
      // кнопка плюс
      if(IS_BUTTON_PRESSED(_bouncerPlus))
        ButtonHandlerP();
     
      // кнопка минус
      if(IS_BUTTON_PRESSED(_bouncerMinus))
        ButtonHandlerM();
     
      // если что-то изменилось - обновляем дисплей
      if(_updateDisplay)
        UpdateDisplay();
    }
     
    // обработчик кнопки "влево"
    void ButtonHandlerL()
    {
      _itemIndex = (_itemIndex > 0) ? _itemIndex - 1 : OPTIONS_COUNT - 1;
      _updateDisplay = true;
    }
     
    // обработчик кнопки "вправо"
    void ButtonHandlerR()
    {
      _itemIndex = (_itemIndex < (OPTIONS_COUNT - 1)) ? _itemIndex + 1 : 0;
      _updateDisplay = true;
    }
     
    // обработчик кнопки "плюс"
    void ButtonHandlerP()
    {
      _menuItems[_itemIndex].value++;
      _updateDisplay = true;
    }
     
    // обработчик кнопки "минус"
    void ButtonHandlerM()
    {
      _menuItems[_itemIndex].value--;
      _updateDisplay = true;
    }
     
    void UpdateDisplay()
    {
      // первая строка дисплея
      _lcd.clear();
      _lcd.print("ITEM:  ");
      _lcd.print(_menuItems[_itemIndex].name);
     
      // вторая строка дисплея
      _lcd.setCursor(0, 1);
      _lcd.print("VALUE: ");
      _lcd.print(_menuItems[_itemIndex].value);
     
      _updateDisplay = false;
    }
     
  4. kirex

    kirex Нуб

    Помогите пожалуйста. Вот для этого кода нужно плавное включение света в заданное время и плавное выключение в другое заданное время. Что-то у меня с плавностью никак не получается.

    Код (Text):
    // Библиотеки необходимые для работы модуля часов
    #include "Wire.h"
    #include "DS1307new.h"
    // библиотека экрана
    #include "LiquidCrystal.h"
    LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
    int hours;
    int minutes;
    int LW = 3;  
    int LR = 11;
    int LB = 12;  
    int On_Time =0;
    int Off_Time =0;
    int Curent_Time =0;
    void setup(){
      Serial.begin(9600);
      lcd.begin(16, 2); // запускаем библиотеку экрана
      pinMode(LW, OUTPUT);
      pinMode(LR, OUTPUT);
      pinMode(LB, OUTPUT);
    }
    void loop(){
      analogWrite(10, 100);
      RTC.getTime();// получить время от модуля
      RTC.hour;
      RTC.minute;
      printTimeToSerial(); // выводим полученное время в лог
      printTimeToLCD();; // выводи время на экран
      lcd.setCursor(0, 1);          // Set the cursor to column 0, line 1
      doSerialCommands(); // слушаем и выполняем команды из Serial
    On_Time=(20*60+27);
    Off_Time=(20*60+29);
    Curent_Time=RTC.hour*60+RTC.minute;//текущее время
    if(On_Time < Off_Time) //Проверка, таймер в течении одних суток?
      {
            if (Curent_Time >= On_Time && Curent_Time <= Off_Time)
                    for(int fadeValue = 0; fadeValue <= 255; fadeValue +=3)
              {
                    analogWrite(LR, fadeValue);
    }
      else
              for(int fadeValue = 255; fadeValue >= 0; fadeValue -=3)
              {
                    analogWrite(LR, fadeValue);
      }
    }
    else // если сутки сменились
    {
                    if ((Curent_Time >= On_Time && Curent_Time <= 2820)||(Curent_Time >= 0 && Curent_Time <= Off_Time))//2820=24часа*60
                    for(int fadeValue = 0; fadeValue <= 255; fadeValue +=3)
              {
                    analogWrite(LR, fadeValue);
            }
            else
              for(int fadeValue = 255; fadeValue >= 0; fadeValue -=3)
              {
                    analogWrite(LR, fadeValue);
              }
              }
    }
    // Выводит текущие время в Serial
    void printTimeToSerial(){
      byte static prevSecond=0; // тут будем хранить, сколько секунд было при прошлом отчете
     
      if(RTC.second!=prevSecond){ // что-то делаем только если секунды поменялись
            Serial.print(RTC.hour); // часы
     
            Serial.print(":"); // разделитель
            Serial.print(RTC.minute);
     
            Serial.print(":");
            Serial.println(RTC.second);
           
            prevSecond=RTC.second; // запомнили когда мы "отчитались"
      }
    }
    // Выводит текущие время на LCD
    void printTimeToLCD(){
            byte static prevSecond=0; // тут будем хранить, сколько секунд было при выводе
           
            if(RTC.second!=prevSecond){ // что-то делаем только если секунды поменялись
              lcd.setCursor(11,0); // устанавливаем позицию курсора
             
              if(RTC.hour<10)lcd.print(" ");
              lcd.print(RTC.hour); // часы
           
              lcd.print( (RTC.second % 2)?" ":":"); // разделитель моргает
             
              if(RTC.minute<10)lcd.print(0); // лидирующий ноль, если нужен
              lcd.print(RTC.minute);
           
            prevSecond=RTC.second; // запомнили когда мы "отчитались"
      }
    }
    // устанавливает часы модуля на какое-то заранее определенное время
    void setSomeTime(){
      RTC.stopClock();// останавливаем часы
      RTC.fillByHMS(20,24,0); // "подкручиваем стрелки на 20:24:00
      RTC.setTime();// отправляем "подкрученное время" самому модулю
      RTC.startClock(); // и опять запускаем часы
    }
    // слушает из Serial команды и выполняет их. Каждая команда - один символ.
    // доступны команды:
    //  s - установить время указанное в функции setSomeTime()
    void doSerialCommands(){
      if(Serial.available()){ // что-нибудь пришло?
            char ch=Serial.read(); // читаем что пришло
           
            switch(ch){
              case 's': // команда установки времени
                      setSomeTime(); // устанавливаем
                      break;
                     
              // тут, в будущем, мы можем добавлять дополнительные команды
              default:;
                      // на неизвестную команду - ничего не делаем
            };
      }
    }
     
  5. Megakoteyka

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

    Строки
    RTC.hour;
    RTC.minute;
    ничего не делают и не имеют никакого смысла.

    On_Time=(20*60+27);
    Off_Time=(20*60+29);
    if(On_Time < Off_Time) { ... }
    Это условие будет выполняться всегда.

    Поскольку в циклах плавного включения/выключения подсветки нет задержки, эти циклы будут выполняться практически мгновенно.

    Разберитесь с условиями и поставьте delay(...) после analogWrite(LR, fadeValue);.

    Перед вставкой кода на форум нажимайте Ctrl+T в Arduino IDE для автоматического форматирования кода.
     
  6. kirex

    kirex Нуб

    Да пробовал я уже, всё равно нет плавности, загорается сразу на 100%.
    А с delay идёт задержка во время которой виснут часы. Да и не могу же я поставить задержку продолжительностью в 5 часов.
     
  7. Megakoteyka

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

    Тогда немного иначе.
    Нужно соорудить машину состояний, имеющую состояния "яркость_увеличивается", "яркость_уменьшается" и прочие.
    Вместо цикла заводим переменную Т, в которой храним время очередного повышения яркости и переменную Х, хранящую текущее значение яркости. В момент, когда нужно начать наращивать яркость, переходим в состояние "яркость_увеличивается", задаем начальное значение яркости и записываем в Т текущее время. В обработчике ветки "яркость_увеличивается" машины состояний сравниваем текущее время и Т. Если Т стало больше или равно текущему времени - вызываем analogWrite(pin, X), увеличиваем Х и Т (в Т кладем время очередного приращения яркости, в Х - следующее значение яркости), в противном случае ничего не делаем. Теперь условие будет срабатывать через определенные промежутки времени и никакого delay не потребуется. Если непонятно объяснил, спрашивайте.
     
  8. kirex

    kirex Нуб

    Честно говоря мало что понял, я в программировании почти полный ноль.
    Может поможете организовать всё это в вышеприведённом коде.
    Был бы очень признателен и премного благодарен.
     
  9. kirex

    kirex Нуб

    Либо есть ещё такой код, но как его прикрутить к моему я тоже не пойму.

    #include <Wire.h>
    #include "RTClib.h"

    RTC_DS1307 RTC;

    float minutes(uint8_t hh,uint8_t mm) {return hh*60+mm;}

    class Led
    {
    private:
    uint8_t Hours_Start_Sunrise, Minutes_Start_Sunrise, Hours_End_Sunrise, Minutes_End_Sunrise;
    uint8_t Hours_Start_Sunset, Minutes_Start_Sunset, Hours_End_Sunset, Minutes_End_Sunset;
    uint8_t Meridian_PWM, Midnight_PWM, Current_PWM, PWM_Pin;
    public:
    Led(uint8_t HSSr,uint8_t MSSr,uint8_t HESr,uint8_t MESr,
    uint8_t HSSs,uint8_t MSSs,uint8_t HESs,uint8_t MESs,
    uint8_t MerPWM,uint8_t MidPWM,uint8_t CurPWM,uint8_t PWMPin)
    : Hours_Start_Sunrise(HSSr),Minutes_Start_Sunrise(MSSr),Hours_End_Sunrise(HESr),Minutes_End_Sunrise(MESr),
    Hours_Start_Sunset(HSSs), Minutes_Start_Sunset(MSSs), Hours_End_Sunset(HESs), Minutes_End_Sunset(MESs),
    Meridian_PWM(MerPWM), Midnight_PWM(MidPWM), Current_PWM(CurPWM), PWM_Pin(PWMPin)
    {
    pinMode(PWM_Pin, OUTPUT);
    analogWrite(PWM_Pin, Midnight_PWM);
    }
    void Dim(DateTime now)
    {
    if (now.hour() if (now.hour()>Hours_End_Sunrise &amp;&amp; now.minute()>Minutes_End_Sunrise) {analogWrite(PWM_Pin,Meridian_PWM);return;}
    if (now.hour() if (now.hour()>Hours_End_Sunset &amp;&amp; now.minute()>Minutes_End_Sunset) {analogWrite(PWM_Pin,Midnight_PWM);return;}
    if (now.hour()>=Hours_Start_Sunrise &amp;&amp; now.minute()>=Minutes_Start_Sunrise)
    {
    Current_PWM = (int)(minutes(now.hour(),now.minute())-minutes(Hours_Start_Sunrise,Minutes_Start_Sunrise))/(minutes (Hours_End_Sunrise,Minutes_End_Sunrise)-minutes(Hours_Start_Sunrise,Minutes_Start_Sunrise))*(Meridian_PWM-Midnight_PWM);
    analogWrite(PWM_Pin,Midnight_PWM);
    return;
    }
    if (now.hour()>=Hours_Start_Sunset &amp;&amp; now.minute()>=Minutes_Start_Sunset)
    {
    Current_PWM = (int)(minutes(Hours_End_Sunset,Minutes_End_Sunset)-minutes(now.hour(),now.minute()))/(minutes(Hours_End_Sunset,Minutes_End_Sunset)-minutes(Hours_Start_Sunset,Minutes_Start_Sunset))*(Meridian_PWM-Midnight_PWM);
    analogWrite(PWM_Pin,Midnight_PWM);
    return;
    }
    }
    };

    // конструктор объектов (часы начала восхода, минуты начала восхода, часы конца восхода, минуты конца восхода,
    // часы начала заката, минуты начала заката, часы конца заката, минуты конца заката, макс светимость, мин светимость, текущая светимость, пин)

    Led CoolWhite(11,0,15,0,17,0,21,0,128,0,0,3);
    Led TrueViolet(9,0,12,0,20,0,23,0,192,0,0,5);
    Led RoyalBlue(10,0,13,0,19,0,22,0,192,0,0,6);
    Led Blue(11,0,14,0,18,0,21,0,192,0,0,9);
    Led DeepRed(12,0,15,0,17,0,21,0,128,0,0,10);
    Led Green(12,0,15,0,17,0,21,0,128,0,0,11);

    uint8_t coolerPin = 7;
    uint8_t moonlightPin = 8;
    DateTime now;

    void night(DateTime now)
    {
    if (now.hour()<9 &amp;&amp; now.hour()>22)
    {
    digitalWrite(coolerPin, LOW);
    digitalWrite(moonlightPin, HIGH);
    }
    else
    {
    digitalWrite(coolerPin, HIGH);
    digitalWrite(moonlightPin, LOW);
    }
    }

    void setup()
    {
    Serial.begin(57600);
    Wire.begin();
    RTC.begin();
    if (! RTC.isrunning()) Serial.println("RTC is NOT running!");
    pinMode(coolerPin, OUTPUT);
    pinMode(moonlightPin, OUTPUT);
    }

    void loop()
    {
    now = RTC.now();
    CoolWhite.Dim(now);
    TrueViolet.Dim(now);
    RoyalBlue.Dim(now);
    Blue.Dim(now);
    DeepRed.Dim(now);
    Green.Dim(now);
    night(now);
    }
     
  10. Megakoteyka

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

    Вот немного о машине состояний.
    Не надо ничего никуда прикручивать, лучше разобраться и сделать самостоятельно, это гораздо интересней и полезней. Да и модернизировать потом проще будет.
    "Русские на войне своих не бросают" (с)

    Попробуйте вот такой подход:

    Код (Text):
    #define TIME_STEP 100  // временной шаг изменения подсветки
    #define LIGHT_STEP 5  // яркостный шаг изменения подсветки
    #define PIN_LED 13    // пин, управляющий подсветкой

    // набор состояний для машины состояний
    enum STATE {
      STATE_LIGHT_UP,    // состояние "подсветка включается"
      STATE_LIGHT_DOWN,  // состояние "подсветка выключается"
      STATE_NONE        // состояние "ничего не делать"
    };

    STATE _state = STATE_NONE;  // текущее состояние машины состояний
    int _lightValue = 0;        // текущее значение яркости подсветки
    long _nextTime = 0;        // время очередного прибавления/убавления яркости
    long _timeToOn = 0;        // время включения
    long _timeToOff = 0;        // время выключения

    void setup()
    {
    }

    void loop()
    {
      long currentTime = millis();
      // если текущее время больше либо равно времени начала включения подсветки
      if(currentTime >= _timeToOn)
      {
        _state = STATE_LIGHT_UP; // переходим в состояние увеличения яркости
        _lightValue = 0;        // задаем начальную яркость
        _nextTime = millis();    // устанавливаем время изменения яркости
      }

      // если текущее время больше либо равно времени начала выключения подсветки
      if(currentTime >= _timeToOff)
      {
        _state = STATE_LIGHT_DOWN;// переходим в состояние уменьшения яркости
        _lightValue = 255;        // задаем начальную яркость
        _nextTime = millis();    // устанавливаем время изменения яркости
      }

      // машина состояний
      switch(_state)
      {
        // включение подсветки
        case STATE_LIGHT_UP:
          // если пришло время очередного шага
          if(currentTime >= _nextTime)
          {
            _lightValue += LIGHT_STEP;        // увеличиваем яркость
            _nextTime += TIME_STEP;          // устанавливаем время очередного шага
            analogWrite(PIN_LED, _lightValue);// делаем изменение яркости
         
            // если яркость достигла максимума,
            // перестаем ее наращивать, для этого
            // переходим в состояние ничегонеделания
            if(_lightValue >= 255)
              _state = STATE_NONE;
          }
          break;
     
        // выключение подсветки
        case STATE_LIGHT_DOWN:
          // если пришло время очередного шага
          if(currentTime >= _nextTime)
          {
            _lightValue -= LIGHT_STEP;        // уменьшаем яркость
            _nextTime += TIME_STEP;          // устанавливаем время очередного шага
            analogWrite(PIN_LED, _lightValue);// делаем изменение яркости
         
            // если яркость достигла минимума,
            // перестаем ее убавлять, для этого
            // переходим в состояние ничегонеделания
            if(_lightValue <= 0)
              _state = STATE_NONE;
          }
     
          break;
     
        // ничего не делать
        case STATE_NONE:
          break;
      }
    }
    Попробуйте разобраться в логике работы этого кода. Вместо millis() используйте запрос показаний с часов реального времени. Время храните как количество секунд - h*60*60 + m*60 + s, тогда код потребует минимальных правок, да и сравнений меньше будет. Задайте константы LIGHT_STEP и TIME_STEP по вкусу.

    Обратите внимание на принципы именования констант и переменных, это здорово помогает. Форматирование кода (расстановка отступов) помогает сходу видеть структуру программы, не пренебрегайте этим.

    Ардуины под рукой нет, так что на железе не проверял, но в целом логика должна работать.

    Спрашивайте, если что-то непонятно.
     
    Последнее редактирование: 25 мар 2014
  11. kirex

    kirex Нуб

    Со светом разобрался. Теперь нужно сделать возможным включение и выключение света LW и LR кнопками (UP-Вкл., DOWN-Выкл.), независимо от времени. А также возможность включения и выключения нагревателя Н2 кнопками (LEFT-Вкл., RIGHT-Выкл.), независимо от температуры.
    Вот часть кода по срабатыванию реле:
    Код (Text):

      // Если температура достигает 28,3 (с погрешностью), отключаем кипятильник
      if (celsius > 28.3)
      {
        digitalWrite(40, Relay_Off);
      lcd.setCursor(0, 1);
      lcd.print("H1-Off");
      }
      if (celsius < 28.0)
      {
        digitalWrite(40, Relay_On);
      lcd.setCursor(0, 1);
      lcd.print("H1-On ");
      }

    // Если температура достигает 28,5 (с погрешностью), отключаем кипятильник
      if (celsius > 28.5)
      {
        digitalWrite(41, Relay_Off);
      lcd.setCursor(7, 1);
      lcd.print("H2-Off");
      }
      if (celsius < 28.0)
      {
        digitalWrite(41, Relay_On);
      lcd.setCursor(7, 1);
      lcd.print("H2-On ");
      }

    lcd_key = read_LCD_buttons();  // read the buttons

    switch (lcd_key)              // depending on which button was pushed, we perform an action
    {
      case btnRIGHT:
        {
        digitalWrite(41,!digitalRead(41));
      lcd.setCursor(7, 1);
      lcd.print("H2-Off");
        break;
        }
      case btnLEFT:
        {
        digitalWrite(41, Relay_On);
      lcd.setCursor(7, 1);
      lcd.print("H2-On ");
        break;
        }
      case btnUP:
        {
        lcd.print("UP    ");
        break;
        }
      case btnDOWN:
        {
        lcd.print("DOWN  ");
        break;
        }
      }
    }//------------Конец ЦИКЛА-----------------------------
     
     
    Последнее редактирование: 27 мар 2014