Досветка в теплице.

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

  1. zsm

    zsm Гик

    Здравствуйте уважаемые форумчане)

    Решил для знакомого собрать устройство для досветки в теплице.
    Задача максимально проста и банальна - включать натриевые лампы когда становится пасмурно.
    Накидал код , всё работает , но встал вопрос как избежать ложных срабатываний при случайном затемнении фоторезистора и.т.д.
    Видится многократная проверка условия y+x>100 , но не понимаю как это сделать :(
    да и в правильном ли направлении я двигаюсь тоже не понятно..

    Буду рад любым советам и предложениям)
    Так же интересны рекомендации по удешевлению устройства, думаю использовать более дешевый
    микроконтроллер. Подойдёт ли для этих целей attiny13 например? просто 328atmega слишком расточительно для таких целей использовать.




    Код (Text):
        #define SENSOR_PIN A5//фоторезистор
        #define VAR_REZ A0// чувствительность
        int led = 13;
        int ledState = LOW;
       
        void setup()
        {
        Serial.begin(9600);
        pinMode(led, OUTPUT);
        }
       
        void loop()
       
         
        {
         
          delay (1000) ;
         
          int lightLevel = analogRead(SENSOR_PIN);
          int sensitivity = analogRead(VAR_REZ);
          int y = map(lightLevel,0,1023,1,100) ;
          int x = map(sensitivity,31,955,1,100) ;
          Serial.println(y);
          Serial.println(x);
          Serial.println(lightLevel);
          Serial.println(sensitivity);
       
         
        if  (y+x>100 && ledState == HIGH )
       
        {
          ledState = LOW;
          digitalWrite(led, ledState);
        }
         
         
         
          if  (y+x<100 && ledState == LOW )
         
         
        {
          ledState = HIGH;
          digitalWrite(led, ledState);
        }
         
       
         
        }
     
     
  2. -Mark-

    -Mark- Гик

    Считаю, что опрашивать постоянно датчик нет никакого смысла! Достаточно раз в час.
    Да и вообще для такой задачи подойдет готовая платка с 4-5 деталюхами от китай-прома...если не ошибаюсь то стоит такая не больше 300 руб.
     
    Последнее редактирование: 3 дек 2013
  3. NR55RU

    NR55RU Гик

    И в этот момент человек с лейкой будет стоять рядом закрывая датчик от красивого солнышка, в итоге свет погаснет лишь через час в момент очередной проверки :)

    Можно сделать достаточно простой вариант, приведу идею на вскидку, можно будет доработать и додумать.
    Можно создать переменную - состояние, так называемый средний уровень освещения, при каждом опросе датчика, пересчитывается средняя освещенность, как например на простом вело компьютере рассчитывается средняя скорость когда делят расстояние на время.
    Примерно так и у вас, только с той разницей что например среднюю освещенность надо рассчитывать на час или на пол часа, короче зависит от того как быстро должна сработать подсветка, чем больше период расчета освещенности тем дольше должно быть темно чтобы она снизилась.
    А включение освещения будете проводить именно по средней освещенности :)
    Так регулируя частоту проверки датчика и период за который рассчитывается средняя величина освещенности можно регулировать и скорость реакции света на эти изменения. :)
    Такая система будет устойчива к быстрым сменам освещения.
     
    zsm нравится это.
  4. Megakoteyka

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

    Можно завести массив (или FIFO) из n состояний датчика за последние n измерений. При каждом измерении выбрасывать одно старое значение, сдвигать все элементы и записывать новое. Потом пересчитывать среднее значение. Если результат очередного измерения сильно отличается от среднего, его можно отбросить - наверняка это птичка на датчик села.

    Насчет удешевления.
    Контроллер любой годится, лишь бы обладал достаточным количеством ног и имел необходимые модули (АЦП, например). Внешний кварц нафиг не нужен, вполне хватит и внутренней RC-цепочки - производительность для такой задачи не нужна, точное измерение времени тоже вроде ни к чему.
    attiny13: если не отключать reset, останется 5 ног, из них 3 с АЦП. Должно хватить, если подключатль только датчики и реле. Если подключать дисплей и кнопки (для индикации и управления режимами работы и настройками), то придется взять контроллер немного потолще. Начните с составления функциональной схемы предполагаемого устройства.
    Плату изготовить тоже несложно - потребуется кусок текстолита, банка персульфата аммония за 40р. Лазерный принтер и кусок бумаги из журнала нынче не проблема найти :)
     
    zsm нравится это.
  5. zsm

    zsm Гик

    Большое спасибо за развернутые ответы) буду думать какой вариант выбрать:)
    ключевое понятие - расчёт среднего значения, сам как то не додумался до этого...:(
     
  6. zsm

    zsm Гик

    Благодаря советам получилось , все работает - усредняется 10 значений собранных через 1 секунду ( для реального устройства время увеличу)
    но расстраивает что код очень корявый , хочется всё это без delay замутить и размером поменьше, т.к. в тиньку это уродство просто не влезет)

    Код (Text):
     #define SENSOR_PIN A5
        #define VAR_REZ A0
        int latency=1000;
        int led = 13;
        int ledState = LOW;
        int average = 0;
        int a=0;
        int b=0;
        int c=0;
        int d=0;
        int e=0;
        int f=0;
        int g=0;
        int h=0;
        int i=0;
        int j=0;
       
        void setup()
        {
        Serial.begin(9600);
        pinMode(led, OUTPUT);
        }
       
        void loop()
       
         
        {
         
          delay (latency) ;
         
          int lightLevel = analogRead(SENSOR_PIN);
          int sensitivity = analogRead(VAR_REZ);
          int y = map(lightLevel,0,1023,1,100) ;
          int x = map(sensitivity,31,955,1,100) ;
          int a=(x+y);
          Serial.println("a");
          Serial.println(a);
         
          delay (latency) ;
         
          lightLevel = analogRead(SENSOR_PIN);
          sensitivity = analogRead(VAR_REZ);
          y = map(lightLevel,0,1023,1,100) ;
          x = map(sensitivity,31,955,1,100) ;
          int b=(x+y);
          Serial.println("b");
          Serial.println(b);
         
          delay (latency) ;
         
          lightLevel = analogRead(SENSOR_PIN);
          sensitivity = analogRead(VAR_REZ);
          y = map(lightLevel,0,1023,1,100) ;
          x = map(sensitivity,31,955,1,100) ;
          int c=(x+y);
          Serial.println("c");
          Serial.println(c);
         
          delay (latency) ;
         
          lightLevel = analogRead(SENSOR_PIN);
          sensitivity = analogRead(VAR_REZ);
          y = map(lightLevel,0,1023,1,100) ;
          x = map(sensitivity,31,955,1,100) ;
          int d=(x+y);
          Serial.println("d");
          Serial.println(d);
         
          delay (latency) ;
         
          lightLevel = analogRead(SENSOR_PIN);
          sensitivity = analogRead(VAR_REZ);
          y = map(lightLevel,0,1023,1,100) ;
          x = map(sensitivity,31,955,1,100) ;
          int e=(x+y);
          Serial.println("e");
          Serial.println(e);
         
          delay (latency) ;
         
          lightLevel = analogRead(SENSOR_PIN);
          sensitivity = analogRead(VAR_REZ);
          y = map(lightLevel,0,1023,1,100) ;
          x = map(sensitivity,31,955,1,100) ;
          int f=(x+y);
          Serial.println("f");
          Serial.println(f);
         
          delay (latency) ;
         
          lightLevel = analogRead(SENSOR_PIN);
          sensitivity = analogRead(VAR_REZ);
          y = map(lightLevel,0,1023,1,100) ;
          x = map(sensitivity,31,955,1,100) ;
          int g=(x+y);
          Serial.println("g");
          Serial.println(g);
         
          delay (latency) ;
         
          lightLevel = analogRead(SENSOR_PIN);
          sensitivity = analogRead(VAR_REZ);
          y = map(lightLevel,0,1023,1,100) ;
          x = map(sensitivity,31,955,1,100) ;
          int h=(x+y);
          Serial.println("h");
          Serial.println(h);
         
          delay (latency) ;
         
          lightLevel = analogRead(SENSOR_PIN);
          sensitivity = analogRead(VAR_REZ);
          y = map(lightLevel,0,1023,1,100) ;
          x = map(sensitivity,31,955,1,100) ;
          int i=(x+y);
          Serial.println("i");
          Serial.println(i);
         
          delay (latency) ;
         
          lightLevel = analogRead(SENSOR_PIN);
          sensitivity = analogRead(VAR_REZ);
          y = map(lightLevel,0,1023,1,100) ;
          x = map(sensitivity,31,955,1,100) ;
          int j=(x+y);
          Serial.println("j");
          Serial.println(j);
         
          delay (latency) ;
         
         
         
         
         
          Serial.println("*********");
         
          average = (a+b+c+d+e+f+g+h+i+j)/10;
         
          Serial.print("average-");
          Serial.println(average);
         
          Serial.println("*********");
         
         
         
        if  (average>100 && ledState == HIGH )
         
        {
        ledState = LOW;
        digitalWrite(led, ledState);
        }
         
     
        if  (y+x<100 && ledState == LOW )
        {
        ledState = HIGH;
        digitalWrite(led, ledState);
        }
     
     
     
      }
     
     
  7. Megakoteyka

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

    Код (Text):
    int buffer[10];

    void setup()
    {

    }

    void loop()
    {
      // сдвинули все элементы массива влево,
      // при этом потеряли первый
      for(int i = 0; i < 9; i++)
        buffer[i] = buffer[i + 1];
      // на место последнего элемента записали показания датчика
      buffer[9] = analogRead(A0);
     
      // суммируем показания и вычисляем среднее
      int sum = 0;
      for(int i = 0; i < 10; i++)
        sum += buffer[i];
      sum /= 10;
     
      // управляем лампочкой, глядя на значение sum
      // ...
     
      delay(1000);
    }
    А чем delay() помешал? Он вреден, когда нужно быть готовым в любой момент среагировать на некое событие, а тут вроде ничего такого нет.
     
    zsm нравится это.
  8. zsm

    zsm Гик

    Большое спасибо так гораздо лучше)
    От delay хочется отказаться т.к. в конечном устройстве паузы будут регулироваться дополнительной ручкой , а значения задержки будут скорее всего больше чем в примере , не хочется чтобы устройство повисало и не реагировало на повороты ручек...
     
  9. Megakoteyka

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

    Тогда так:
    Код (Text):
    #define BUFFER_SIZE 10  // количество показаний датчика для расчета среднего
    #define INTERVAL 1000  // интервал опроса датчика

    int buffer[BUFFER_SIZE];// буфер с показаниями датчика
    long nextTime = 0;      // время очередного срабатывания датчика

    // пороги гистерезиса
    int minimum = 300;      // показания, при которых лампа включится
    int maximum = 600;      // показания, при которых лампа потухнет

    void setup()
    {
    }

    void loop()
    {
      // получили текущее время
      long time = millis();

      // если текущее время дошло до времени срабатывания
      if(time >= nextTime)
      {
        // устанавливаем новое время срабатывания
        nextTime = time + INTERVAL;

        // сдвинули все элементы массива влево,
        // при этом потеряли первый элемент
        for(int i = 0; i < BUFFER_SIZE - 1; i++)
          buffer[i] = buffer[i + 1];

        // на место последнего элемента записали показания датчика
        buffer[BUFFER_SIZE - 1] = analogRead(A0);

        // суммируем показания
        int sum = 0;
        for(int i = 0; i < BUFFER_SIZE; i++)
          sum += buffer[i];

        // вычисляем среднее
        sum /= BUFFER_SIZE;

        if(sum >= maximum)
        {
          // выключить свет
        }
        if(sum <= minimum)
        {
          // включить свет
        }
      }
    }
    Имеет смысл добавить гистерезис, иначе вполне возможна ситуация, когда лампа начнет мигать из-за того, что показания датчика незначительно меняются туда-сюда. Значения минимума и максимума освещенности стоит принять как порог срабатывания +/- некоторая величина, определяемая экспериментально.
     
    zsm нравится это.
  10. zsm

    zsm Гик

    Огромное спасибо это действительно то что нужно! и размер 660 байт после компиляции очень радует)
    Гистерезис вы очень кстати вкрутили , без него вероятность сбоев гораздо выше бы была..
    Теперь думаю как красивый код не испоганить ... :)
     
  11. zsm

    zsm Гик

    Все отлично заработало на 13 тиньке . прикрутил 2 ручки - время опроса и чувствительность. Тинька напрямую управляет твердотельным реле ssr25.
    [​IMG] [​IMG]


    Код (Text):
    #define BUFFER_SIZE 10  // количество показаний датчика для расчета среднего
    //#define INTERVAL 100  // интервал опроса датчика

    int buffer[BUFFER_SIZE];// буфер с показаниями датчика
    long nextTime = 0;      // время очередного срабатывания датчика



    void setup()
    {
      pinMode(0, OUTPUT);
    }

    void loop()
    {
      // получили текущее время

      int sensitivity = analogRead(A1);
      int INTERVAL = analogRead(A3)*2;

      long time = millis();

      // если текущее время дошло до времени срабатывания
      if(time >= nextTime)
      {
        // устанавливаем новое время срабатывания
        nextTime = time + INTERVAL;

        // сдвинули все элементы массива влево,
        // при этом потеряли первый элемент
        for(int i = 0; i < BUFFER_SIZE - 1; i++)
          buffer[i] = buffer[i + 1];

        // на место последнего элемента записали показания датчика
        buffer[BUFFER_SIZE - 1] = analogRead(A2);

        // суммируем показания
        int sum = 0;
        for(int i = 0; i < BUFFER_SIZE; i++)
          sum += buffer[i];

        // вычисляем среднее
        sum /= BUFFER_SIZE;

        if(sum >= sensitivity+20) // +20-порог гистерезиса
        {
          // выключить свет

          digitalWrite(0, LOW);

        }
        if(sum <= sensitivity-20)//-20-порог гистерезиса
        {
          // включить свет

          digitalWrite(0, HIGH);
        }
      }
    }
    [​IMG]
     
    Последнее редактирование: 8 янв 2014
  12. Tomasina

    Tomasina Сушитель лампочек Модератор

    да, уже косяк найден и вопрос потёрт мною :)
     
  13. ИгорьК

    ИгорьК Гуру

    Коллеги, может я не постиг глубину вопроса... Поэтому поделюсь свой логикой включения/выключения, а не предлагаю что-то менять в Вашем коде.
    1. Гистерезис: включаем свет (условно) ниже 100, выключаем (условно) выше 150.
    2. Проверяем датчик света (предположим) 10 раз с перерывом 1 секунда.
    3. Сравниваем одновременно и со 100 и со 150.
    4. Если все 10 раз меньше 100 - команда на включение.
    5. Если все 10 больше 150 - команда на выключение.
    6. Иначе - ничего.
    (7.) в п. 4 и 5 можно добавить флаги "включаем, если не включено" и "выключаем, если не выключено".
     
  14. Amigoss

    Amigoss Нерд

    Гистерезис - это то, что Вам надо. Я как раз похожую штуку родителям сделал на Tiny85.
    Только она у меня еще и время светового дня автоматически поддерживает. Всё уместилось в розетку 220 вольт, включая реле на 5А, переменный резюк и кнопку.
    Переменным резистором регулируем порог срабатывания, и еще есть кнопочка, которая задает длительность светового дня.
    То есть можно Задать, чтобы поддерживался световой день например 14 часов. Тогда при нехватке естественного света будет включаться лампа, но работать будет столько, чтобы в сумме с солнцем было 14 ч. Если надо, дам скетч и схему.
     
    zsm нравится это.
  15. zsm

    zsm Гик

    Спасибо , интересно было бы взглянуть..
     
  16. Amigoss

    Amigoss Нерд

    Вот, нашел. Оказывается не на 85й а на 45 тиньке влезло. :)

    Схема:
    teplica.jpg
    Питал зарядником от телефона. Провод от зарядника с "противоизломной резинкой" использовал тут же для выноса датчика освещения (фоторезистор). Реле на 5А нагрузки, питание обмотки 5 В. Чтобы не было скачков питания на контроллере, питаю его от 4 В через стабилитрон.
    Вот как выглядит моя плата. Изделие в сборе, к сожалению, не фоткал, так как не думал публиковать.
    photo.JPG image.jpg
     
    dreadfull, zsm и Megakoteyka нравится это.
  17. Amigoss

    Amigoss Нерд

    И скетч вот. Он правда никак не оптимизировался, но рабочий. Мне надо было "ехать, а не шашечки чтоб были".
    Я старался его максимально комментировать, но если что - спрашивайте.
    В целом работает так:
    Задаем начало дневного цикла самим фактом включения. Например, включили в 7 утра и всё. С тех пор устройство отсчитывает циклы по 24 часа. Первые 12 часов (т.е. в нашем случае до 7 часов вечера) в "сутках" считаются "днем", и если света на датчике не хватает (эта "граница" задается ручкой потенциометра) включается реле. Когда проходит 12 часов, реле выключается независимо от наличия света снаружи. По истечении 24 часов все повторяется снова.
    Светодиод предназначен для контроля (вдруг свет выключался, и "начальная точка" сбилась?). Миганием показывается порядковый номер текущего часа в "виртуальных сутках" контроллера. Причем для удобства подсчета, короткая вспышка значит 1, а длинная - 5. То есть три коротких это третий час, а длинная и две коротких - седьмой.
    Кнопка нужна, чтобы можно было менять длину светового дня (по умолчанию - 12 часов), она может быть от 10 до 17 часов. Для этого при подаче питания кнопку надо удерживать нажатой, тогда устройство войдет в режим программирования, о чем сообщит двумя длинными вспышками (т.е. 2х5=10 часов). теперь можно понажимать коротко кнопку, увеличивая каждый раз время на 1, после каждого нажатия будет индикация заданного времени. Когда нащелкали то, что нужно, сделайте паузу, и через пару секунд устройство выйдет из программирования, и начнет работу. Кнопка больше не опрашивается (до следующего включения питания).
     

    Вложения:

    • Sketch.txt
      Размер файла:
      14,7 КБ
      Просмотров:
      609
    ИгорьК, Megakoteyka и zsm нравится это.
  18. zsm

    zsm Гик

    Спасибо , здорово получилось !
     
  19. Amigoss

    Amigoss Нерд

    Пользуйтесь на здоровье!