Помогите разобраться с кодом инкубатора

soldat6600
Offline
Зарегистрирован: 14.12.2014

Помогите пожалуйсто заменить датчик влажности и температуры SHT на DHT11. Сам пробовал не получается.



#include <PID_v1.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM2.h>
#include <DallasTemperature.h>
#include <OneWire.h>
//#include <SimpleTimer.h>
#include <Sensirion.h>



int del = 80;                     // переменная ожидания между выборами меню
unsigned int interval = 100;      // интервал сколько будет длиться цикл while, после чего перейдёт к следующему меню.(кол-во итераций)

#define heater_pin 13                  // нагреватель
#define humidifer_pin 12               // увлажнитель
#define fan_pin 11                    // вентилятор
#define alarm_pin 14                   // пин аварии
#define beeper_pin 9                //пищалка по аварии
#define dataPin 5                      //SHT10
#define clockPin 6                     //SHT10 
#define turn_pin 10                // управление поворотом
#define button_minus_pin 2            //пин кнопки "минус"
#define button_plus_pin 3             //пин кнопки "плюс"
#define button_enter_pin 4            //пин кнопки "enter"
#define DS18B20_Pin 7                 //пин термометра
#define setSampleTime 1000            //время цикла ПИД
#define voltmeter_pin 1               //вход А1 через делитель (22к/10к) подключен к питанию модуля. Измеряет до 16В.
#define T_correction -0.4              // коррекция температуры SHT10

boolean button_minus;
boolean button_plus;
boolean button_enter;
boolean turnFlag = 0;              // флаг поворота для случайного периода
float humidity;                  // Влажность
float temp1Ink;                  // Температура DS18B20  
float temp2Ink;                  // Температура SHT10
float dewpoint;                  // Точка росы

unsigned int rawData;
unsigned long currentTime;            // задаем переменные для тайминга поворота
unsigned long loopTime;
unsigned long serialTime; //this will help us know when to talk with processing
unsigned long now;
unsigned long trhMillis = 0;    // период опроса датчиков
byte measActive = false;
byte measType = TEMP;
const unsigned long TRHSTEP   = 3000UL;  // Sensor query period

LiquidCrystal_I2C lcd(0x27, 20, 4);  // инициализация библиотеки дисплея
//SHT1x sht1x(dataPin, clockPin);
OneWire oneWire(DS18B20_Pin);
DallasTemperature sensors(&oneWire);
Sensirion sht = Sensirion(dataPin, clockPin);

double Setpoint, Input, Output;            //объявляем переменные для ПИД
PID myPID(&Input, &Output, &Setpoint, 5, 4, 3, DIRECT); //Инициализируем ПИД-библиотеку и коэффициенты
int WindowSize = setSampleTime;                  // ширина окна терморегулятора 1 секунда.
unsigned long windowStartTime;

//SimpleTimer timer;

/*  EEPROM1 -   tempInk
 EEPROM5 (13) -   set_humidity
 EEPROM7 -   alarmTemp
 EEPROM9 -   fanTemp
 EEPROM11 -  turnPeriod            */




void setup() {
  Serial.begin(9600);

  lcd.init();          // Старт дисплея
  lcd.backlight();     // Включаем подсветку дисплея
  windowStartTime = millis();
  byte stat;
  byte error = 0;
  delay(15);

  myPID.SetOutputLimits(0, WindowSize); //задаем лимиты ширины ПИД-импульса от 0 до 1 секунды.
  myPID.SetMode(AUTOMATIC);             //включаем ПИД-регулирование
  myPID.SetSampleTime(setSampleTime);

    pinMode(8, OUTPUT);      //пока не используемый 8 вывод. Переводим в 1 чтобы не включать реле.
    digitalWrite(8, HIGH);
  pinMode(heater_pin, OUTPUT);
  pinMode(turn_pin, OUTPUT);      // устанавливаем выводы
  digitalWrite(turn_pin, HIGH);
  pinMode(humidifer_pin, OUTPUT);
  pinMode(fan_pin, OUTPUT);
  digitalWrite(fan_pin, HIGH);
  pinMode(alarm_pin, OUTPUT);
  digitalWrite(alarm_pin, HIGH);
  pinMode(button_minus_pin, INPUT_PULLUP); //подтягиваем входы кнопок к плюсу встроенными резисторами
  pinMode(button_plus_pin, INPUT_PULLUP);
  pinMode(button_enter_pin, INPUT_PULLUP);

  sensors.begin();
  sensors.setResolution(12);    // установить разрешение (точность)
  sensors.setWaitForConversion(false);  // отключить ожидание

  //timer.setInterval(3000, getSensors);

  windowStartTime = millis();
  currentTime = millis();  // считываем время, прошедшее с момента запуска программы

  loopTime = currentTime;

  //EEPROM_write(1, 37.5);
  //EEPROM_write(13, 65.0);
  //EEPROM_write(13, 61.0);
}

void loop() {
  // Input = getTemp();
  unsigned long now = millis();

  //timer.run();
  button_read();
  if (!button_enter) {
    delay(del);
    lcd.clear();
    menu();
  }
  if (!button_minus) {
    delay(del);
    lcd.clear();
    alarm_delay();    // задержка аварии по нажатии кнопки Минус
  }
  if (!button_plus) {
    delay(del);
    lcd.clear();
    //действие по нажатии кнопки "+"
  }
  //send-receive with processing if it's time
  if (millis() > serialTime)
  {
    SerialReceive();
    SerialSend();
    serialTime += 500;
  }
  getSensors();
  thermostat();
  humidifer();
  turn();
  fan();
  alarm();
  outpuPower();
  //unsigned long now1 = millis();
  //Serial.println(now1-now);
}


void button_read() {//функция проверки нажатия кнопки
  button_minus = digitalRead(button_minus_pin); //запоминаем значение кнопки
  button_plus = digitalRead(button_plus_pin); //запоминаем значение кнопки
  button_enter = digitalRead(button_enter_pin); //запоминаем значение кнопки
  if (!button_minus || !button_plus || !button_enter) beeper(50);
}

//меню
void menu() {
  temp_setup();
  hum_setup();
  turn_setup();
  alarm_setup();
  vent_setup();
  //data_time_setup();
}




//устанавливаем температуру в меню
void temp_setup() {
  float tempInk;
  lcd.clear();
  delay(del);
  button_read();
  lcd.setCursor(2, 0);
  lcd.print("TEMP.INK SETUP");
  delay(1000);
  int x = 0;
  while (1) {
    x++;
    if (x > interval) {
      break;
    }
    button_read();
    //EEPROM_write(1, 37.5);
    EEPROM_read(1, tempInk);
    if (!button_enter) {
      delay(del);
      lcd.clear(); //очищаем экран
      break;
    }
    if (!button_minus) {
      EEPROM_write(1, tempInk + 0.1);
      if (tempInk > 40) {     //проверяем, если выше 40,
        EEPROM_write(1, 40);  //пишем в память 40
      }
      lcd.clear();
    }

    if (!button_plus) {
      EEPROM_write(1, tempInk - 0.1);
      if (tempInk < 30.0) {     //проверяем, если выше 30,
        EEPROM_write(1, 30.0);  //пишем в память 30
      }
      lcd.clear();
    }
    lcd.setCursor(2, 0);
    lcd.print("TEMP.INK = ");
    lcd.print(tempInk, 1);
    lcd.setCursor(0, 3);
    lcd.print("minus  NEXT  plus");
    delay(del);
  }
}


//устанавливаем влажность
void hum_setup() {
  float set_humidity;
  lcd.clear();
  delay(del);
  button_read();
  lcd.setCursor(3, 0);
  lcd.print("HUMIDITY SETUP");
  delay(1000);
  int x = 0;
  while (1) {
    x++;
    if (x > interval) {
      break;
    }

    button_read();
    //EEPROM_write(13, 65.0);
    //EEPROM_read_mem(13, &set_humidity, sizeof(set_humidity));
    EEPROM_read(13, set_humidity);

    if (!button_enter) {
      delay(del);
      lcd.clear(); //очищаем экран
      break;
    }
    if (!button_minus) {
      EEPROM_write(13, set_humidity + 0.5);
      if (set_humidity > 100) {     //проверяем, если выше 40,
        EEPROM_write(13, 100.0);  //пишем в память 40
      }
      lcd.clear();
    }

    if (!button_plus) {
      EEPROM_write(13, set_humidity - 0.5);
      if (set_humidity < 20) {     //проверяем, если выше 40,
        EEPROM_write(13, 20.0);  //пишем в память 40
      }
      lcd.clear();
    }

    lcd.setCursor(2, 0);
    lcd.print("Humidity = ");
    lcd.print(set_humidity, 1);
    lcd.setCursor(0, 3);
    lcd.print("minus  NEXT  plus");
    delay(del);
  }

}

//устанавливаем поворот
void turn_setup() {
  int turnPeriod;
  lcd.clear();
  delay(del);
  button_read();
  lcd.setCursor(4, 0);
  lcd.print("TURN SETUP");
  delay(1000);
  int x = 0;
  while (1) {
    x++;
    if (x > interval) {
      break;
    }

    button_read();
    EEPROM_read(11, turnPeriod);

    if (!button_enter) {
      delay(del);
      lcd.clear(); //очищаем экран
      break;
    }
    if (!button_minus) {
      EEPROM_write(11, turnPeriod + 1);
      if (turnPeriod > 13) {     //проверяем, если выше 40,
        EEPROM_write(11, 13);  //пишем в память 40
      }
      lcd.clear();
    }

    if (!button_plus) {
      EEPROM_write(11, turnPeriod - 1);
      if (turnPeriod < 0) {     //проверяем, если выше 40,
        EEPROM_write(11, 0);  //пишем в память 40
      }
      lcd.clear();
    }
    EEPROM_read(11, turnPeriod);
    lcd.setCursor(2, 0);
    lcd.print("PERIOD = ");
    lcd.print(turnPeriod);
    lcd.print(" Hour");
    lcd.setCursor(0, 3);
    lcd.print("minus  NEXT  plus");
    delay(del);
  }
}


//устанавливаем сигнализацию
void alarm_setup() {
  int alarmTemp;
  lcd.clear();
  delay(del);
  button_read();
  lcd.setCursor(4, 0);
  lcd.print("ALARM SETUP");
  delay(1000);
  int x = 0;
  while (1) {
    x++;
    if (x > interval) {
    break;
    }

    button_read();
    EEPROM_read(5, alarmTemp);

    if (!button_enter) {
      delay(del);
      lcd.clear(); //очищаем экран
      break;
    }
    if (!button_minus) {
      EEPROM_write(5, alarmTemp + 1);
      if (alarmTemp > 10) {     //проверяем, если выше 40,
        EEPROM_write(5, 10);  //пишем в память 40
      }
      lcd.clear();
    }

    if (!button_plus) {
      EEPROM_write(5, alarmTemp - 1);
      if (alarmTemp < 1) {     //проверяем, если выше 40,
        EEPROM_write(5, 1);  //пишем в память 40
      }
      lcd.clear();
    }
    lcd.setCursor(2, 0);
    lcd.print("T.Alarm + - ");
    lcd.print(alarmTemp);
    lcd.print((char)223);
    lcd.print("C");
    lcd.setCursor(0, 3);
    lcd.print("minus  NEXT  plus");
    delay(del);
  }

}

//устанавливаем вентиляцию
void vent_setup() {
  int fanTemp;
  lcd.clear();
  delay(del);
  button_read();
  lcd.setCursor(4, 0);
  lcd.print("FAN SETUP");
  delay(1000);
  int x = 0;
  while (1) {
    x++;
    if (x > interval) {
      break;
    }

    button_read();
    EEPROM_read(9, fanTemp);

    if (!button_enter) {
      delay(del);
      lcd.clear(); //очищаем экран
      break;
    }
    if (!button_minus) {
      EEPROM_write(9, fanTemp + 1);
      if (fanTemp > 40) {     //проверяем, если выше 40,
        EEPROM_write(9, 40);  //пишем в память 40
      }
      lcd.clear();
    }

    if (!button_plus) {
      EEPROM_write(9, fanTemp - 1);
      if (fanTemp < 20) {     //проверяем, если выше 40,
        EEPROM_write(9, 20);  //пишем в память 40
      }
      lcd.clear();
    }
    lcd.setCursor(4, 0);
    lcd.print("T.Fan = ");
    lcd.print(fanTemp);
    lcd.print((char)223);
    lcd.print("C");
    lcd.setCursor(0, 3);
    lcd.print("minus  NEXT  plus");
    delay(del);
  }
}




void getSensors(){

  unsigned long curMillis = millis();          // Получаем текущее время работы
  sensors.requestTemperatures();

  // Demonstrate non-blocking calls
  if (curMillis - trhMillis >= TRHSTEP) {      // время для нового измерения?
    measActive = true;
    measType = TEMP;
    sht.meas(TEMP, &rawData, NONBLOCK);        // измеряем температуру.
    trhMillis = curMillis;
  }
  if (measActive && sht.measRdy()) {           // проверяем статус измерения
    if (measType == TEMP) {                    // обрабатываем температуру или влажность?
      measType = HUMI;
      temp2Ink = sht.calcTemp(rawData);     // Конвертируем сырые данные с сенсора
      temp2Ink = (temp2Ink + (T_correction)); // Корректируем показания текрмометра
      temp1Ink = sensors.getTempCByIndex(0);
      sht.meas(HUMI, &rawData, NONBLOCK);      // измеряем влажность
    } 
    else {
      measActive = false;
      humidity = sht.calcHumi(rawData, temp2Ink); // конвертируем данные с сенсора
      dewpoint = sht.calcDewpoint(humidity, temp2Ink);

    }
  }
 // logData();
}



//void logData() {
//  Serial.print("temp1Ink = ");   
//  Serial.print(temp1Ink);
//  Serial.print("temp2Ink = ");   
//  Serial.print(temp2Ink);
//  Serial.print(" C, Humidity = ");  
//  Serial.print(humidity);
//  Serial.print(" %, Dewpoint = ");  
//  Serial.print(dewpoint);
//  Serial.println(" C");
//}



//используем терморегулятор
void thermostat() {
  now = millis();
  float tempPoint;
  EEPROM_read_mem(1, &tempPoint, sizeof(tempPoint));
  EEPROM_read(1, tempPoint);
  Setpoint = tempPoint;
  myPID.Compute();


  if (now - windowStartTime > WindowSize) { //время для перещелкивания периода окна
    windowStartTime = windowStartTime + WindowSize;
    //voltmeter();                        //запускаем функцию измерения напряжения
    Input = temp1Ink;
    lcd.setCursor(1, 0);                 // устанавливаем курсор в 0-ом столбце, 0 строка (начинается с 0)
    lcd.print("T1= ");
    lcd.print(temp1Ink, 1);              // печать температуры на дисплей
    lcd.print((char)223);
    lcd.print("  (");
    lcd.print(Setpoint, 1);
    lcd.print(")");
    lcd.setCursor(1, 1);
    lcd.print("T2= ");
    lcd.print(temp2Ink, 1);            // печать температуры на дисплей
    lcd.print((char)223);
    lcd.setCursor(11, 1);
    lcd.print(" (*");
    lcd.print(temp1Ink - temp2Ink, 1);
    lcd.print(") ");
    //lcd.print((char)223);
    //lcd.print("  (");
    //lcd.print(Setpoint, 1);
    //lcd.print(")");

  }
  if (Output > (now - windowStartTime)) digitalWrite(heater_pin, HIGH);
  else digitalWrite(heater_pin, LOW);

}

//управляем влажностью
void humidifer() {
  //float humidity;
  float set_humidity;
  unsigned long humMillis = 0;
  unsigned long curMillis = millis();
  //  if (curMillis - humMillis >= humStep) {  
  //    humMillis = curMillis;
  //    //humidity = sht1x.readHumidity();
  //  }
  EEPROM_read_mem(13, &set_humidity, sizeof(set_humidity));
  EEPROM_read(13, set_humidity);
  lcd.setCursor(1, 2);                 // устанавливаем курсор в 0-ом столбце, 1 строка (начинается с 0)
  lcd.print(" H= ");
  lcd.print(humidity, 1);           // печать влажности на дисплей
  lcd.print("%");
  lcd.print("  (");
  lcd.print(set_humidity, 1);
  lcd.print(")");
  if (set_humidity > humidity) digitalWrite(humidifer_pin, HIGH); //сравниваем измеренную влажность с заданной
  else digitalWrite(humidifer_pin, LOW); //если влажность низкая, включаем увлажнитель

}


//управляем поворотом
void turn() {
  int turnPeriod;                //период поворота лотков в часах
  int turnCommand;
  EEPROM_read(11, turnPeriod);
  lcd.setCursor(10, 3);
  lcd.print("P");
  lcd.print(turnPeriod);
  if (turnPeriod == 0) return;           //если нулевой период поворота, то не поворачиваем яйца.
  if (turnPeriod < 13) turnCommand = turnPeriod;
  else if (turnPeriod > 12 && turnFlag == 0) { //если произошел поворот (сброшен флаг) и значение в памяти 13, то
    turnCommand = random(1, 6);        //берем случайное значение часов 1-6
    turnFlag = 1;                     //защелкиваем флаг вычисления случайных значений до следующего поворота
  }
  currentTime = millis();
  if (currentTime >= (loopTime + turnCommand * 3600000)) {  // 3600000 сравниваем текущий таймер с переменной loopTime + период поворота в часах.
    digitalWrite(turn_pin, !digitalRead(turn_pin));       // включаем/выключаем реле поворота
    loopTime = currentTime;    // в loopTime записываем новое значение
    turnFlag = 0;    //сбрасываем флаг поворота
  }
}

//управляем авариями
void alarm() {
  float tempInk = sensors.getTempCByIndex(0);
  int alarmTemp;
  float setTemp;
  EEPROM_read(5, alarmTemp);
  EEPROM_read_mem(1, &setTemp, sizeof(setTemp));
  EEPROM_read(1, setTemp);
  lcd.setCursor(0, 3);
  lcd.print("A");
  lcd.print(setTemp + alarmTemp, 1);
  if (millis() > 1800000) {
    if (tempInk > (setTemp + alarmTemp) || tempInk < (setTemp - alarmTemp)) {
      beeper(10);
      digitalWrite(alarm_pin, LOW); //если измеренная температура выше заданной на величину аварии
    }
    else digitalWrite(alarm_pin, HIGH); //то включаем аварийный сигнал.
  }
}

void beeper(int duration) {
  tone(beeper_pin, 2000, duration);
}


//управляем вентиляторами
void fan() {
  //float tempInk = sht1x.readTemperatureC();
  int fanTemp;
  EEPROM_read(9, fanTemp);
  lcd.setCursor(6, 3);
  lcd.print("F");
  lcd.print(fanTemp);
  if (temp1Ink > fanTemp) digitalWrite(fan_pin, LOW); //если измеренная температура выше заданной на величину аварии
  else digitalWrite(fan_pin, HIGH); //то включаем аварийный сигнал.

}

// вольтметр
void voltmeter(){   
  float outputValue = 0;     
  outputValue = float(analogRead(voltmeter_pin))/63,9;
  //if(outputValue < 4.5) beeper(50); 
  //Serial.print("Voltage = " );                      
  //Serial.println(outputValue); 
  lcd.setCursor(14, 3);
  lcd.print("V");
  lcd.print(outputValue, 1);
}

// Печать мощности нагрвателя
void outpuPower(){ 
  lcd.setCursor(14, 3);
  lcd.print("W");
  lcd.print(Output, 0);
  lcd.print(" ");  
}

//задержка аварийного сигнала на 30 минут
void alarm_delay(){ 
 extern volatile unsigned long timer0_overflow_count; 
 cli();
 timer0_overflow_count = 0;
 sei();
}

/********************************************
 * Serial Communication functions / helpers
 ********************************************/


union {                // This Data structure lets
  byte asBytes[24];    // us take the byte array
  float asFloat[6];    // sent from processing and
}                      // easily convert it to a
foo;                   // float array



// getting float values from processing into the arduino
// was no small task.  the way this program does it is
// as follows:
//  * a float takes up 4 bytes.  in processing, convert
//    the array of floats we want to send, into an array
//    of bytes.
//  * send the bytes to the arduino
//  * use a data structure known as a union to convert
//    the array of bytes back into an array of floats

//  the bytes coming from the arduino follow the following
//  format:
//  0: 0=Manual, 1=Auto, else = ? error ?
//  1: 0=Direct, 1=Reverse, else = ? error ?
//  2-5: float setpoint
//  6-9: float input
//  10-13: float output
//  14-17: float P_Param
//  18-21: float I_Param
//  22-245: float D_Param

void SerialReceive()
{

  // read the bytes sent from Processing
  int index = 0;
  byte Auto_Man = -1;
  byte Direct_Reverse = -1;
  while (Serial.available() && index < 26)
  {
    if (index == 0) Auto_Man = Serial.read();
    else if (index == 1) Direct_Reverse = Serial.read();
    else foo.asBytes[index - 2] = Serial.read();
    index++;
  }

  // if the information we got was in the correct format,
  // read it into the system
  if (index == 26  && (Auto_Man == 0 || Auto_Man == 1) && (Direct_Reverse == 0 || Direct_Reverse == 1))
  {
    Setpoint = double(foo.asFloat[0]);
    //Input=double(foo.asFloat[1]);       // * the user has the ability to send the
    //   value of "Input"  in most cases (as
    //   in this one) this is not needed.
    if (Auto_Man == 0)                    // * only change the output if we are in
    { //   manual mode.  otherwise we'll get an
      Output = double(foo.asFloat[2]);    //   output blip, then the controller will
    }                                     //   overwrite.

    double p, i, d;                       // * read in and set the controller tunings
    p = double(foo.asFloat[3]);           //
    i = double(foo.asFloat[4]);           //
    d = double(foo.asFloat[5]);           //
    myPID.SetTunings(p, i, d);            //

    if (Auto_Man == 0) myPID.SetMode(MANUAL); // * set the controller mode
    else myPID.SetMode(AUTOMATIC);             //

    if (Direct_Reverse == 0) myPID.SetControllerDirection(DIRECT); // * set the controller Direction
    else myPID.SetControllerDirection(REVERSE);          //
  }
  Serial.flush();                         // * clear any random data from the serial buffer
}

// unlike our tiny microprocessor, the processing ap
// has no problem converting strings into floats, so
// we can just send strings.  much easier than getting
// floats from processing to here no?
void SerialSend()
{
  
  Serial.print("PID ");
  Serial.print(Setpoint);
  Serial.print(" ");
  Serial.print(Input);
  Serial.print(" ");
  Serial.print(Output);
  Serial.print(" ");
  Serial.print(myPID.GetKp());
  Serial.print(" ");
  Serial.print(myPID.GetKi());
  Serial.print(" ");
  Serial.print(myPID.GetKd());
  Serial.print(" ");
  if (myPID.GetMode() == AUTOMATIC) Serial.print("Automatic");
  else Serial.print("Manual");
  Serial.print(" ");
  if (myPID.GetDirection() == DIRECT) Serial.println("Direct");
  else Serial.println("Reverse");
}

 

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

Замена SHT на DHT11 в инкубаторе, помоему не самая лучшая идея. Этот показометр рисует что угодно, кроме действительной влажности. На мой взгляд лучше пожертвовать 15USD и не создавать себе проблем.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

ну или хотя бы DHT22. но лучше конечно хороший датчик

soldat6600
Offline
Зарегистрирован: 14.12.2014

DHT22 у меня тоже есть. А помочь сможете? С кодом просто датчик sht дороговат.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

не я так. чисто поболтать

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

Вряд ли кто за вас будет перерывать 700 строк кода. Скрупулезно перебираете все переменные и функции, смотрите которые работают или зависят от Sensirion.h и переводите их к библиотеке Dht. Основная работа с SHT проводится в функции getSensors(), возможно где то еще. Тупо в лоб переписать переменные вряд ли получится.

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

SHT10 у меня в инкубаторах работают без проблем где то по 2 года (вывод каждые 20 дней), дальше влажность начинает значительно уезжать. DHT и их клоны переживут пару выводов, далее потребуется или замена или каким то образом очищать сам сенсор от налипшей на активном слое пыли+калибровка. Так что взвесьте еще раз целесообразность такого замещения.

soldat6600
Offline
Зарегистрирован: 14.12.2014

спасибо за ваши советы. заказал Sht10 и SHT15