Умная теплица на базе Arduino Mega

bwn
Offline
Зарегистрирован: 25.08.2014

Код больно жуткий получается. Уменя все с менюшки меняется+автокоррекция и смотрится проще. Если интересно могу либу скинуть. Ссылку не могу найти, не помню откуда брал.

Cyoko
Offline
Зарегистрирован: 22.08.2014

Конечно интересно....Да и ваш скетчик бы глянул :)

itjunky
Offline
Зарегистрирован: 15.09.2014

Я тоже такие часики юзал не через RTC либу, а через ту что выше упомянули, с именем далласовского чипа. И как-то с установкой времени вообще не стал запариваться, поскольку идущий в поставке скетчик может установить время с компа. А поскольку часики с батарейкой, то и переустанавливать время больше нет необходимости.

bwn
Offline
Зарегистрирован: 25.08.2014

Код недоделанный, сейчас DHT правлю,  до исполнительной части еще не дошло. В loop соответственно задействовано case1,2,8. и скорее всего потом эту логику тоже поменяю. В менюшках нужна оптимизация - выносить повторяющиеся куски в отдельную функцию.

#if defined(ARDUINO) && ARDUINO >= 100 //Определение версии IDE
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include <Wire.h>                   //Библиотека I2C
#include <DS1307.h>                 //Библиотека для часов
#include <LiquidCrystalCyr_I2C.h>   //Библиотека LCD I2C русифицированная
#include <OneWire.h>                //Для DS18B20
#include "DHT.h"                    //Библиотека DHT
#include <CyberLib.h>               //Библиотека от Cyber-Place.ru
volatile uint8_t tic, Dimmer1, Dimmer2;
uint8_t data;

LiquidCrystalCyr_I2C lcd(0x20,16,2); //Дисплей 16х2, адрес 0х20

OneWire  ds(8);         //Пин подключения DS18B20
#define DHTPIN 7        // what pin we're connected to
#define DHTTYPE DHT21   // DHT 21 (AM2301)

DHT dht(DHTPIN, DHTTYPE);


//************ Блок инициализации переменных**********

int key=0;            //Переменная кода кнопки
byte f=0;             //Переменная для включения прерывания
long timeDat[6];      //Массив для хранения времени счетчиков

//************Блок переменных для часов****************
byte Hr, Mn, Sk, Dy, Mes, TimeSum;
int Yr;               //Переменные часов
byte TimeRazd=0;      //Разделитель
byte flagTime=1;      //флаг коррекции времени

//************Конец блока переменных для часов*********

//**********Блок переменных для DS18B20 и AM2301**************
  
  byte present = 0;
  byte datadall[12];         //Данные температуры
  byte addr[9];              //Переменная считанных данных адреса
  int HighByte, LowByte, Fract, TReading, HighTemp;
  float Whole, Tc_100;
  byte count=0;
  byte jDall;
  float tDall[4];       //Массив температур датчиков Даллас и DHT
  
   
//***********Конец блока переменных для DS18B20****************

//************Текстовые переменные для вывода на экран**********

char* str[]={"                ","Дата/Время","Время осв.минут",
"Температура `C","Влажность %","Выход","Редакт.наж.ОК","Год",
"Месяц","День","Часы","Минуты","Корр.время","Корр.темп.низ",
"Корр.темп.ул.","Корр.темп.верх","Корр.влажность","Ту Тп Вл",
"Нагреть дат.пом."};

//************Переменные для обработки меню********************

int eeDat;  //Номер ячейки в EEPROM хранящей значение, значение в устанавливаемом регистре для времени
byte prStr; //Номер текстовой строки из str[]
int znMax; //Максимально допустимое значение
int znMin; //Минимально допустимое значение
byte shag;  //Шаг приращения, убывания
byte col;  //Номер колонки курсора
byte row;  //Номер строки курсора


//************Блок исполнительных переменных***********
const byte alarm=9;         //Номер пина тревоги
const byte ventV=10;        //Номер пина вытяжного вентилятора
const byte ventP=11;        //Номер пина перемешивающего вентилятора
const byte osv=12;          //Номер пина освещения
const byte led=13;          //Индикатор и аварийный сброс

//************Конец блока исполнительных переменных**********

//**********Конец блока инициализации переменных*************

//***********БЛОК НАЧАЛЬНОЙ ИНИЦИАЛИЗАЦИИ********************
void setup () 
{
  
   Wire.begin();            // Инициализация I2C
   lcd.init();              // Инициализация lcd             
   lcd.backlight();         // Включаем подсветку
   dht.begin();             // Инициализация DHT
        
//************Проверка и установка констант в EEPROM***********************

if (ReadEEPROM_Word(0)<400) {WriteEEPROM_Word(0, 510);}  //Значение клавиши Set
if (ReadEEPROM_Word(2)<400) {WriteEEPROM_Word(2, 825);}  //Значение клавиши UP
if (ReadEEPROM_Word(4)<400) {WriteEEPROM_Word(4, 690);}  //Значение клавиши DOWN
if (ReadEEPROM_Byte(6)<1||ReadEEPROM_Byte(6)>20) {WriteEEPROM_Byte(6, 5);} //Время освещения по умолчанию
if (ReadEEPROM_Byte(7)<8||ReadEEPROM_Byte(7)>20) {WriteEEPROM_Byte(7, 10);} //Температура по умолчанию
if (ReadEEPROM_Byte(28)<30||ReadEEPROM_Byte(28)>80) {WriteEEPROM_Byte(28, 40);} //Влажность по умолчанию
if (ReadEEPROM_Long(2)<-29||ReadEEPROM_Long(2)>29) {WriteEEPROM_Long(2, 0);} //Корр. времени по умолчанию
if (ReadEEPROM_Long(3)<-5||ReadEEPROM_Long(3)>5) {WriteEEPROM_Long(3, 0);} //Корр. темп.помещения низ даллас
if (ReadEEPROM_Long(4)<-5||ReadEEPROM_Long(4)>5) {WriteEEPROM_Long(4, 0);} //Корр.темп.улица даллас
if (ReadEEPROM_Long(5)<-5||ReadEEPROM_Long(5)>5) {WriteEEPROM_Long(5, 0);} //Корр.темп.помещение DHT
if (ReadEEPROM_Long(6)<-15||ReadEEPROM_Long(6)>15) {WriteEEPROM_Long(6, 0);} //Корр.влажности DHT


//***********Блок проверки и редактирования адресов датчиков Даллас**********
   
   byte i=0;
   byte dall[2][9];      //Массив адресов датчиков даллас
   byte j=0;             //Переменная кол-ва датчиков
   byte flagdal=0;       //Переменная признака
   
 label_2:
   if ( !ds.search(addr))  //Проверка окончания перечня адресов
   {
    ds.reset_search();     //Сброс опроса адресов
    goto label_1;          //Переход на цикл сравнения адресов с EEPROM
   } 
  
  for (i=0; i<8; i++)              //Создание адресного массива
     {  dall[count][i]=addr[i]; }
     dall[count][8]=1;
     count++;
     
     if (OneWire::crc8(addr, 7) != addr[7]) //Проверка на  соотв.контрольной суммы
     {
     ds.reset_search();
     count=0;
     return;
     }
     goto label_2;          //Возврат на считывание адресов датчиков
     
 label_1:                   //Проверка соответствия адресов
      
     for (j=0; j<count; j++)
     {
     flagdal=0;              //Обнуление переменной признака
        if (dall[j][8]!=0)   //Проверка условия соответствия адресов
        {
          for (i=0; i<8; i++) //Побайтовое сравнение адреса
          {
            if (dall[j][i]!=ReadEEPROM_Byte(i+31+j*9)) //Сверка значения
            { flagdal=1; }                             //Признак несоответствия
          dall[j][8]=flagdal;                         //Запись признака несоответствия 
          }
        }
     }
     
     flagdal=0;                    //Обнуление признака
     for ( j=0; j<count; j++ )     //Считывание признака несоответствия
     {
     flagdal=flagdal+dall[j][8];   //При 0 все значения соответствуют
     }
     
     if (flagdal!=0)                //Проверка несоответствия адресов
     {
       for ( j=0; j<count; j++ )    //Цикл перебора датчиков
       {
         for ( i=0; i<8; i++ )       //Цикл перебора байт адреса
         {
         WriteEEPROM_Byte( i+31+j*9, dall[j][i] ); //Запись байта в EEPROM
         WriteEEPROM_Byte( i+32+j*9, 0 );          //Очистка байта признака датчика
         }
       }   
 }
 //********Конец блока проверки и редактирования адресов датчиков*************

 //********Блок проверки принадлежности датчика**************
 
  DallasStartTemp();                       //Старт конвертации Далласов
  delay(750);                              //Задержка на конвертацию
  
   for (jDall=0; jDall<count; jDall++)    //Перебор адресов
 {
     dallRead();                          //Считывание температуры
     
   if (jDall==0)                         //Определение датчика
   {
     tDall[0]=Whole;                      //Присвоение температуры
   }
   if (jDall==1)                         //Определение датчика
   {
     tDall[1]=Whole;                    //Присвоение температуры
   }
      tDall[2]=dht.readTemperature();     //Температура с DHT
      tDall[3]=dht.readHumidity();        //Влажность с DHT
 }
  
  int tempDall;                       //Целочисленная переменная температуры
  lcd.clear();                        //Очистка экрана
  label_3:                            //Метка возврата
    if (ReadEEPROM_Byte(39)+ReadEEPROM_Byte(48)==0) //Проверка наличия признака 
 {
    DallasStartTemp();               //Старт конвертации температуры
    lcd.setCursor(0,0);              //Установка курсора
    lcd.print(str[18]);              //Печать строки
    delay(750);                      //Задержка на конвертацию
    
     for (jDall=0; jDall<count; jDall++) //Перебор датчиков
   {
     dallRead();                        //Считывание температуры датчика
     
   if (jDall==0)                        //Определение датчика
     {  
       tempDall=abs(tDall[0]-Whole);    //Расчет разницы в целочисленном значении
       if (tempDall>5)                  //Проверка условия
       {
       WriteEEPROM_Byte(39,1);          //Запись байта признака если ДА 
       }
     }
   if (jDall==1)                       //Определение датчика
     {
       tempDall=abs(tDall[1]-Whole);  //Подсчет разницы в целочисленном значении
       if (tempDall>5)                //Проверка условия
       {
        WriteEEPROM_Byte(48,1);       //Запись байта признака
       }
     }
    }
 goto label_3;                       //Возврат к проверке принадлежности
 }
 lcd.clear();                       //Очистка экрана

 //*****Конец блока определения принадлежности Далласов*******    
         
 //**********Инициализация исполнительных выводов*********
   pinMode(alarm, OUTPUT);
   pinMode(ventV, OUTPUT);
   pinMode(ventP, OUTPUT);
   pinMode(osv, OUTPUT);
   pinMode(led, OUTPUT);
   digitalWrite(alarm, LOW);
   digitalWrite(ventV, LOW);
   digitalWrite(ventP, LOW);
   digitalWrite(osv, HIGH);
   digitalWrite(led, HIGH);
  
 //***********Инициализация массива задержек****************************** 
   
   for(i=0; i<7; i++)
   {
     timeDat[i]=millis();
   }
 //***** timeDat[0] счетчик задержки на мигание сторожевым светододом (1000 мсек.)
 //***** timeDat[1] счетчик работы освещения от момента включения
 //***** timeDat[2] счетчик времени нажатия клавиши, необходимо обнулять
 //***** timeDat[3] счетчик времени нахождения в меню  
 //***** timeDat[4] счетчик времени для исключения ложных срабатываний в меню
 //***** timeDat[5] счетчик задержки DS18B20
 //***** timeDat[6] счетчик периода считывания DS18B20
 
//************Инициализация диммеров*************************************** 
  D4_Out; D5_Out;          //Настраиваем порты на выход
  D4_Low; D5_Low;          //установить на выходах низкий уровень сигнала
  D2_In;                   //настраиваем порт на вход для отслеживания прохождения сигнала через ноль  
  
//CHANGE – прерывание вызывается при любом изменении значения на входе; 
//RISING – вызов прерывания при изменении уровня напряжения с низкого (Low) на высокий(HIGH) 
//FALLING – вызов прерывания при изменении уровня напряжения с высокого (HIGH) на низкий (Low) 
    //attachInterrupt(0, detect_up, LOW);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень
    StartTimer1(halfcycle, 40); //время для одного разряда ШИМ
    StopTimer1(); //остановить таймер     

//********************Запуск счетного выхода RTC на 8192Гц.*******************
    Wire.beginTransmission(0x68);     
    Wire.send(0x07);
    Wire.send(B00010010);
    Wire.endTransmission();
 }
//*************КОНЕЦ БЛОКА НАЧАЛЬНОЙ ИНИЦИАЛИЗАЦИИ**************


//********************ОБРАБОТКА ПРЕРЫВАНИЙ*******************************
void halfcycle()  //прерывания таймера
{ 
  tic++;  //счетчик  
  if(Dimmer1 < tic ) D4_High; //управляем выходом
  if(Dimmer2 < tic ) D5_High;  //управляем выходом 
}

void  detect_up()  // обработка внешнего прерывания. Сработает по переднему фронту
{  
 tic=0;             //обнулить счетчик
 ResumeTimer1();   //запустить таймер
 attachInterrupt(0, detect_down, HIGH);  //перепрограммировать прерывание на другой обработчик
}  

void  detect_down()  // обработка внешнего прерывания. Сработает по заднему фронту
{   
 StopTimer1(); //остановить таймер
 D4_Low; D5_Low; //логический ноль на выходы
 tic=0;       //обнулить счетчик
 attachInterrupt(0, detect_up, LOW); //перепрограммировать прерывание на другой обработчик
} 
//*************************КОНЕЦ ОБРАБОТКИ ПРЕРЫВАНИЙ**********************



//**************************************ФУНКЦИИ****************************
 
//*****************Считывание температуры Далласов**********

void dallRead()
{
  byte i;                         //Переменная для цикла
  for (i=0; i<10; i++)            //Цикл считывания адреса
     {
       addr[i]=ReadEEPROM_Byte(i+31+jDall*9);  //Чтение адреса из EEPROM
     }
   present = ds.reset();          //Обращение к датчикам
   ds.select(addr);               //Выбор датчика
   ds.write(0xBE);                //Команда считывания
   for ( i = 0; i < 9; i++)       //Цикл считывания данных
    {
      datadall[i] = ds.read();    //Считывание данных в массив
    }
   LowByte = datadall[0];         //Младший байт
   HighByte = datadall[1];        //Старший байт
   HighTemp = datadall[2];
   TReading = (HighByte << 8) + LowByte;   //Сдвиг с присвоением
   Tc_100 = (6 * TReading) + TReading / 4; //Расчет температуры для 12бит.
   Whole = Tc_100 / 100;                   //Температура
}

//*****Конец функции считывания температуры Даллас************

//********Функция печати температуры и влажности**********
 
 void DallasPrintTemp()
 {
   lcd.setCursor(0,0);
   lcd.print(str[17]);
   lcd.setCursor(0,1); 
   lcd.print(tDall[0],0);
   lcd.print(" ");
   lcd.print(tDall[1],0);
   lcd.print(" ");
   lcd.print(tDall[3],0);
   
   Serial.print(tDall[3]);
   Serial.print("  ");
 }

//************Конец функции печати температуры и влажности*****

//******Функция запуска конвертации температуры с датчиков Даллас*****

    void DallasStartTemp()
    {
      ds.reset();          //Сброс датчиков
      ds.write(0xCC);      //Команда инициации
      ds.write(0x44);      //Команда на конвертирование
    }
 
//******Конец функции запуска конвертации температуры с DS18B20*******

//**********Функция присвоения температуры и влажности с датчиков***********

 void DallasTempPresent()
 {
   
   for (jDall=0; jDall<count; jDall++)     //Цикл перебора датчиков
   {
     dallRead();                           //Считывание температуры датчика
     
     if (Whole<-45||Whole>55)              //Проверка корректности значений
     {break;}
     
   if (jDall==0)                           //Определение датчика
   {
     tDall[ReadEEPROM_Byte(39)]=(tDall[ReadEEPROM_Byte(39)]+Whole)/2;          //Присвоение температуры датчику
   }
   if (jDall==1)                           //Определение датчика
   {
     tDall[ReadEEPROM_Byte(48)]=(tDall[ReadEEPROM_Byte(48)]+Whole)/2;          //Присвоение температуры датчика
   }
  }
   
   float t;
   t=dht.readTemperature();
   tDall[2]=(tDall[2]+t)/2;                      //Температура с DHT
   t=dht.readHumidity();
   tDall[3]=(tDall[3]+t)/2;            //Влажность с DHT
   
   DallasStartTemp();                     //Запуск новой конвертации
   timeDat[5]=millis();                   //Запуск переменной ожидания
   
 }
 
//*****Конец функции считывания температуры с датчиков********

//********Блок чтения времени****************
    void readTime()
    {
         Hr=(RTC.get(DS1307_HR,true));
         Mn=(RTC.get(DS1307_MIN,false));
         Sk=(RTC.get(DS1307_SEC,false));
         Dy=(RTC.get(DS1307_DATE,false));
         Mes=(RTC.get(DS1307_MTH,false));
         Yr=(RTC.get(DS1307_YR,false));
  }
//********Конец блока чтения времени***************

//*******Блок ежесуточной коррекции времени********

   void korTime()
   {
    if (Hr==23&&Mn==58&&Sk==30&&flagTime==1)   //Определение времени коррекции
    { 
    readTime();                                //Считывание с DS1307
    RTC.stop();                                //Остановка часов
    byte i=Sk;                                 //Присвоение значения секунд
    long j=i+ReadEEPROM_Long(2);               //Значение секунд после коррекции
    byte k=j;                                  //Перевод в целочисленное значение
    Sk=k;                                      //Присвоение нового значения
    flagTime=Hr+Mn;                            //Запись признака коррекции
    writeTime();                               //Запись нового значения времени
    }
   }

//******Конец блока ежесуточной коррекции времени*****

//***********Блок вывода ВРЕМЕНИ на дисплей*********
    void printTime()
{    
   if (TimeSum!=Hr+Mn+Sk)        //Проверка на изменение значения
 {      
       TimeSum=Hr+Mn+Sk;         //Обновление признака
       if (flagTime!=1)          //Проверка условия
       {
         if (flagTime<Hr+Mn) { flagTime=1; } //Присвоение значения если ДА
       } 
       
       korTime();                 //На функцию ежесуточной коррекции времени
       TimeRazd=!TimeRazd;       //Инверсия разделителя
   
    lcd.setCursor(11, 0);         // Курсор в 11поз. 1-й строки
    lcd.print(Hr/10);             // Десятки часов
    lcd.print(Hr%10);             // Единицы часов
       lcd.print(':');            // Разделитель
    lcd.print(Mn/10);             // Десятки минут
    lcd.print(Mn%10);             // Единицы минут
       //lcd.print(':');           // Разделитель
    //lcd.print(Sk/10);  // Десятки секунд
    //lcd.print(Sk%10);  // Единицы секунд
        lcd.setCursor(11, 1);     // Курсор в 11поз. 2-й строки 
    lcd.print(Dy/10);            // Десятки дней
    lcd.print(Dy%10);            // Единицы дней
        lcd.print('-');          // Разделитель     
    lcd.print(Mes/10);           // Десятки месяца
    lcd.print(Mes%10);           // Единицы месяца
    
 } 
else
  {
    if (TimeRazd==true)          //Мигаем разделителем
     {
      lcd.setCursor(13, 0);
      lcd.print (':');
     }
    else
        {
         lcd.setCursor(13, 0);
         lcd.print(' ');
        }         
   }
}
//***********Конец блока вывода ВРЕМЕНИ на дисплей******

//******Блок инд.свтодиодом************* 
 void ledBlink()
 {
   byte i;                            //Переменная статуса
   if (timeDat[0]+1000<millis())      //Проверка условия
      {
      timeDat[0]=millis();            //Установка задержки
      i=digitalRead(led);             //Проверка предыдущего состояния
      
      if (i==LOW)                     //Обновление статуса
        i=HIGH;
        else
        i=LOW;
        
        digitalWrite(led, i);        //Вывод значения на пин
      }
 }
//*********Конец блока индикации светодиодом***********************

//**********Блок подсветки и освещения*****************************
void light()
{
  if (timeDat[1]+(ReadEEPROM_Byte(6)*60000)<millis())      //Проверка времени работы освещения
  {
  digitalWrite(osv, LOW);                                  //Выключение освещения если ДА
  lcd.noBacklight();                                       //Выключение подсветки если ДА
  }
}
//********Конец блока подсветки и освещения************************


//********Блок распознавания значения кнопки***********

void keyPush()
{
        int keyKod=analogRead(0);        //Считываем значение клавиши
        delay(20);
        if (keyKod>(ReadEEPROM_Word(0)-15)&&keyKod<(ReadEEPROM_Word(0)+15)) { key=1; }  //Клавиша Set
        if (keyKod>(ReadEEPROM_Word(2)-15)&&keyKod<(ReadEEPROM_Word(2)+15)) { key=2; }  //Клавиша Up
        if (keyKod>(ReadEEPROM_Word(4)-15)&&keyKod<(ReadEEPROM_Word(4)+15)) { key=3; }  //Клавиша Down
        if (keyKod>850)                           { key=8; }  //Значение для начальной калибровки клавиш (Нажаты все)
         
}

//***********Конец блока распознования значения кнопки************

//***********Блок калибровки кнопок*******************************

void knopKal()
{
      int keyKod;
      int keyZap;
      //Вводим значение кнопки Set
      lcd.clear(); 
      lcd.setCursor(0,0);
      lcd.print("Нажмите Set 3сек.");
      long i=millis()+4000;             //Время задержки считывания
      while (i>millis())                //Цикл задержки
      {
      int keyKod=analogRead(0);         //Считывание значения кноки
      keyZap=keyKod;
      }
      if (keyZap>400)                   //Проверка нажатия
      {WriteEEPROM_Word(0, keyZap);}    //Запись в память если есть значение
      else
      {WriteEEPROM_Word(0, 510);}       //Запись если ничего не нажато
      
      //Вводим значение кнопки Вверх
      lcd.clear();                      //Все действия аналогично первого блока
      lcd.setCursor(0,0);
      lcd.print("Нажмите UP 3сек.");
      i=millis()+4000;
      while (i>millis())
      {
      int keyKod=analogRead(0);
      keyZap=keyKod;
      }
      if (keyZap>400) 
      {WriteEEPROM_Word(2, keyZap);}
      else
      {WriteEEPROM_Word(2, 825);}
      
      //Вводим значение кнопки Вниз
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Нажмите DOWN 3сек.");
      i=millis()+4000;
      while (i>millis())
      {
      int keyKod=analogRead(0);
      keyZap=keyKod;
      }
      if (keyZap>400) 
      {WriteEEPROM_Word(4, keyZap);}
      else
      {WriteEEPROM_Word(4, 687);}
      
      lcd.clear(); 
}
//*****************Конец блока калибровки кнопок*****************************

//*****************БЛОКИ ОБРАБОТКИ МЕНЮ ПРОГРАММЫ****************************

//**********************Блок обработки меню**********************************

void menuCikl()
{
          lcd.clear();
          lcd.setCursor(col, row);
          lcd.print(str[prStr]);
  byte i=0;
  i=ReadEEPROM_Byte(eeDat);               //Считываем ранее записанное значение
  int keyKod=0;                           //Значение нажатой кнопки
  byte key1=0;                            //Статус нажатия кнопки
          lcd.setCursor(6,1);
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);               //Вывод записанного значения на экран
  timeDat[3]=millis()+20000;              //Счетчик времени нахождения в меню
  timeDat[4]=millis()+1000;               //Счетчик задержки на срабатывание клавиши Set
  while(timeDat[3]>millis())              //Цикл обработки меню по времени
   { 
    keyKod=analogRead(0);                 //Считываем значение кнопки
    delay(20);
    if (key1==1&&keyKod>400) { continue; } //Если не изменялось - возврат
    if (key1==0&&keyKod<400) { continue; } //Если не изменялось - возврат
    if (key1==0&&keyKod>400) { key1=1; } //Изменение статуса состояния
    if (key1==1&&keyKod<400) { key1=0; } //Изменение статуса состояния
    if (keyKod>(ReadEEPROM_Word(2)-15)&&keyKod<(ReadEEPROM_Word(2)+15)) //Проверка значения UP
   {  
     timeDat[3]=millis()+20000;          //Обновление времени нахождения в меню
     i=i+shag;                                //Приращение значения 
          if (i>znMax)                     //Проверка на превышение допустимых значений
          {
          i=znMin;                           //Если превышено, переход на минимальное значение
          lcd.setCursor(6,1);            //Вывод на экран
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);
     }
          lcd.setCursor(6,1);            //Вывод на экран
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);
   }
  
    if (keyKod>(ReadEEPROM_Word(4)-15)&&keyKod<(ReadEEPROM_Word(4)+15))  //Проверка на нажатие Down
    {  
     timeDat[3]=millis()+20000;      //Обновление времени нахождения в меню
     i=i-shag;                            //Уменьшение задаваемого значения
          if (i<znMin)                  //Проверка на достижение минимального значения
        {
        i=znMax;                        //Если достигнуто, переход на максимальное значение
          lcd.setCursor(6,1);        //Вывод на экран
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);
    }
          lcd.setCursor(6,1);        //Вывод на экран
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);  
   }  
        
     if (keyKod>(ReadEEPROM_Word(0)-15)&&keyKod<(ReadEEPROM_Word(0)+15)&&timeDat[4]<millis()) //Проверка нажатия клавиши Set с задержкой
   {
        lcd.clear();                                 //Очистка экрана
        if (ReadEEPROM_Byte(eeDat)==i) { break; }   //Сравнение нового значения с сохраненным, выход если равны
        WriteEEPROM_Byte(eeDat, i);                 //Сохранение нового значения
        break;                                      //Выход   
     }
   }
 
      lcd.clear();                                  //Очистка экрана
} 

//*************************Конец блока обработки и записи меню******************************************************

//*************************Блок корректировки и записи времени******************************************************

void menuCiklTime()
{
          
          lcd.clear();
          lcd.setCursor(col, row);
          lcd.print(str[prStr]);
  int i=0;
  i=eeDat;                                //Старое значение
  int keyKod=0;                           //Значение нажатой кнопки
  byte key1=0;                            //Статус нажатия кнопки
          lcd.setCursor(6,1);
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);               //Вывод записанного значения на экран
  timeDat[3]=millis()+10000;              //Счетчик времени нахождения в меню
  timeDat[4]=millis()+1000;               //Счетчик задержки на срабатывание клавиши Set
  while(timeDat[3]>millis())              //Цикл обработки меню по времени
   { 
    keyKod=analogRead(0);                 //Считываем значение кнопки
    delay(20);
    if (key1==1&&keyKod>400) { continue; } //Если не изменялось - возврат
    if (key1==0&&keyKod<400) { continue; } //Если не изменялось - возврат
    if (key1==0&&keyKod>400) { key1=1; } //Изменение статуса состояния
    if (key1==1&&keyKod<400) { key1=0; } //Изменение статуса состояния
    if (keyKod>(ReadEEPROM_Word(2)-15)&&keyKod<(ReadEEPROM_Word(2)+15)) //Проверка значения UP
   {  
     timeDat[3]=millis()+10000;          //Обновление времени нахождения в меню
     i=i+shag;                                //Приращение значения 
          if (i>znMax)                     //Проверка на превышение допустимых значений
          {
          i=znMin;                           //Если превышено, переход на минимальное значение
          lcd.setCursor(6,1);            //Вывод на экран
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);
     }
          lcd.setCursor(6,1);            //Вывод на экран
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);
   }
  
    if (keyKod>(ReadEEPROM_Word(4)-15)&&keyKod<(ReadEEPROM_Word(4)+15))  //Проверка на нажатие Down
    {  
     timeDat[3]=millis()+10000;      //Обновление времени нахождения в меню
     i=i-shag;                            //Уменьшение задаваемого значения
          if (i<znMin)                  //Проверка на достижение минимального значения
        {
        i=znMax;                        //Если достигнуто, переход на максимальное значение
          lcd.setCursor(6,1);        //Вывод на экран
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);
    }
          lcd.setCursor(6,1);        //Вывод на экран
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);  
   }  
        
     if (keyKod>(ReadEEPROM_Word(0)-15)&&keyKod<(ReadEEPROM_Word(0)+15)&&timeDat[4]<millis()) //Проверка нажатия клавиши Set с задержкой
   {
        lcd.clear();                                 //Очистка экрана
        eeDat=i;
        break;                                      //Выход   
     }
   }
 
      lcd.clear();                                  //Очистка экрана
} 

//*******Конуц блока корректировки и записи времени******************************************************

//*******Блок записи длинных и отрицательных коэфф.в EEPROM******
void menuCiklLong()
{
          lcd.clear();
          lcd.setCursor(col, row);
          lcd.print(str[prStr]);
  long i=0;
  i=ReadEEPROM_Long(eeDat);                   //Считываем ранее записанное значение
  int keyKod=0;                           //Значение нажатой кнопки
  byte key1=0;                            //Статус нажатия кнопки
          lcd.setCursor(6,1);
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);               //Вывод записанного значения на экран
  timeDat[3]=millis()+20000;              //Счетчик времени нахождения в меню
  timeDat[4]=millis()+1000;               //Счетчик задержки на срабатывание клавиши Set
  while(timeDat[3]>millis())              //Цикл обработки меню по времени
   { 
    keyKod=analogRead(0);                 //Считываем значение кнопки
    delay(20);
    if (key1==1&&keyKod>400) { continue; } //Если не изменялось - возврат
    if (key1==0&&keyKod<400) { continue; } //Если не изменялось - возврат
    if (key1==0&&keyKod>400) { key1=1; } //Изменение статуса состояния
    if (key1==1&&keyKod<400) { key1=0; } //Изменение статуса состояния
    if (keyKod>(ReadEEPROM_Word(2)-15)&&keyKod<(ReadEEPROM_Word(2)+15)) //Проверка значения UP
   {  
     timeDat[3]=millis()+20000;          //Обновление времени нахождения в меню
     i=i+shag;                                //Приращение значения 
          if (i>znMax)                     //Проверка на превышение допустимых значений
          {
          i=znMin;                           //Если превышено, переход на минимальное значение
          lcd.setCursor(6,1);            //Вывод на экран
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);
     }
          lcd.setCursor(6,1);            //Вывод на экран
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);
   }
  
    if (keyKod>(ReadEEPROM_Word(4)-15)&&keyKod<(ReadEEPROM_Word(4)+15))  //Проверка на нажатие Down
    {  
     timeDat[3]=millis()+20000;      //Обновление времени нахождения в меню
     i=i-shag;                            //Уменьшение задаваемого значения
          if (i<znMin)                  //Проверка на достижение минимального значения
        {
        i=znMax;                        //Если достигнуто, переход на максимальное значение
          lcd.setCursor(6,1);        //Вывод на экран
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);
    }
          lcd.setCursor(6,1);        //Вывод на экран
          lcd.print("   ");
          lcd.setCursor(6,1);
          lcd.print(i,DEC);  
   }  
        
     if (keyKod>(ReadEEPROM_Word(0)-15)&&keyKod<(ReadEEPROM_Word(0)+15)&&timeDat[4]<millis()) //Проверка нажатия клавиши Set с задержкой
   {
        lcd.clear();                                 //Очистка экрана
        if (ReadEEPROM_Long(eeDat)==i) { break; }   //Сравнение нового значения с сохраненным, выход если равны
        WriteEEPROM_Long(eeDat, i);                 //Сохранение нового значения
        break;                                      //Выход   
     }
   }
 
      lcd.clear();                                  //Очистка экрана
} 

//******Конец блока длинных и отрицательных значений в EEPROM*********************

//******Блок записи значений времени**********

 void writeTime()
 {
   
  RTC.set(DS1307_SEC,Sk);        //set the seconds
  RTC.set(DS1307_MIN,Mn);        //set the minutes
  RTC.set(DS1307_HR,Hr);        //set the hours
  //RTC.set(DS1307_DOW,1);      //set the day of the week
  RTC.set(DS1307_DATE,Dy);      //set the date
  RTC.set(DS1307_MTH,Mes);      //set the month
  RTC.set(DS1307_YR,Yr-2000);   //set the year
  RTC.start();
 }
 
 //*******Конец блока записи значений времени******

//***********Блок установки времени*************

void ustTime()
{
  readTime();                      //Чтение текущего времени
  RTC.stop();                      //Остановка часов
  prStr=7; eeDat=Yr; znMin=2010; znMax=2099; shag=1; col=6; row=0; //Новое значение года
        menuCiklTime();
        Yr=eeDat;
  prStr=8; eeDat=Mes; znMin=1; znMax=12; shag=1; col=5; row=0; //Новое значение месяца
        menuCiklTime();
        Mes=eeDat;
  prStr=9; eeDat=Dy; znMin=1; znMax=31; shag=1; col=6; row=0;  //Новое значение даты
        menuCiklTime();
        Dy=eeDat;
  prStr=10; eeDat=Hr; znMin=0; znMax=23; shag=1; col=6; row=0;  //Новое значение часов
        menuCiklTime();
        Hr=eeDat;
  prStr=11; eeDat=Mn; znMin=0; znMax=59; shag=1; col=5; row=0;  //Новое значение минут
        menuCiklTime();
        Mn=eeDat;
  writeTime();                             //На функцию записи времени
  
}  
//************Конец блока установки времени******************************************************************


//*******************Основное меню************************************************************************

void mainMenu()                //Алгоритм перебора значений как в menuCikl()
{
  lcd.clear();
  byte i=1;
  int keyKod=0;
  byte key1=0;
  timeDat[2]=0;                //Сбрасываем задержку срабатывания для исключения возврата
  timeDat[3]=millis()+20000;
  timeDat[4]=millis()+1000;
  while(timeDat[3]>millis())
   { 
    keyKod=analogRead(0);
    delay(20);
    if (key1==1&&keyKod>400) { continue; }
    if (key1==0&&keyKod<400) { continue; }
    if (key1==0&&keyKod>400) { key1=1; }
    if (key1==1&&keyKod<400) { key1=0; }
    if (keyKod>(ReadEEPROM_Word(2)-15)&&keyKod<(ReadEEPROM_Word(2)+15))
   {  
       timeDat[3]=millis()+20000;
       i++; 
          if (i==11) {i=1;}
   }
  
    if (keyKod>(ReadEEPROM_Word(4)-15)&&keyKod<(ReadEEPROM_Word(4)+15))
   {  
       timeDat[3]=millis()+20000;
       i--; 
          if (i==0) {i=10;}
   }  
   
        if (keyKod>(ReadEEPROM_Word(0)-15)&&keyKod<(ReadEEPROM_Word(0)+15)&&timeDat[4]<millis()) 
          {
            lcd.clear();
            lcd.setCursor(0, 1);
            if(i==1)
            {
              ustTime();   //На функцию установки времени
            }
            if (i==2)             //Установка времени работы освещения и подсветки
            {
               eeDat=6; prStr=2; znMax=20; znMin=1; shag=1; col=0; row=0;
                   menuCikl();    
            }
            if (i==3)              //Установка значения  температуры
            {
              eeDat=7; prStr=3; znMax=18; znMin=8; shag=1; col=1; row=0;
                  menuCikl();      
            }
            if (i==4)           //Установка значения влажности
            {
              eeDat=28; prStr=4; znMax=80; znMin=30; shag=5; col=2; row=0;
                  menuCikl();  
            }
            if (i==5)           //Установка коррекции времени
            {
              eeDat=2; prStr=12; znMax=29; znMin=-29; shag=1; col=3; row=0;
                  menuCiklLong();
            }       
            if (i==6)           //Установка коррекции температуры нижнего датчика
            {
              eeDat=3; prStr=13; znMax=5; znMin=-5; shag=1; col=2; row=0;
                  menuCiklLong();
            }
            if (i==7)           //Установка коррекции температуры нижнего датчика
            {
              eeDat=4; prStr=14; znMax=5; znMin=-5; shag=1; col=2; row=0;
                  menuCiklLong();
            }              
            if (i==8)           //Установка коррекции температуры нижнего датчика
            {
              eeDat=5; prStr=15; znMax=5; znMin=-5; shag=1; col=1; row=0;
                  menuCiklLong();
            } 
             if (i==9)           //Установка коррекции температуры нижнего датчика
            {
              eeDat=6; prStr=16; znMax=15; znMin=-15; shag=1; col=1; row=0;
                  menuCiklLong();
            }             
            if (i==10)
            {
              break;
            }           
     }
      
   switch (i)           //Вывод пунктов меню на экран
   {
     case 1:
          lcd.setCursor(0,0);               //Установка курсора
          lcd.print(str[0]);                //Очистка строки вывода
          lcd.setCursor(3,0);               //Установка курсора
          lcd.print(str[1]);                //Вывод названия пункта меню
          lcd.setCursor(2,1);
          lcd.print(str[6]);
          continue;                          //Возврат на цикл отсчета нахождения в меню
          
     case 2:
          lcd.setCursor(0, 0);
          lcd.print(str[0]);
          lcd.setCursor(1,0);
          lcd.print(str[2]);
          lcd.setCursor(2,1);
          lcd.print(str[6]);
          continue;
          
     case 3:     
          lcd.setCursor(0, 0);
          lcd.print(str[0]);
          lcd.setCursor(1,0);
          lcd.print(str[3]);
          lcd.setCursor(2,1);
          lcd.print(str[6]);
          continue;
          
     case 4:
          lcd.setCursor(0, 0);
          lcd.print(str[0]);
          lcd.setCursor(3,0);
          lcd.print(str[4]);
          lcd.setCursor(2,1);
          lcd.print(str[6]);
          continue;
    
     case 5:
          lcd.setCursor(0, 0);
          lcd.print(str[0]);
          lcd.setCursor(3,0);
          lcd.print(str[12]);
          lcd.setCursor(2,1);
          lcd.print(str[6]);
          continue; 
     
      case 6:
          lcd.setCursor(0, 0);
          lcd.print(str[0]);
          lcd.setCursor(2,0);
          lcd.print(str[13]);
          lcd.setCursor(2,1);
          lcd.print(str[6]);
          continue; 
   
     case 7:
          lcd.setCursor(0, 0);
          lcd.print(str[0]);
          lcd.setCursor(2,0);
          lcd.print(str[14]);
          lcd.setCursor(2,1);
          lcd.print(str[6]);
          continue;
         
     case 8:
          lcd.setCursor(0, 0);
          lcd.print(str[0]);
          lcd.setCursor(1,0);
          lcd.print(str[15]);
          lcd.setCursor(2,1);
          lcd.print(str[6]);
          continue;
          
      case 9:
          lcd.setCursor(0, 0);
          lcd.print(str[0]);
          lcd.setCursor(1,0);
          lcd.print(str[16]);
          lcd.setCursor(2,1);
          lcd.print(str[6]);
          continue;
                  
     case 10:
          lcd.setCursor(0, 0);
          lcd.print(str[0]);
          lcd.setCursor(5,0);
          lcd.print(str[5]);
          lcd.setCursor(2,1);
          lcd.print(str[6]);
          continue;    
          }
    }
    lcd.clear();
}

//****************Конец блока обработки основного меню***********************

//****************КОНЕЦ БЛОКОВ МЕНЮ ПРОГРАММЫ********************************

//**************ОСНОВНОЙ ЦИКЛ ПРОГРАММЫ**************************************

void loop () 
{
 
   readTime();  //На функцию считывания времени
   printTime(); //На функцию вывода времени
   ledBlink();  //На функцию индикации светодиодом
   light();     //На функцию статуса подсветки
     
     if (timeDat[5]+5000<millis()) //Счетчик времени опроса датчиков
     {
       DallasTempPresent();
       DallasPrintTemp();
     }
   
        key=0;
        int keyKod=analogRead(0); //Считываем значение нажатой кнопки
        // Резисторы 10К к 0, 10К+4К7+2К2
        // 1 Кнопка1=509
        // 2 Кнопка2=825
        // 3 Кнопка3=687
        // 4 Кн1+Кн2=855
        // 5 Кн1+Кн3=767
        // 6 Кн2+Кн3=878
        // 7 Кн1+Кн2+Кн3=894
        if(keyKod>100)             //Нажатие любой кнопки
        {
          timeDat[1]=millis();       //Взведение счетчика освещения
          digitalWrite(osv, HIGH);   //Включение освещения
          lcd.backlight();           //Включение подсветки дисплея
             keyPush();              //На функции считывания и определения кода кнопки
        }
   
 
 //********Блок выполнения нажатия кнопки******       
        
        switch (key) 
        {
     case 0:
        timeDat[2]=0;              //Обнуление счетчика времени нажатия клавиш, если нет нажатия
        // lcd.setCursor(0, 0);
        // lcd.print("     ");
        // lcd.setCursor(0,0);
        // long j;
        // j=ReadEEPROM_Long(15);
        // lcd.print(j);
      break;
          
      case 1: 
         if (timeDat[2]==0)    {timeDat[2]=millis()+3000;} //Взведение счетчика времени нажатия Set
         if (timeDat[2]>millis()) {keyPush();}             //Ожидание если клавиша Set нажата
         else
        {mainMenu();}                                      //Переход на основное меню по достижении времени нажатия
      break;
      
      case 2: 
        
        //DallasTemp();
       //lcd.setCursor(0,0);
      // lcd.print(TEMPDal1);
     
      //lcd.setCursor(0, 0);
         //lcd.print("     ");
         //lcd.setCursor(0,0);
         //lcd.print(TEMP);
      break;
      
      case 3: 
      //lcd.setCursor(0, 0);
         //lcd.print("     ");
         //lcd.setCursor(0,0);
         //lcd.print("Вниз");
         
         //Dimmer2=Dimmer2+20;
         //delay(200);
         
      break;
      
      case 4: 
      lcd.setCursor(0, 0);
         lcd.print("     ");
         lcd.setCursor(0,0);
         lcd.print("K1+2");
      break;
      
      case 5: 
      lcd.setCursor(0, 0);
         lcd.print("     ");
         lcd.setCursor(0,0);
         lcd.print("K1+3");
      break;
      
      case 6: 
      lcd.setCursor(0, 0);
         lcd.print("     ");
         lcd.setCursor(0,0);
         lcd.print("K2+3");
      break;
      
      case 7: 
      lcd.setCursor(0, 0);
         lcd.print("     ");
         lcd.setCursor(0,0);
         lcd.print("1+2+3");
      break;
      
      case 8:
      if (timeDat[2]==0)    {timeDat[2]=millis()+10000;} //Взведение счетчика времени нажатия всех кнопок
      if (timeDat[2]>millis()) {keyPush();}              //Ожидание если все кнопки нажаты
      else
      {knopKal();}                                       //Переход на функцию калибровки кнопок по достижении времени
      break;
    
      // default необязателен
  }
        


//********Блок вывода диммирования на лампу********

      //Dimmer2=100;
      //delay(500);
      //Dimmer2=150;
      //delay(500);
 
      //Dimmer1=200;
      //Dimmer3=200;
      
//********Конец блока вывода диммирования****//


//********Запуск прерывания диммеров после RESET****************
   
                                        //Запуск прерывания для работы диммеров (если запускать в Setup, не позволяет инициализироватся
                                        //остальным устройствам, дисплей, часы и т.д. Запускается один раз после перезагрузки.
   if (f==0)                            //Флаг состояния прервания после перезагрузки
  {
    f++;                                //Изменение флага состояния прерывания
   attachInterrupt(0, detect_up, LOW);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень
  }
}
//********Конец блока запуска прерывания после RESET*************

//***********ОКОНЧАНИЕ ОСНОВНОГО ЦИКЛА*****************************

      
bwn
Offline
Зарегистрирован: 25.08.2014

Установка времени нужна кнопками, т.к. после отладки, общего с Ардуиной останется Atmega с кварцем. Все остальное отдельный девайс.

Cyoko
Offline
Зарегистрирован: 22.08.2014

С дневными таймерами вроде разобрался.....Сейчас буду думать о периодичных.....
Постепенно встает вопрос о разъемах для подключения датчиков и внешних устройств....

Кто что может посоветовать ?
Интересуют трех пиновые разъемы для подключения датчиков температуры, давления и т.д.
Двух пиновые для управления нагрузкой. Вообще думаю сделать модуль на базе розетки.... Типа в розетку ИН подаем и 220 и - . А с розетки АУТ выходит 220 и - , но уже скоммутированный через реле.
И какие реле можете посоветовать для управления нагрузкой скажем до 1КВт , ну тот же свет Днат например?

bwn
Offline
Зарегистрирован: 25.08.2014

Релюшки любые на 10А, возможно SSR, но с балластом не знаю как себя поведут. Разъемы под датчики, для себя остановился - винт или пайка. Остальные в уличных условиях думаю будет колбасить.  Силовые буду ставить компьютерные сетевые, у них "земля" имеется и размер поменьше розетки.

Cyoko
Offline
Зарегистрирован: 22.08.2014

Я просто хочу коробочку аккуратную сделать и чтоб из нее "мамы" выходили.... Вот думаю какие разъемы лучше использовать....Чтоб они удобно крепились к корпусу....
По поводу реле, взял на пробу такие :

http://ru.aliexpress.com/item/5V-One-1-Channel-Relay-Module-Board-Shield...

Пока не пробовал с нормальной нагрузкой, попробую, отпишу. Но чтото сомневаюсь что они потянут 600Днат например. Поэтому вот думаю какие внешние может есть на примете , надежные.....

bwn
Offline
Зарегистрирован: 25.08.2014

Если надежные, то лучше посмотреть в сторону контакторов на DIN рейку и весь девайс делать в этом формфакторе. Реле управляет контактором, контактор на мощную нагрузку. Заодно и УЗО туда воткнуть. Теплица-влажность-фаза 220В-БАХ.

Cyoko
Offline
Зарегистрирован: 22.08.2014

Вот я в этом же ключе и думаю :) Просто не электрик , поэтому не знаю что лучше использовать. Думаю надо чтоб ардуина включала релюшку , а сама релюшка внешняя, подбирается для нужд отдельно.

Cyoko
Offline
Зарегистрирован: 22.08.2014

Еще обнаружился косячок , что на ардуино уно уже код не влезает :) Но это пока до лучших времен....

Cyoko
Offline
Зарегистрирован: 22.08.2014

Вот еще какая трабла нарисовалась.... Решил провести тест точности датчиков температуры.... Имеем Мега+DHT11 ,  УНО+DS18B20 и обычный термометр.

Обычный - 25

DHT11 - 23

DS18B20 -26,2

Где заявленная точность в десятые градуса ? Так как на DHT11 убрал десятые и сотые , предположим занижает на полтора градуса. DS18B20 завышает на градус.

В чем подвох ?

 

bwn
Offline
Зарегистрирован: 25.08.2014

DHT это вообще особая песня. Далее сквозняки и нагр.приборы(в т.ч. комп.) и обычный термометр какой используете?

Cyoko
Offline
Зарегистрирован: 22.08.2014

да все рядом на столе лежит, в 3 см друг от друга..... Ну обычный термометр, спиртовой наверно, жидкость вообщем внутри колбы :) Хотя может и на нем шкала не правильно нарисована .....

bwn
Offline
Зарегистрирован: 25.08.2014

Термометр лучше ртуть (более менее точные данные). Сверять - какая нибудь коробка с высокими бортами и крышкой (убираем сквозняк) и выдержка минут 15. DS ки очень чувствительные, буквально от дуновения температура ползет.

bwn
Offline
Зарегистрирован: 25.08.2014

Второй вариант - DS ку и градусник подмышку, краем глаза смотрим пока не остановится.

Cyoko
Offline
Зарегистрирован: 22.08.2014

Вообщем надо эталонный градусник искать :)

bwn
Offline
Зарегистрирован: 25.08.2014

Подмышкой проще. Там сразу разницу увидете. А +-0,5 на DS ке и так заявлено. Я на 4 одновременно проверял, в эту погрешность попадали.

itjunky
Offline
Зарегистрирован: 15.09.2014

У меня так же много разных DS, у них разброс не больше полуградуса, и DHT11 так же с разбросом около градуса.

Cyoko
Offline
Зарегистрирован: 22.08.2014

да я просто не пойму , неужели у меня дома 26-27 градусов :) чет жарковато как то 

witamin
Offline
Зарегистрирован: 05.04.2013

DHT22 лучше DHT11 но медленые очень

у них влажность болеменее но от прямой влаги нужно изолировать

 

DS лучше всех. Только с точностью 12 бит долго ответ дает зато десятые бегут

может стол нагретый или провода

проверь на льду таяние льда 0гр кипение воды 100гр

кстати там минус не все библиотеки на DS18b20 реализуют правильно, проверь за окошком

хотя на лето пофигу и как правило 3-5 градусов погрешность не так важна

следующий точный датчик только такой   куча коэфициентов и точность не очень

 

Cyoko
Offline
Зарегистрирован: 22.08.2014

А от плохой пайки может врать на градус другой ? А то я DS сам припаивал к платке модуля...Ну на которой резисторы и диодик и пины :)

renoshnik
Offline
Зарегистрирован: 11.04.2013

таймер полива

https://www.youtube.com/watch?v=VsHSq5yDYUc

 

Тима
Тима аватар
Offline
Зарегистрирован: 11.04.2013

Я бы "обычным термометрам" не доверял... Делал как-то автоматику на теплицу, натыкал датчики температуры(3 датчика на воздух и 1 на почву). Колибровал относительно ртутного термометра. Хозяит подошел ко мне с притензиями, что данные с панели управления и с "обычных термометров" не совпадают. Тогда я собрал все датчики и термометнры в одном месте, подождали минут 30 и сравнили показания... Все "мои" датчики как и ртутный показывали одну температуру, а из "обычных" не было двух с одним показанием, разница между большим и меньшим была 4 градуса...

Jonny
Offline
Зарегистрирован: 15.12.2014

Как можно с Вами связаться? Напишите пжл мне, на почту ramon6@mail.ru или в контакт https://vk.com/alexnoname1111

Cyoko
Offline
Зарегистрирован: 22.08.2014

Это вы мне написали ? :)

itjunky
Offline
Зарегистрирован: 15.09.2014

Jonny пишет:

Как можно с Вами связаться? Напишите пжл мне, на почту ramon6@mail.ru или в контакт https://vk.com/alexnoname1111

 

Вася, тебя ищет Катя, позвони Пете =)

garag.75
Offline
Зарегистрирован: 22.12.2014

доброго времени суток.интересная тема сам занимаюсь теплицей а вот в програмровании слабый хочу попросит у вас помощи .

у меня есть от куда взять тёплай воздух и хочу регулировать подачувот таким устройством

http://bigbarrel.ru/%D0%BA%D0%BB%D0%B8%D0%BC%D0%B0%D1%82-%D0%BA%D0%BE%D0...

всё вроде сделал правельно но у меня не работает.с аналоговым датчиком работаее а с далласом не работает.помогите

 

garag.75
Offline
Зарегистрирован: 22.12.2014

вот самая полезная вещь в теплице жду с ебея детали

http://ganja-forum.com/index.php?threads/%D0%90%D0%B2%D1%82%D0%BE%D0%BC%...

itjunky
Offline
Зарегистрирован: 15.09.2014

garag.75 пишет:

доброго времени суток.интересная тема сам занимаюсь теплицей а вот в програмровании слабый хочу попросит у вас помощи .

у меня есть от куда взять тёплай воздух и хочу регулировать подачувот таким устройством

http://bigbarrel.ru/%D0%BA%D0%BB%D0%B8%D0%BC%D0%B0%D1%82-%D0%BA%D0%BE%D0...

всё вроде сделал правельно но у меня не работает.с аналоговым датчиком работаее а с далласом не работает.помогите

 

Куча предыстории и одно слово про саму проблему... Может быть Вы опишете более подробно что было сделано и какой конкретно получился результат? Или Вы ожидаете, что Вам дадут готовую программу под Вашу задачу? Вряд ли кто-то будет писать для Вас код бесплатно. Зато многие готовы рассказать чего куда пихать и какой алгоритм применить.

garag.75
Offline
Зарегистрирован: 22.12.2014

да мне только и нужно чтоб ктото только проверил скетч и сказал что он работает или нет если есть ошибки то сказал что да есть ошибки ищи.вот и всё .я собрал всё по схеме загрузил все библиотеки и залил скетч ,серва стала в удержание а на повороты резистором не реагирует

я просто хоть какуюто подсказку жду всё равно спасибо

 

witamin
Offline
Зарегистрирован: 05.04.2013

Проверить не могу, но стандартные действия - проверь какие данные выводятся с датчика, сделай проверку значений близких к крайним. Сделай задержку опроса датчика и отработку нового значения сервой, округление сглаживание данных . Дергай серву только если  значение датчика изменилось на ХХ.   А так всё правильно, серве с датчика Всё время приходит - например 0,5 0,6 0,5 и она их честно отрабатывает 

garag.75
Offline
Зарегистрирован: 22.12.2014

мне вот что не понятно вот тут

return map(analogRead(1),255,1023,15,27);//читаем положение регулятора температуры(потенциометр)
}
void loop() {
if (digitalRead(1)==HIGH){

я так мпонял что резистор подключается к а1 апочему тогда сравнивают д1 с высоким уровнем?

witamin
Offline
Зарегистрирован: 05.04.2013

Дословно. Первая строка это преобразование аналогового значения с пина а1 в значение из диапазона map, почитай про эту функцию

дальше идет главный циикл программы 

Условие если вход D1 высокий то ... дальше см программу

это разные части программы смотри что входит на D1 по тексту программы я не понял для чего этот D1 

закоментируй эту проверку и проверь 

еще пример без Пид регулятора http://habrahabr.ru/post/146190/

ну сам поищи должен кто-то уже такое сделать

 

garag.75
Offline
Зарегистрирован: 22.12.2014

вот я и не понял что там сидит 

#define ONE_WIRE_BUS 4  Сидит датчиктемпературы  д4сидит датчик температуры
myservo.attach(3,2540,640);//устанавливаем пин управления servo/устанавливаем границы поворота сервы  тоже понялкуда серва цепляется д3

 

int sp(){
return map(analogRead(1),255,1023,15,27);//читаем положение регулятора температуры(потенциометр)
} цепляем резистор на а1

а вот на д1 я не понял что цеплять ,может кнопка включения ?

witamin
Offline
Зарегистрирован: 05.04.2013

Автор там обещал дальше написать может фото были бы но пока можно просто выкинуть.

ИЛИ это включено зажигание - можно так наверное думать.  Точно!

 

itjunky
Offline
Зарегистрирован: 15.09.2014

Мдааа, помогать кому-то не понимающему в программировании понять ЧУЖУЮ прогу, написанную под конкретно его оборудование и его задачу... По-моему не благодарное дело. Примерно как глухой рассказывает слепому про то как ему когда-то описывали шум морского прибоя...

Гараж, Вы если купили такой девайс, то у автора бы и спросили чего как. А ежели сами решили воспроизвести, то надо это делать не с конца, а начала ж. А начало, очевидно лежит в освоении базвого программирования и обучения находить нужную инфу. Нарпимер по приведённому коду всю инфу можно получить в справке по программированию на ардуино.

В любом случае компилить прогу у себя в голове глупейшая затея. Поскольку в раельных условиях могут прийти данные, которые ты даже не предполагал получить в этом месте, а подключение устройств так же может быть не корректным, что скажется на поведении программы. Так что такие сложные системы необходмио тестировать только в купе с железом. С этой задачей может помочь вот такое виртуальное железо как на этом сайте http://123d.circuits.io/ Но мне почему-то кажется, что  Гараж не поймёт как с ним работать.

garag.75
Offline
Зарегистрирован: 22.12.2014

itjunky пишет:

Мдааа, помогать кому-то не понимающему в программировании понять ЧУЖУЮ прогу, написанную под конкретно его оборудование и его задачу... По-моему не благодарное дело. Примерно как глухой рассказывает слепому про то как ему когда-то описывали шум морского прибоя...

Гараж, Вы если купили такой девайс, то у автора бы и спросили чего как. А ежели сами решили воспроизвести, то надо это делать не с конца, а начала ж. А начало, очевидно лежит в освоении базвого программирования и обучения находить нужную инфу. Нарпимер по приведённому коду всю инфу можно получить в справке по программированию на ардуино.

В любом случае компилить прогу у себя в голове глупейшая затея. Поскольку в раельных условиях могут прийти данные, которые ты даже не предполагал получить в этом месте, а подключение устройств так же может быть не корректным, что скажется на поведении программы. Так что такие сложные системы необходмио тестировать только в купе с железом. С этой задачей может помочь вот такое виртуальное железо как на этом сайте http://123d.circuits.io/ Но мне почему-то кажется, что  Гараж не поймёт как с ним работать.

уважаемый вас не кто не очём не просил,а хамить не надо ато ясам станухамом .

я  не думал что всё так сложно (для знающего человека )

Cyoko
Offline
Зарегистрирован: 22.08.2014

Не надо в моей теме ругаться :)
Лучше скажите что там с регулировкой ПШ ? Знаю что основная проблема в недолговечности датчика , точности измерения, решили эти вопросы ? И что там с насосами велко ? Они правда так хороши и где их покупать ?

garag.75
Offline
Зарегистрирован: 22.12.2014

пш  датчик как не крути а всё равном будет обростать микроорганизмами ,но на кокоето время хватит .смотрел репор так у человека он циклотпахал нормальна .Купить можно на ебее Идатчик и моторы  и усилитель к датчику правдо последний самый дорогой, а на щёт помпы была попытка использовать насос стекломывателя но кислота в течении вроде месяца сьела вал.Лучше раз вмесяц калибровать пребор чем каждый день мерять пш ,рост растений в первую очередь от пш 

http://www.ebay.com/itm/PH-Electrode-Probe-BNC-Connector-for-Aquarium-PH-Controller-Meter-Sensor-JT1-/400473542857?pt=LH_DefaultDomain_0&hash=item5d3e1550c9

http://www.ebay.com/itm/12V-DC-DIY-Dosing-pump-Peristaltic-dosing-Head-For-Aquarium-Lab-Analytica-water-/111490364442?pt=LH_DefaultDomain_0&hash=item19f557f41a

 

http://www.ebay.com/itm/pH-Circuit-Sensor-for-Arduino/191271586094?_trksid=p2045573.c100033.m2042&_trkparms=aid%3D111001%26algo%3DREC.SEED%26ao%3D1%26asc%3D20131017132637%26meid%3Df3adbfc092db4c2fa1cccbb7c22d742f%26pid%3D100033%26prg%3D20131017132637%26rk%3D1%26rkt%3D4%26sd%3D191271586094

 

itjunky
Offline
Зарегистрирован: 15.09.2014

Цикл это очень мало. В то же время измерять ph постоянно не нужно. Это необходимо делать примерно два раза в сутки и при поливе. Соответственно, есть два решения:
1 либо опускать датчик в раствор в нужный момент на пару минут
2 либо закачивать измеряемую жидкость в резервуар с датчиом.

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

Cyoko
Offline
Зарегистрирован: 22.08.2014

Пока об этом не думаю , но чтоб было в одном месте....
Вот какой вопрос у меня....
Есть у меня таймер на свет , например в 9 утра включается и в 2 ночи выключается (не суть важно ) . Вот как я это делаю сейчас :

if ( TimeHHon == RTC.hour & TimeMMon == RTC.minute ) digitalWrite(Relay2_PIN, HIGH); //если наступило время включения , включаем свет
  else if ( TimeHHoff == RTC.hour & TimeMMoff == RTC.minute ) digitalWrite(Relay2_PIN, LOW);// если наступило время выключения , выключаем свет

У этого способа есть недостатки.... Один из самых больших , что если я включил устройство(свет мигнул) в промежутке между временем включения и выключения , то свет не включится.

Вариантов решения вижу два : 1- записывать состояние реле в еепром . 2- делать условие не по времени , а по периоду .

2 вариант как осуществить не знаю.

1 вроде без проблем осуществим.

Есть ли еще какие варианты или 1 вариант норм ?

p.s. пока отказался от усложнения устройства , хочу сделать уже работающий вариант (так сказать проверить работоспособность вообще). Пока собрал все на листе из ДСП. 2 реле - одно следит за температурой и включает вентилятор , второе по таймеру свет. Сделал на базе УНО , поэтому от меню пришлось отказаться(памяти не хватает. МЕГУ оставил для продолжения проекта..... Если кому интересно посмотреть как я все это сделал(хе-хе) могу выложить фотки . Еще есть много вопросов именно по сборке и комплектующим , но вначале таймер охото добить.

witamin
Offline
Зарегистрирован: 05.04.2013

Вариант 1 можно дергать раз в минуту или пять, по условию - пока время включения меньше стартового и больше времени выключения

Запись бита состояния в епром - это лучшее что придумано

для смеха можно прикрутить фотореле рядом с лампочкой и проверять также по условию 

плюсы не знаю - может реле меньше натрудится

Cyoko
Offline
Зарегистрирован: 22.08.2014

Первое испытание закончилось неудачей :(
Когда нагревал датчик , вентилятор включался и выключался. Но когда включилась лампа и нагрела датчик , вентилятор не сработал. Не знаю почему , но датчик словил ерор я так понял . Температуру показывал -127 почемуто.

Может это из-за того что интервал опроса датчика 30 секунд и лампа его за это время перегрела ? (После перезагрузки ардуины лампа самособой выключилась , температуру показал 47 грдусов , включил вентилятор)

А может быть при включении лампы какие наводки пошли ? (лампу взял пока 150 ватт днат+эпра , хотелось бы конечно потестить с 400 или 600 , но что то дорого стоят)

 

Теперь что касаемо таймера : вот идея проверки на меньше, больше мне очень нравится

Так это получается : time >9  & time < 2 абракадабра получается :) ааааа, пока читал понял что может есть логическое или :) убег в раздел програмирования .....

С записью в еепром вот вроде какой косяк , например свет выключился когда лампа включена , записали значение 1. А включили свет когда лампа должна быть выключена , получается так и проработает до следующей ночи . От кратко времменных  выключений конечно это спасет.

 

Про фотореле не понял :)

bwn
Offline
Зарегистрирован: 25.08.2014

Cyoko пишет:

Первое испытание закончилось неудачей :(
Когда нагревал датчик , вентилятор включался и выключался. Но когда включилась лампа и нагрела датчик , вентилятор не сработал. Не знаю почему , но датчик словил ерор я так понял . Температуру показывал -127 почемуто.

Может это из-за того что интервал опроса датчика 30 секунд и лампа его за это время перегрела ? (После перезагрузки ардуины лампа самособой выключилась , температуру показал 47 грдусов , включил вентилятор)

А может быть при включении лампы какие наводки пошли ? (лампу взял пока 150 ватт днат+эпра , хотелось бы конечно потестить с 400 или 600 , но что то дорого стоят)

 

Теперь что касаемо таймера : вот идея проверки на меньше, больше мне очень нравится

Так это получается : time >9  & time < 2 абракадабра получается :) ааааа, пока читал понял что может есть логическое или :) убег в раздел програмирования .....

С записью в еепром вот вроде какой косяк , например свет выключился когда лампа включена , записали значение 1. А включили свет когда лампа должна быть выключена , получается так и проработает до следующей ночи . От кратко времменных  выключений конечно это спасет.

 

Про фотореле не понял :)

По таймеру, суммируйте часы с минутами. Если больше включения и меньше выключения - HIGH.

ДНАТ вроде с балластом, развязывайте питание.

Cyoko
Offline
Зарегистрирован: 22.08.2014

С минутами решил не заморачиваться , пусть включается в 00 минут . Фишка в том что время включения больше чем время выключения . Ищу как будет или в языке . Что значит развязывать питания ?
У меня так вилка из "устройства" в розетку дома . внутри устройства клемник , 0 - напрямую к двум розеткам , Фаза к двум реле от них к розеткам.

Cyoko
Offline
Зарегистрирован: 22.08.2014

вот как написал 

if ( RTC.hour >= TimeHHon || RTC.hour <= TimeHHoff ) digitalWrite(Relay2_PIN, HIGH); //если время больше или равно времени включения или меньше или равно времени выключения , то светим
  else if ( RTC.hour < TimeHHon & RTC.hour > TimeHHoff ) digitalWrite(Relay2_PIN, LOW);// если время меньше времени включения и больше времени выключения не светим 

правильно ?

bwn
Offline
Зарегистрирован: 25.08.2014

Cyoko пишет:

вот как написал 

if ( RTC.hour >= TimeHHon || RTC.hour <= TimeHHoff ) digitalWrite(Relay2_PIN, HIGH); //если время больше или равно времени включения или меньше или равно времени выключения , то светим
  else if ( RTC.hour < TimeHHon & RTC.hour > TimeHHoff ) digitalWrite(Relay2_PIN, LOW);// если время меньше времени включения и больше времени выключения не светим 

правильно ?

Во второй строке, после else просто digitalWrite(...,LOW). Вроде так.

А питание - RC цепочки, кондеры к DS18, может провод к DS разносить от провода ДНАТ, экранированный провод. Здесь уже эксперимент.

В первой строке наверно все таки &

bwn
Offline
Зарегистрирован: 25.08.2014

Вместо реле возможно симистор с оптопарой и отловом нуля.

Cyoko
Offline
Зарегистрирован: 22.08.2014

Теперь почемуто при включении вентилятора начинает включатся и выключатся свет. Может из-за того что фаза как то перетекает через общую розетку ?