Термостат на нескольких датчиках DS18B20

Forvad
Offline
Зарегистрирован: 09.02.2016

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

Скажите правильно ли я делаю?

Вопрос еще и к тому что временами это вдруг перестает работать. Температура выше порога включения, а реле не встаёт под ток. А флажки  "X" и "Y" на каждом круге оба увеличиваются на 1.



  if (cooler == false) // включение кулера
  {
    if (tmp_bp1 > tmp_max || tmp_bp2 > tmp_max || tmp_dc1 > tmp_max || tmp_dc2 > tmp_max || tmp_r1 > tmp_max || tmp_r2 > tmp_max || tmp_r3 > tmp_max)
    {
     cooler = true;
     digitalWrite(cooler_pin, HIGH);  //включить кулер
     x = x + 1;
    }    
  }

 if (cooler == true) // выключение кулера
  {
   if (tmp_bp1 < tmp_min && tmp_bp2 < tmp_min && tmp_dc1 < tmp_min && tmp_dc2 < tmp_min && tmp_r1 < tmp_min && tmp_r2 < tmp_min && tmp_r3 < tmp_min)
    {
      cooler = false;
      digitalWrite(cooler_pin, LOW);  //выключить кулер
      y = y + 1;
    }  
  }

 

Logik
Offline
Зарегистрирован: 05.08.2014

Все верно, увеличиваются, только не на каждом круге от cooler зависит. И от той мути после if. А изредка и резко уменшатся.  А чего Вы хотели то?

T.Rook
Offline
Зарегистрирован: 05.03.2016

Forvad пишет:

А флажки  "X" и "Y" на каждом круге оба увеличиваются на 1.

если, к примеру,  tmp_min>tmp_max  -  то это  нормально. Но отсюда невидать :(

Forvad
Offline
Зарегистрирован: 09.02.2016

Logik пишет:

Все верно, увеличиваются, только не на каждом круге

 

в том то и дело что на каждом ...  т.е. это когда глючит. А так да ... включилось реле - вырос Х, выключилось - вырос Y. Я их для этого и воткнул - чтобы следить выполнилось условие или нет.  

Logik пишет:
от cooler зависит

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

Logik пишет:
. И от той мути после if.

:) про неё и вопрос ... если хоть одна температура выше верхнего предела - включается кулер. А выключается когда все температуры снижаются за нижний предел.

Logik пишет:
А изредка и резко уменшатся.

эт Вы про температуры  с датчиков?  резко они никуда не скачат, я ж в порту (порте) за ними смотрю

Logik пишет:
А чего Вы хотели то?

эт вопрос риторический? :) хотел бы что б "работало" :)

Forvad
Offline
Зарегистрирован: 09.02.2016

Цитата:

если, к примеру,  tmp_min>tmp_max  -  то это  нормально. Но отсюда невидать :(







float tmp_min = 30.0;
float tmp_max = 33.0;

диапазон конечно маленький ... но это на время отладки, чтобы от тепла рук срабатывало. от комнатных 27град до 33 срабатывания датчик греется секунд 5. температура растет плавно

Опять же - это происходит не всегда и не сразу ... работает - работает вдруг раз и перестало ... вот Этими фражками увидел такое ... почему так происходит я не пойму

и ладно бы клацало реле - ведь попав в первое условие, к Х - оно должно включится,  и тут же выключится раз и Y увеличился. А оно же не клацает

 

 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, для начала хотелось бы увидеть скетч целиком. И почти наверняка придётся посмотреть и на схему.

b707
Offline
Зарегистрирован: 26.05.2017

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

Forvad
Offline
Зарегистрирован: 09.02.2016

ЕвгенийП пишет:

Ну, для начала хотелось бы увидеть скетч целиком. И почти наверняка придётся посмотреть и на схему.

а схема, схема по скетчу. собрана пока на сенсор-шилде.

на А4\А5 экран , на D2 - гирлянда датчиков, на D8 - релюшка





/*
 * блок питания v. 0.1 
 * 
 */
#include <OneWire.h>
#include <DallasTemperature.h>
#include "ASOLED.h"
 
OneWire oneWire(2); // вход датчиков 18b20
DallasTemperature ds(&oneWire);

DeviceAddress ard_bp1 = {0x28, 0xFF, 0xC1, 0x8B, 0x01, 0x17, 0x03, 0x21};
DeviceAddress ard_bp2 = {0x28, 0xFF, 0x23, 0x93, 0x01, 0x17, 0x03, 0x5C};
DeviceAddress ard_dc1 = {0x28, 0xFF, 0x94, 0x99, 0x01, 0x17, 0x03, 0x59};
DeviceAddress ard_dc2 = {0x28, 0xFF, 0xE4, 0x08, 0x02, 0x17, 0x04, 0x3D};
DeviceAddress ard_r1 = {0x28, 0xFF, 0x1D, 0x98, 0x01, 0x17, 0x03, 0xEE};
DeviceAddress ard_r2 = {0x28, 0xFF, 0x52, 0xA4, 0x01, 0x17, 0x05, 0xEF};
DeviceAddress ard_r3 = {0x28, 0xFF, 0xA0, 0xDD, 0x01, 0x17, 0x04, 0xAF};


float tmp_bp1 = 0;
float tmp_bp2 = 0;
float tmp_dc1 = 0;
float tmp_dc2 = 0;
float tmp_r1 = 0;
float tmp_r2 = 0;
float tmp_r3 = 0;

byte buzz_gnd=4; //динамик земля
byte buzz_pin=5; //динамик сигнал

byte cooler_pin = 8; //пин реле включения кулера

unsigned long prevMillis;
unsigned long testStart;

boolean cooler = false; //флаг работы кулера
float tmp_min = 30.0;
float tmp_max = 33.0;


int x = 0;
int y = 0;

void setup() {
  Serial.begin(115200);
  ds.begin();
  
  pinMode(buzz_pin, OUTPUT); //пищалка
  pinMode(buzz_gnd, OUTPUT); //пищалка
  digitalWrite(buzz_gnd, 0);
  
  LD.init();  //иниц OLED диспл
  LD.clearDisplay();

  testStart = millis();  //время начала теста в системе отсчёта ардуины
  prevMillis = millis();  //время первого шага

  pinMode(cooler_pin, OUTPUT);  //пин реле как выход
  digitalWrite(cooler_pin, LOW); //обесточить реле, выключить кулер 
  Serial.println("BP1   BP2   DC1   DC2   R1    R2    R3    Cool  X  Y");
}


void sendData()      // данные в порт
{  
 Serial.print(tmp_bp1, 1);
 Serial.print("  ");
 Serial.print(tmp_bp2, 1);
 Serial.print("  ");
 Serial.print(tmp_dc1, 1);
 Serial.print("  ");
 Serial.print(tmp_dc2, 1);
 Serial.print("  ");
 Serial.print(tmp_r1, 1);
 Serial.print("  ");
 Serial.print(tmp_r2, 1);
 Serial.print("  ");
 Serial.print(tmp_r3, 1);
 Serial.print("  ");
 Serial.print(cooler);
 Serial.print("     ");
 Serial.print(x);
 Serial.print("  ");
 Serial.print(y);
 Serial.print("  ");
 Serial.println(millis());
}

void DispPrint()      //отображения данных на экране
{
 // первая строка
 LD.printString_12x16("");
 LD.printNumber((long)tmp_bp1, 0, 0); // переменная, столбец, строка
 LD.printString_6x8(" ");
 LD.printString_12x16(""); 
 LD.printNumber((long)tmp_bp2); // переменная, столбец, строка
 LD.printString_6x8(" "); 
 LD.printString_12x16("");
 LD.printNumber((long)tmp_dc1); // переменная, столбец, строка
 LD.printString_6x8(" ");
 LD.printString_12x16(""); 
 LD.printNumber((long)tmp_dc2); // переменная, столбец, строка

 // вторая строка
 LD.printString_12x16("");
 LD.printNumber((long)tmp_r1, 0, 2); // переменная, столбец, строка
 LD.printNumber((long)tmp_r2, 45, 2); // переменная, столбец, строка
 LD.printNumber((long)tmp_r3, 90, 2); // переменная, столбец, строка    
}


void loop() {
 
 ds.requestTemperatures(); // считываем температуру с датчиков
 
 tmp_bp1 = ds.getTempC(ard_bp1);
 tmp_bp2 = ds.getTempC(ard_bp2);
 tmp_dc1 = ds.getTempC(ard_dc1);
 tmp_dc2 = ds.getTempC(ard_dc2);
 tmp_r1 = ds.getTempC(ard_r1);
 tmp_r2 = ds.getTempC(ard_r2);
 tmp_r3 = ds.getTempC(ard_r3);
  
 sendData(); // отправка данных
 DispPrint();  

  if (cooler == false) // включение кулера
  {
    if (tmp_bp1 > tmp_max || tmp_bp2 > tmp_max || tmp_dc1 > tmp_max || tmp_dc2 > tmp_max || tmp_r1 > tmp_max || tmp_r2 > tmp_max || tmp_r3 > tmp_max)
    {
     cooler = true;
     digitalWrite(cooler_pin, HIGH);  //включить кулер
     x = x + 1;
    }    
  }

 if (cooler == true) // выключение кулера
  {
   if (tmp_bp1 < tmp_min && tmp_bp2 < tmp_min && tmp_dc1 < tmp_min && tmp_dc2 < tmp_min && tmp_r1 < tmp_min && tmp_r2 < tmp_min && tmp_r3 < tmp_min)
    {
      cooler = false;
      digitalWrite(cooler_pin, LOW);  //выключить кулер
      y = y + 1;
    }  
  }

}

 

b707
Offline
Зарегистрирован: 26.05.2017

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

Forvad
Offline
Зарегистрирован: 09.02.2016

b707 пишет:

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

можно и попробовать .. только я даж не знаю с чего начать :( программер я аховый. Если "if" как то понимаю то - с массивом сложнее. 

А что в том "if" безумного? ну переменных много .. а было бы их две? 

if (tmp_bp1 > 30 || tmp_bp2 > 30)  ... уже имхо совсем не безумно :)

b707
Offline
Зарегистрирован: 26.05.2017

Forvad пишет:

А что в том "if" безумного? ну переменных много .. а было бы их две? 

с массивом будет одна. И что важно - сделаете вы вместо 7 датчиков 77 - а код останется тем же. Попробуйте представить. во что превратится ваш скетч для 77 датчиков :)

Forvad
Offline
Зарегистрирован: 09.02.2016

b707 пишет:

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

да как Вам сказать .. я же шел от малого. Поставил 1 датчик. Ну какой масив на 1 датчик? :)  Покумекал с алгоритмом - вроде с одним работает. Припаял еще датчиков - и добавил их в условие :) 

 

b707
Offline
Зарегистрирован: 26.05.2017

Forvad пишет:

можно и попробовать .. только я даж не знаю с чего начать :( программер я аховый. Если "if" как то понимаю то - с массивом сложнее.

ну как-то так (компилить не пробовал, могут быть ошипки)

#define SENSORS 7
float temp[SENSORS];

for(int i=0;i<SENSORS;i++) {
	if (temp[i] > temp_max) 
     {
     cooler = true;
     digitalWrite(cooler_pin, HIGH);  //включить кулер
     x = x + 1;
     break;
     }    
}

 

Forvad
Offline
Зарегистрирован: 09.02.2016

как то так ...

мне кажется стало "безумнее" ... мне понятнее не стало дак это точно. на вскидку с "if" логика видна сразу. Да и в 4 раза меньше не стало :) с 19 строк выросло до 31

вроде работает .. но надо потестить ... помогло ли




/*
 * блок питания v. 0.1 
 * 
 */
#include <OneWire.h>
#include <DallasTemperature.h>
#include "ASOLED.h"

#define SENSORS 6
 
OneWire oneWire(2); // вход датчиков 18b20
DallasTemperature ds(&oneWire);

DeviceAddress ard_bp1 = {0x28, 0xFF, 0xC1, 0x8B, 0x01, 0x17, 0x03, 0x21};
DeviceAddress ard_bp2 = {0x28, 0xFF, 0x23, 0x93, 0x01, 0x17, 0x03, 0x5C};
DeviceAddress ard_dc1 = {0x28, 0xFF, 0x94, 0x99, 0x01, 0x17, 0x03, 0x59};
DeviceAddress ard_dc2 = {0x28, 0xFF, 0xE4, 0x08, 0x02, 0x17, 0x04, 0x3D};
DeviceAddress ard_r1 = {0x28, 0xFF, 0x1D, 0x98, 0x01, 0x17, 0x03, 0xEE};
DeviceAddress ard_r2 = {0x28, 0xFF, 0x52, 0xA4, 0x01, 0x17, 0x05, 0xEF};
DeviceAddress ard_r3 = {0x28, 0xFF, 0xA0, 0xDD, 0x01, 0x17, 0x04, 0xAF};

float tmp[SENSORS];

byte buzz_gnd=4; //динамик земля
byte buzz_pin=5; //динамик сигнал

byte cooler_pin = 8; //пин реле включения кулера

unsigned long prevMillis;
unsigned long testStart;

boolean cooler = false; //флаг работы кулера
float tmp_min = 30.0;
float tmp_max = 33.0;


int x = 0;
int y = 0;

void setup() {
  Serial.begin(115200);
  ds.begin();
  
  pinMode(buzz_pin, OUTPUT); //пищалка
  pinMode(buzz_gnd, OUTPUT); //пищалка
  digitalWrite(buzz_gnd, 0);
  
  LD.init();  //иниц OLED диспл
  LD.clearDisplay();

  testStart = millis();  //время начала теста в системе отсчёта ардуины
  prevMillis = millis();  //время первого шага

  pinMode(cooler_pin, OUTPUT);  //пин реле как выход
  digitalWrite(cooler_pin, LOW); //обесточить реле, выключить кулер 
  Serial.println("BP1   BP2   DC1   DC2   R1    R2    R3    Cool  X  Y");
}


void sendData()      // данные в порт
{  
 Serial.print(tmp[0], 1);
 Serial.print("  ");
 Serial.print(tmp[1], 1);
 Serial.print("  ");
 Serial.print(tmp[2], 1);
 Serial.print("  ");
 Serial.print(tmp[3], 1);
 Serial.print("  ");
 Serial.print(tmp[4], 1);
 Serial.print("  ");
 Serial.print(tmp[5], 1);
 Serial.print("  ");
 Serial.print(tmp[6], 1);
 Serial.print("  ");
 Serial.print(cooler);
 Serial.print("     ");
 Serial.print(x);
 Serial.print("  ");
 Serial.print(y);
 Serial.print("  ");
 Serial.println(millis());
}

void DispPrint()      //отображения данных на экране
{
 // первая строка
 LD.printString_12x16("");
 LD.printNumber((long)tmp[0], 0, 0); // переменная, столбец, строка
 LD.printString_6x8(" ");
 LD.printString_12x16(""); 
 LD.printNumber((long)tmp[1]); // переменная, столбец, строка
 LD.printString_6x8(" "); 
 LD.printString_12x16("");
 LD.printNumber((long)tmp[2]); // переменная, столбец, строка
 LD.printString_6x8(" ");
 LD.printString_12x16(""); 
 LD.printNumber((long)tmp[3]); // переменная, столбец, строка

 // вторая строка
 LD.printString_12x16("");
 LD.printNumber((long)tmp[4], 0, 2); // переменная, столбец, строка
 LD.printNumber((long)tmp[5], 45, 2); // переменная, столбец, строка
 LD.printNumber((long)tmp[6], 90, 2); // переменная, столбец, строка    
}


void loop() {
 
 ds.requestTemperatures(); // считываем температуру с датчиков
 
 tmp[0] = ds.getTempC(ard_bp1);
 tmp[1] = ds.getTempC(ard_bp2);
 tmp[2] = ds.getTempC(ard_dc1);
 tmp[3] = ds.getTempC(ard_dc2);
 tmp[4] = ds.getTempC(ard_r1);
 tmp[5] = ds.getTempC(ard_r2);
 tmp[6] = ds.getTempC(ard_r3);
  
 sendData(); // отправка данных
 DispPrint();  

  
  if (cooler == false) // включение кулера
  {
    for(int i=0;i<SENSORS;i++) 
     {
      if (tmp[i] > tmp_max) 
       {
        cooler = true;
        digitalWrite(cooler_pin, HIGH);  //включить кулер
        x = x + 1;
        break;
       }    
     }
  }


 if (cooler == true) // выключение кулера
 {
  int z = 0; 
  for(int i=0;i<SENSORS;i++) 
   {
    if (tmp[i] < tmp_min) 
     {
      z = z + 1;
     }    
   }
   if (z == SENSORS)
    {
     cooler = false;
     digitalWrite(cooler_pin, LOW);  //включить кулер
     y = y + 1; 
    }
 
 }
}

 

Logik
Offline
Зарегистрирован: 05.08.2014

вот просто спать не смогу, пока не выясню. А если tmp_bp1 > tmp_max,а в то же время tmp_bp2 < tmp_min то чего бедному кулеру, хоть разорвись? В чем физический смысл одного кулера на много датчиков?

 

b707
Offline
Зарегистрирован: 26.05.2017

Forvad пишет:

как то так ...

мне кажется стало "безумнее" ... мне понятнее не стало дак это точно. на вскидку с "if" логика видна сразу. Да и в 4 раза меньше не стало :) с 19 строк выросло до 31

вроде работает .. но надо потестить ... помогло ли

Ну так надо же везде циклы вставить, а не в одном месте. Считывание температуры - в цикле, вывод в сериал - тоже

b707
Offline
Зарегистрирован: 26.05.2017

Logik пишет:

вот просто спать не смогу, пока не выясню. А если tmp_bp1 > tmp_max,а в то же время tmp_bp2 < tmp_min то чего бедному кулеру, хоть разорвись? В чем физический смысл одного кулера на много датчиков?

напрасно вы, все там нормально с логикой. Если хоть один датчик показывает перегрев - включается охлаждение, которое работает, пока сигналы со всех датчиков не придут в норму. А tmp_min и tmp_max - это просто гистерезис.

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

Forvad
Offline
Зарегистрирован: 09.02.2016

Logik пишет:

вот просто спать не смогу, пока не выясню. А если tmp_bp1 > tmp_max,а в то же время tmp_bp2 < tmp_min то чего бедному кулеру, хоть разорвись? 

включится кулер .. т.к. для его включение достаточно превышение tmp_max ЛЮБОГО из датчиков. для это стоит "или" ... или bp1 или bp2 или  .. и т.д.  А вот выключится он только когда ВСЕ датчики опустятся за tmp_min. Для это используется "и" ...  и bp1 и bp2 и .. тд

Цитата:
В чем физический смысл одного кулера на много датчиков? 

b707 пишет:

Есть несколько приборов, на каждом датчик перегрева. А система кондиционирования - общая.

совершенной верно ...в одном корпусе несколько устройств греющихся независимо друг от друга.  А кулер один на всех :)

SLKH
Offline
Зарегистрирован: 17.08.2015

Forvad пишет:

Logik пишет:

вот просто спать не смогу, пока не выясню. А если tmp_bp1 > tmp_max,а в то же время tmp_bp2 < tmp_min то чего бедному кулеру, хоть разорвись? 

включится кулер .. т.к. для его включение достаточно превышение tmp_max ЛЮБОГО из датчиков. для это стоит "или" ... или bp1 или bp2 или  .. и т.д.  А вот выключится он только когда ВСЕ датчики опустятся за tmp_min. Для это используется "и" ...  и bp1 и bp2 и .. тд

Цитата:
В чем физический смысл одного кулера на много датчиков? 

b707 пишет:

Есть несколько приборов, на каждом датчик перегрева. А система кондиционирования - общая.

совершенной верно ...в одном корпусе несколько устройств греющихся независимо друг от друга.  А кулер один на всех :)

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