Использование логической функции "И", почему не работает.

AndryGladky
Offline
Зарегистрирован: 09.10.2014

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

#include <EEPROM.h> 
#include <OneWire.h> 
#include <LiquidCrystal.h>
#include <DallasTemperature.h>
#define OUT1 2 // выходы для реле 
#define OUT2 3
#define ONE_WIRE_BUS_1 A1
#define ONE_WIRE_BUS_2 A2
#define ONE_WIRE_BUS_3 A3

OneWire oneWire_1(ONE_WIRE_BUS_1);
OneWire oneWire_2(ONE_WIRE_BUS_2);
OneWire oneWire_3(ONE_WIRE_BUS_3);

DallasTemperature sensor_1(&oneWire_1);
DallasTemperature sensor_2(&oneWire_2);
DallasTemperature sensor_3(&oneWire_3);

byte tempOUT1, tempOUT2, tempOUT3, tempOUT4;
byte OUT3;
byte tempOUT5 = 29;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); 
byte gradus[8] = {   
    0b00110,   
    0b01001,   
    0b01001,   
    0b00110,   
    0b00000,   
    0b00000,   
    0b00000,   
    0b00000 };
byte bykvaPE [8] = {
    0b00000, 	
    0b00000, 	
    0b11111, 	
    0b10001, 	
    0b10001, 	
    0b10001, 	
    0b10001,
    0b00000
};
byte bykvaL[8] = { 	
    0b00000, 	
    0b00000, 	
    0b01111, 	
    0b00101, 	
    0b00101, 	
    0b10101, 	
    0b01001,
    0b00000
    };
byte bykvaU[8] = { 	
    0b00000, 	
    0b00000, 	
    0b10001, 	
    0b10001, 	
    0b11001, 	
    0b10101, 	
    0b11001,
    0b00000
    };
byte bykvaii[8] = {
    0b00000, 	
    0b01010, 	
    0b00100, 	
    0b10001, 	
    0b10011, 	
    0b10101, 	
    0b11001,
    0b00000
    };

void outOff(){ // выключает выходы
    digitalWrite(OUT1, HIGH); // выключаем реле   
    digitalWrite(OUT2, HIGH);
}

void erorr(){ // останавливает работу программы и сигнализирует ошибку   
  outOff(); // выключаем выходы
  lcd.clear();   
  lcd.print("sensor error");    
   while(1){ // крутим бесконечный цикл
       analogWrite(10, 0);
       delay(500);       
       analogWrite(10, 255);       
       delay(500); 
   }
}
    byte key(){ 
    //// для кнопок ЛСДшилда   
    int val = analogRead(0);     
    if (val < 50) return 5;     
    else if (val < 150) return 3;     
    else if (val < 350) return 4;     
    else if (val < 500) return 2;     
    else if (val < 800) return 1;     
    else return 0; 
    } ////
    
void setMenu(){ // установка температуры   
    byte pos;   
    digitalWrite(OUT1, HIGH); // выключаем реле   
    digitalWrite(OUT2, HIGH);
    
    lcd.clear();   
    lcd.setCursor(0, 0); // что нужно отрисовать один раз
    lcd.print("1B:");   
    lcd.setCursor(0, 1);   
    lcd.print("2B:");
    lcd.setCursor(8, 0);   
    lcd.print("1H:");
    lcd.setCursor(8, 1);   
    lcd.print("2H:");   
    lcd.blink();
    
  while(1){ // крутим бесконечный цикл     
    byte KEY = key(); // читаем состояние кнопок
    
    lcd.setCursor(3, 0); // выводим на экран
    lcd.print(tempOUT1);     
    lcd.write(1);     
    lcd.print("C ");     
    lcd.setCursor(3, 1);     
    lcd.print(tempOUT2);     
    lcd.write(1);     
    lcd.print("C ");
    lcd.setCursor(11, 0);     
    lcd.print(tempOUT3);     
    lcd.write(1);     
    lcd.print("C ");
    lcd.setCursor(11, 1);     
    lcd.print(tempOUT4);     
    lcd.write(1);     
    lcd.print("C ");
         
    ////// обработка кнопок

 if (pos == 0){ // если в первой позиции       
    lcd.setCursor(3, 0); // устанавливаем курсор       
    if (KEY == 2) { // если нажата кнопка         
    tempOUT1--;   // изменяем значение         
    EEPROM.write(1, tempOUT1); // сохраняем в еепром       
    }       
    else if (KEY == 5){         
    tempOUT1++;         
    EEPROM.write(1, tempOUT1);       
    }         
    }     
 if (pos == 1){       
    lcd.setCursor(3, 1);       
    if (KEY == 2) {         
    tempOUT2--;         
    EEPROM.write(2, tempOUT2);       
    }       
    else if (KEY == 5){         
    tempOUT2++;         
    EEPROM.write(2, tempOUT2);       
    }         
    }
 if (pos == 2){ // если в третей позиции       
    lcd.setCursor(11, 0); // устанавливаем курсор       
    if (KEY == 2) { // если нажата кнопка         
    tempOUT1--;   // изменяем значение         
    EEPROM.write(3, tempOUT1); // сохраняем в еепром       
    }       
    else if (KEY == 5){         
    tempOUT3++;         
    EEPROM.write(3, tempOUT3);       
    }         
    }         
 if (pos == 3){ // если в четвертой позиции       
    lcd.setCursor(11, 1); // устанавливаем курсор       
    if (KEY == 2) { // если нажата кнопка         
    tempOUT4--;   // изменяем значение         
    EEPROM.write(1, tempOUT4); // сохраняем в еепром       
    }       
    else if (KEY == 5){         
    tempOUT4++;         
    EEPROM.write(4, tempOUT4);       
    }         
    }             
  if (KEY == 3) pos--; // крутим позицию     
  else if (KEY == 4) pos++;     
  if (pos > 3) pos = 0;      
  delay(200);   
    } 
 }

void setup() {
    lcd.createChar(1, gradus);
    lcd.createChar(2, bykvaPE);
    lcd.createChar(3, bykvaL);
    lcd.createChar(4, bykvaU);
    lcd.createChar(5, bykvaii);
    lcd.begin(16, 2);
    lcd.print("Te");
    lcd.write (2);
    lcd.write (3);
    lcd.write (4);
    lcd.write (5);
    lcd.print(" ");
    lcd.write (2);
    lcd.print("o");
    lcd.write (3);
    lcd.setCursor(0, 1);
    lcd.print("AndryGladky 2018");
    
    delay(10000);
    pinMode(OUT1, OUTPUT);   
    pinMode(OUT2, OUTPUT);      
    tempOUT1 = EEPROM.read(1); // читаем настройки
    tempOUT2 = EEPROM.read(2); // из еепром 
    tempOUT3 = EEPROM.read(3);
    tempOUT4 = EEPROM.read(4);
} 
void loop() {
    sensor_1.requestTemperatures();// читаем температуру 1 датчик
    sensor_2.requestTemperatures();// читаем температуру 2 датчик
    sensor_3.requestTemperatures();// читаем температуру 2 датчик
    
    if (key() == 1) setMenu(); // если нажата селект, уходим в меню
    else if (key() == 4) analogWrite(10, 0); // если вниз, глушим подсветку
    else if (key() == 3) digitalWrite(10, HIGH);
    
    float temperature1 = sensor_1.getTempCByIndex(0); 
    float temperature2 = sensor_2.getTempCByIndex(0);
    float temperature3 = sensor_3.getTempCByIndex(0);
    
    if (temperature1 < -125) erorr ();
    if (temperature1 < -125) erorr ();
    if (temperature1 < -125) erorr ();
    
    
    // сверяем температуру и управляем выходами
    if (temperature1 < tempOUT3 && temperature3 > tempOUT5) digitalWrite(OUT1, LOW); 
    else if (temperature1 > tempOUT1) digitalWrite(OUT1, HIGH);
    
    if (temperature2 < tempOUT4) digitalWrite(OUT2, LOW);   
    else if (temperature2 > tempOUT2) digitalWrite(OUT2, HIGH);
    
    if (temperature3 > tempOUT5) OUT3 = LOW;
      else OUT3 = HIGH;
          
    lcd.setCursor(0, 0); /// вывод инфы на экран   
    lcd.print(temperature3, 1);   
    lcd.write(1); 
       // показываем состояние выхода
       if (digitalRead(OUT1)) lcd.print(" OFF");      
       else lcd.print(" ON ");   
    lcd.setCursor(0, 1);    
       if (OUT3) lcd.print(" OFF");     
       else lcd.print(" ON ");    
       if (digitalRead(OUT2)) lcd.print(" OFF");     
       else lcd.print("  ON ");
    
    lcd.setCursor(9, 0); // показываем температуру с датчика
    lcd.print("|");   
    lcd.print(temperature1, 1);   
    lcd.write(1);   
    lcd.print("C");   
    lcd.setCursor(9, 1);   
    lcd.print("|");
    lcd.print(temperature2, 1);
    lcd.write(1);   
    lcd.print("C");
}

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Словами Вы пишете "больше", а в сравнении фигурирует "<".

 

PS Лично я всегда забываю приоритет операций, поэтому везде ставлю скобки.

sva_khv
Offline
Зарегистрирован: 19.12.2016

Вы сраниваете переменную типа byte c переменной float. Возможно проблема в этом. У меня что такое было. Привел оба чила к  int  и потом сравнил. Все заработало.

AndryGladky
Offline
Зарегистрирован: 09.10.2014

Попробовал две переменные написать float, два сравнения тоже написал в скобках.

b707
Онлайн
Зарегистрирован: 26.05.2017

AndryGladky пишет:

Попробовал две переменные написать float, два сравнения тоже написал в скобках.

И?

AndryGladky
Offline
Зарегистрирован: 09.10.2014

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

MacSim
Offline
Зарегистрирован: 28.11.2012

 if ((temperature1 < tempOUT3) && (temperature3 > tempOUT5)){ digitalWrite(OUT1, LOW);}

 if (temperature1 > tempOUT1) {digitalWrite(OUT1, HIGH);}

 

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

 

b707
Онлайн
Зарегистрирован: 26.05.2017

AndryGladky - во-первых, как вам уже сказали, приведите все переменные temperature1, 2 и 3 и все свои tempOUT к одному общему подходящему типу. Я сильно сомневаюсь, что тип byte тут подходит - надо либо float для работы плавающей точкой, либо, к примеру домножить все температуры на 10 или 100, чтобы работать с целыми - то есть 27.4 С это будет значение 274 (тип int)

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

AndryGladky
Offline
Зарегистрирован: 09.10.2014

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

AndryGladky
Offline
Зарегистрирован: 09.10.2014
Написал вот так  работу термостата, пока не прогреется подача на отопление - третья температура, то реле выключено и остальные условия не выполняются.
// сверяем температуру и управляем выходами
    if (temperature3 < tempOUT5) //если температура подачи(датчик3) ниже заданого порога выключаем реле
   {
    digitalWrite(OUT1, HIGH); 
    digitalWrite(OUT2, HIGH);
    OUT3 = HIGH; //показываем что отключеный вход по 3 датчику
   }
   else { //если температура подачи выше порога проверяем остальные условия
    OUT3 = LOW; //показываем что включено по 3 датчику
    if (temperature1 < tempOUT3) {digitalWrite(OUT1, LOW);} //если температура ниже порога 1Н включаем
    else if (temperature1 > tempOUT1) {digitalWrite(OUT1, HIGH);} //если температура выше порога 1В выключаем
      
    if (temperature2 < tempOUT4) digitalWrite(OUT2, LOW); //если температура ниже порога 2Н включаем
    else if (temperature2 > tempOUT2) digitalWrite(OUT2, HIGH); //если температура выше порога 2В выключаем
   }

 

AndryGladky
Offline
Зарегистрирован: 09.10.2014

 Сброшу весь код может кому пригодится.

#include <EEPROM.h> 
#include <OneWire.h> 
#include <LiquidCrystal.h>
#include <DallasTemperature.h>
#define OUT1 2 // выходы для реле 
#define OUT2 3
#define ONE_WIRE_BUS_1 A1
#define ONE_WIRE_BUS_2 A2
#define ONE_WIRE_BUS_3 A3

OneWire oneWire_1(ONE_WIRE_BUS_1);
OneWire oneWire_2(ONE_WIRE_BUS_2);
OneWire oneWire_3(ONE_WIRE_BUS_3);

DallasTemperature sensor_1(&oneWire_1);
DallasTemperature sensor_2(&oneWire_2);
DallasTemperature sensor_3(&oneWire_3);

int tempOUT1, tempOUT2, tempOUT3, tempOUT4;
int tempOUT5 = 28;
int OUT3;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); 
byte gradus[8] = {   
    0b00110,   
    0b01001,   
    0b01001,   
    0b00110,   
    0b00000,   
    0b00000,   
    0b00000,   
    0b00000 };
byte bykvaPE [8] = {
    0b00000, 	
    0b00000, 	
    0b11111, 	
    0b10001, 	
    0b10001, 	
    0b10001, 	
    0b10001,
    0b00000
};
byte bykvaL[8] = { 	
    0b00000, 	
    0b00000, 	
    0b01111, 	
    0b00101, 	
    0b00101, 	
    0b10101, 	
    0b01001,
    0b00000
    };
byte bykvaU[8] = { 	
    0b00000, 	
    0b00000, 	
    0b10001, 	
    0b10001, 	
    0b11001, 	
    0b10101, 	
    0b11001,
    0b00000
    };
byte bykvaii[8] = {
    0b00000, 	
    0b01010, 	
    0b00100, 	
    0b10001, 	
    0b10011, 	
    0b10101, 	
    0b11001,
    0b00000
    };

void outOff(){ // выключает выходы
    digitalWrite(OUT1, HIGH); // выключаем реле   
    digitalWrite(OUT2, HIGH);
}

void erorr(){ // останавливает работу программы и сигнализирует ошибку   
  outOff(); // выключаем выходы
  lcd.clear();   
  lcd.print("sensor error");    
   while(1){ // крутим бесконечный цикл
       analogWrite(10, 0);
       delay(500);       
       analogWrite(10, 255);       
       delay(500); 
   }
}
    byte key(){ 
    //// для кнопок ЛСДшилда   
    int val = analogRead(0);     
    if (val < 50) return 5;     
    else if (val < 150) return 3;     
    else if (val < 350) return 4;     
    else if (val < 500) return 2;     
    else if (val < 800) return 1;     
    else return 0; 
    } ////
    
void setMenu(){ // установка температуры   
    byte pos;   
    digitalWrite(OUT1, HIGH); // выключаем реле   
    digitalWrite(OUT2, HIGH);
    
    lcd.clear();   
    lcd.setCursor(0, 0); // что нужно отрисовать один раз
    lcd.print("1B:");   
    lcd.setCursor(0, 1);   
    lcd.print("2B:");
    lcd.setCursor(8, 0);   
    lcd.print("1H:");
    lcd.setCursor(8, 1);   
    lcd.print("2H:");   
    lcd.blink();
    
  while(1){ // крутим бесконечный цикл     
    byte KEY = key(); // читаем состояние кнопок
    
    lcd.setCursor(3, 0); // выводим на экран
    lcd.print(tempOUT1);     
    lcd.write(1);     
    lcd.print("C ");     
    lcd.setCursor(3, 1);     
    lcd.print(tempOUT2);     
    lcd.write(1);     
    lcd.print("C ");
    lcd.setCursor(11, 0);     
    lcd.print(tempOUT3);     
    lcd.write(1);     
    lcd.print("C ");
    lcd.setCursor(11, 1);     
    lcd.print(tempOUT4);     
    lcd.write(1);     
    lcd.print("C ");
         
    ////// обработка кнопок

 if (pos == 0){ // если в первой позиции       
    lcd.setCursor(3, 0); // устанавливаем курсор       
    if (KEY == 2) { // если нажата кнопка         
    tempOUT1--;   // изменяем значение         
    EEPROM.write(1, tempOUT1); // сохраняем в еепром       
    }       
    else if (KEY == 5){         
    tempOUT1++;         
    EEPROM.write(1, tempOUT1);       
    }         
    }     
 if (pos == 1){       
    lcd.setCursor(3, 1);       
    if (KEY == 2) {         
    tempOUT2--;         
    EEPROM.write(2, tempOUT2);       
    }       
    else if (KEY == 5){         
    tempOUT2++;         
    EEPROM.write(2, tempOUT2);       
    }         
    }
 if (pos == 2){ // если в третей позиции       
    lcd.setCursor(11, 0); // устанавливаем курсор       
    if (KEY == 2) { // если нажата кнопка         
    tempOUT1--;   // изменяем значение         
    EEPROM.write(3, tempOUT1); // сохраняем в еепром       
    }       
    else if (KEY == 5){         
    tempOUT3++;         
    EEPROM.write(3, tempOUT3);       
    }         
    }         
 if (pos == 3){ // если в четвертой позиции       
    lcd.setCursor(11, 1); // устанавливаем курсор       
    if (KEY == 2) { // если нажата кнопка         
    tempOUT4--;   // изменяем значение         
    EEPROM.write(1, tempOUT4); // сохраняем в еепром       
    }       
    else if (KEY == 5){         
    tempOUT4++;         
    EEPROM.write(4, tempOUT4);       
    }         
    }             
  if (KEY == 3) pos--; // крутим позицию     
  else if (KEY == 4) pos++;     
  if (pos > 3) pos = 0;      
  delay(200);   
    } 
 }

void setup() {
    lcd.createChar(1, gradus);
    lcd.createChar(2, bykvaPE);
    lcd.createChar(3, bykvaL);
    lcd.createChar(4, bykvaU);
    lcd.createChar(5, bykvaii);
    lcd.begin(16, 2);
    lcd.print("Te");
    lcd.write (2);
    lcd.write (3);
    lcd.write (4);
    lcd.write (5);
    lcd.print(" ");
    lcd.write (2);
    lcd.print("o");
    lcd.write (3);
    lcd.setCursor(0, 1);
    lcd.print("AndryGladky 2018");
    
    delay(10000);
    pinMode(OUT1, OUTPUT);   
    pinMode(OUT2, OUTPUT);      
    tempOUT1 = EEPROM.read(1); // читаем настройки
    tempOUT2 = EEPROM.read(2); // из еепром 
    tempOUT3 = EEPROM.read(3);
    tempOUT4 = EEPROM.read(4);
        } 
void loop() {
    sensor_1.requestTemperatures();// читаем температуру 1 датчик
    sensor_2.requestTemperatures();// читаем температуру 2 датчик
    sensor_3.requestTemperatures();// читаем температуру 2 датчик
    
    if (key() == 1) setMenu(); // если нажата селект, уходим в меню
    else if (key() == 4) analogWrite(10, 0); // если вниз, глушим подсветку
    else if (key() == 3) digitalWrite(10, HIGH);
    
    
    float temperature1 = sensor_1.getTempCByIndex(0); //считывание температуры 1 датчика
    float temperature2 = sensor_2.getTempCByIndex(0); //считывание температуры 2 датчика
    float temperature3 = sensor_3.getTempCByIndex(0); //считывание температуры 3 датчика
    
    if (temperature1 < -125) erorr (); //если нет датчика ошибка
    if (temperature2 < -125) erorr (); //если нет датчика ошибка
    if (temperature3 < -125) erorr (); //если нет датчика ошибка
       
    // сверяем температуру и управляем выходами
    if (temperature3 < tempOUT5) //если температура подачи(датчик3) ниже заданого порога выключаем реле
   {
    digitalWrite(OUT1, HIGH); 
    digitalWrite(OUT2, HIGH);
    OUT3 = HIGH; //показываем что отключеный вход по 3 датчику
   }
   else { //если температура подачи выше порога проверяем остальные условия
    OUT3 = LOW; //показываем что включено по 3 датчику
    if (temperature1 < tempOUT3) {digitalWrite(OUT1, LOW);} //если температура ниже порога 1Н включаем
    else if (temperature1 > tempOUT1) {digitalWrite(OUT1, HIGH);} //если температура выше порога 1В выключаем
      
    if (temperature2 < tempOUT4) digitalWrite(OUT2, LOW); //если температура ниже порога 2Н включаем
    else if (temperature2 > tempOUT2) digitalWrite(OUT2, HIGH); //если температура выше порога 2В выключаем
   }
              
    lcd.setCursor(0, 0); /// вывод инфы на экран   
    lcd.print(temperature3, 1);   
    lcd.write(1); //выводим знак градуса
  // показываем состояние выхода
       if (digitalRead(OUT1)) lcd.print(" OFF");      
       else lcd.print(" ON ");   
    lcd.setCursor(0, 1);  // устанавливаем курсор  
       if (OUT3) lcd.print(" OFF");     
       else lcd.print(" ON ");    
       if (digitalRead(OUT2)) lcd.print("  OFF");     
       else lcd.print("  ON ");
       
    lcd.setCursor(9, 0); // устанавливаем курсор
    lcd.print("|"); //выводим горизонтальную палочку
    lcd.print(temperature1, 1); // показываем температуру с датчика 1
    lcd.write(1);  //выводим знак градуса 
    lcd.print("C");  //выводим С 
    lcd.setCursor(9, 1); // устанавливаем курсор
    lcd.print("|"); //выводим горизонтальную палочку
    lcd.print(temperature2, 1); // показываем температуру с датчика 2
    lcd.write(1); //выводим знак градуса
    lcd.print("C"); //выводим С
}

 

kalapanga
Offline
Зарегистрирован: 23.10.2016

AndryGladky,  что, меню "безвыходное" или я что-то проглядел? Сделать кнопку "выход", заодно по ней и записывать установленные значения в еепром, а не по каждому тыку в кнопки плюс/минус.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

kalapanga, так паршиво спроектирована программа. Вот косяки ТС и проникли в программу.

AndryGladky
Offline
Зарегистрирован: 09.10.2014

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

b707
Онлайн
Зарегистрирован: 26.05.2017

AndryGladky пишет:

при достижении температуры теплого пола установленного верхнего порога допустим 30 градусов при изменении температуры 29.9 - 30 щелкает реле туда сюда включая выключая насос,

Это называется гистерезис.

Чтобы реле не щелкало в районе 30 градусов - нужно два условия. Одно для выключенного насоса - он не должен включатся, пока температура выше нижнего предела. Другое условие для включенного насоса - он не должен выключатся, пока температура не достигла верхнего предела.

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

AndryGladky пишет:

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

Цикл http://arduino.ru/Reference/While . В качестве условия используете булев флаг, который изменяется внутри цикла по требуемому условию или таймауту.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

AndryGladky пишет:
Хочу сделать выход с меню но не знаю как реализовать, подскажите или дайте ссылку где почитать. Буду рад любым советам.
Не возможно сделать из сруба пятистенка эмпайр стейт билдинг. И даже в хрущевку не выйдет. Опять же есть меню и есть оперативное управление. Если первое позволять задавать различные переменные , то второе это отслеживание текущих показаний и подача команд. Это различные системы . Выход из меню означает вход в оперативное управление и наоборот. Но так как и та и та система пользуется одним и тем же экраном и теми же кнопками, то экран и кнопки выделяют в отдельную независимую систему. У Вас все объеденено в кучу. То есть по факту у программы нет возможности дальнешего усовершенствования, то есть смерть программы.

b707
Онлайн
Зарегистрирован: 26.05.2017

qwone - как Вы изменились :) Полтора года назаД. когда я пришел на форум - вы каждому новичку тут же выдавали готовый код. Может не очень понятный, закрученный на классах - но работающий. Теперь - только порцию трепа...  :)

Не принимайте к сердцу - шутка.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

b707 пишет:
qwone - как Вы изменились :)
  Вы думаете , что я к примеру выложу готовый код к этой теме, то ТС поймет. Скажет что не рабочую хрень выложил .  То что я ранее выкладывал, требовало минимальной базы. А здесь уровень для решения задачи нужен повыше, а и времени затратить побольше. И разумеется у меня тоже уровень маловат. При серьезных проектах мне надо прыгать и прыгать и все равно не зацеплюсь. А то что говорил выше это не треп.

AndryGladky
Offline
Зарегистрирован: 09.10.2014

Да на счёт меню спасибо я понял, я много посмотрел примеров то там меню написано отдельно программа отдельно, но ладно для этого проекта мне и так сгодится. А на счёт цыкла while он проверяет значение пока не выполнится условие, а если температура прыгает 29.9 - 30 раз в пол секунды потому что бетонный пол не может резко нагрется, он будет работать етот цикл как триггер при одноразовом повышении до 30 градусов просто выключит насос, хоть и температура упадет на 29,9. 

b707
Онлайн
Зарегистрирован: 26.05.2017

AndryGladky пишет:

А на счёт цыкла while он проверяет значение пока не выполнится условие, а если температура прыгает 29.9 - 30 раз в пол секунды потому что бетонный пол не может резко нагрется, он будет работать етот цикл как триггер при одноразовом повышении до 30 градусов просто выключит насос, хоть и температура упадет на 29,9. 

сами же пишете, что реле щелкает туда-сюда - значит ваш "триггер" нифига не работает. Вы бы не спорили, а слушали советы

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

Когда писал про While, вообще то имел в виду меню. В гистерезисе он и нах не нужен.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

AndryGladky пишет:
А на счёт цыкла while он проверяет значение пока не выполнится условие, а если температура прыгает 29.9 - 30 раз в пол секунды потому что бетонный пол не может резко нагрется, он будет работать етот цикл как триггер при одноразовом повышении до 30 градусов просто выключит насос, хоть и температура упадет на 29,9.
Ну вот опять. Есть такая программистакая штука как цифровой автомат.  У вас ЦА на два состояния ВКЛ насос/ ВЫКЛ насос. А дальше надо прописать состояния перехода. Будет это просто температура разово выше/ ниже порога. Или же эта температура будет выше и дольше к примеру с 1минуту. Вот организуете и получите.

b707, вот вам ЕвгенийП целую тему консультацию по ЦА выделил. Так что в этой теме должны уже рулить. Так что объясните ТС, может тогда и сами поймете.

b707
Онлайн
Зарегистрирован: 26.05.2017

qwone пишет:

Есть такая программистакая штука как цифровой автомат.  У вас ЦА на два состояния ВКЛ насос/ ВЫКЛ насос. А дальше надо прописать состояния перехода.

b707, вот вам ЕвгенийП целую тему консультацию по ЦА выделил. Так что в этой теме должны уже рулить. Так что объясните ТС, может тогда и сами поймете.

я уже ТС все обьяснил

b707 пишет:

Чтобы реле не щелкало в районе 30 градусов - нужно два условия. Одно для выключенного насоса - он не должен включатся, пока температура выше нижнего предела. Другое условие для включенного насоса - он не должен выключатся, пока температура не достигла верхнего предела.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вот это простой автомат, но выраженый в коде

/**/
/* Допустим это датчик температуры 0 ниже порога/1 выше порога*/
const byte tempPin = 2;
const byte pumpPin = 13; /*это у нас насос*/
/*а это у нас автомат с двумя состояниями*/
enum state_t {PumpOFF = 0, PumpON } state;
/*переключающая функция автомата*/
void stand(state_t s) {
  state = s;
  switch (state) {
    case PumpOFF :
      digitalWrite(pumpPin, LOW);
      break;
    case PumpON :
      digitalWrite(pumpPin, HIGH);
      break;
  }
}
//-------------------------------------------------------
void setup() {
  pinMode(tempPin, INPUT);
  pinMode(pumpPin, OUTPUT);
  stand(PumpOFF);
}
void loop() {
  bool temp = digitalRead(tempPin);
  /*если насос выключен и стало холодно то включить насос*/
  if (state == PumpOFF && temp == LOW)stand(PumpON);
  /*если насос включен и стало жарко то выключить насос*/
  if (state == PumpON && temp == HIGH)stand(PumpOFF);
}

Плюс всего этого в том что это можно по размому модернизировать.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Попробуем переписать скетч который выше

/**/
/* Допустим это датчик температуры 0 ниже порога/1 выше порога*/
const byte tempPin = 2;
const byte pumpPin = 13; /*это у нас насос*/
/*а это у нас автомат с двумя состояниями*/
enum state_t {PumpOFF = 0, PumpON } state;
/*переключающая функция автомата*/
void stand(state_t s) {
  state = s;
  switch (state) {
    case PumpOFF :
      digitalWrite(pumpPin, LOW);
      break;
    case PumpON :
      digitalWrite(pumpPin, HIGH);
      break;
  }
}
//-------------------------------------------------------
void setup() {
  pinMode(tempPin, INPUT);
  pinMode(pumpPin, OUTPUT);
  stand(PumpOFF);
}
void loop() {
  bool temp = digitalRead(tempPin);
  switch (state) {
    case PumpOFF :/* состояние насос выключен*/
      if (temp == LOW)stand(PumpON);/*стало холодно то включить насос*/
      break;
    case PumpON : /* состояние насос включен*/
      if (temp == HIGH)stand(PumpOFF);/*жарко то выключить насос*/
      break;
  }
}

А теперь к нему добавим условие что переключаться должно если температура держится к примеру 2 секунды.

/**/
/* Допустим это датчик температуры 0 ниже порога/1 выше порога*/
const byte tempPin = 2;
const byte pumpPin = 13; /*это у нас насос*/
/*а это у нас автомат с двумя состояниями*/
enum state_t {PumpOFF = 0, PumpON } state;
unsigned long past;
const unsigned long time2sec = 2000; /*время 2 секунды*/
/*переключающая функция автомата*/
void stand(state_t s) {
  state = s;
  switch (state) {
    case PumpOFF :
      digitalWrite(pumpPin, LOW);
      break;
    case PumpON :
      digitalWrite(pumpPin, HIGH);
      break;
  }
}
//-------------------------------------------------------
void setup() {
  pinMode(tempPin, INPUT);
  pinMode(pumpPin, OUTPUT);
  stand(PumpOFF);
}
void loop() {
  bool temp = digitalRead(tempPin);
  switch (state) {
    case PumpOFF :/* состояние насос выключен*/
      if (temp == HIGH) past = millis();/*подтормаживаем таймер*/
      else if (millis() - past >= time2sec)stand(PumpON); /*стало холодно 2 секунды то включить насос*/
      break;
    case PumpON : /* состояние насос включен*/
      if (temp == LOW) past = millis();/*подтормаживаем таймер*/
      else if (millis() - past >= time2sec)stand(PumpOFF);/*стало жарко 2 секунды то выключить насос*/
      break;
  }
}

 

AndryGladky
Offline
Зарегистрирован: 09.10.2014

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

AndryGladky
Offline
Зарегистрирован: 09.10.2014

Здравствуйте, изучил много прочитал статей про использование цифрового автомата переписал код под свою задачу но, почему то не работает, снова щелкает реле, не могу понять почему так происходит, вроде написал все правильно, но а почему то не работает. Может где ошибку какую допустил, не могу понять. Подскажите или ткните где не правильно. Где использовал функцию автомата, выделил строки.

#include <LiquidCrystal.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <EEPROM.h>
// выходы для реле
byte OUT1 = 2;
byte OUT2 = 3;
#define ONE_WIRE_BUS_1 A1
#define ONE_WIRE_BUS_2 A2
#define ONE_WIRE_BUS_3 A3

OneWire oneWire_1(ONE_WIRE_BUS_1);
OneWire oneWire_2(ONE_WIRE_BUS_2);
OneWire oneWire_3(ONE_WIRE_BUS_3);

DallasTemperature sensor_1(&oneWire_1);
DallasTemperature sensor_2(&oneWire_2);
DallasTemperature sensor_3(&oneWire_3);

int tempOUT1, tempOUT2, tempOUT3, tempOUT4;
int tempOUT5 = 30;
int OUT3;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
byte gradus[8] = {
    0b00110,
    0b01001,
    0b01001,
    0b00110,
    0b00000,
    0b00000,
    0b00000,
    0b00000 };
byte bykvaPE [8] = {
    0b00000,
    0b00000,
    0b11111,
    0b10001,
    0b10001,
    0b10001,
    0b10001,
    0b00000
};
byte bykvaL[8] = {
    0b00000,
    0b00000,
    0b01111,
    0b00101,
    0b00101,
    0b10101,
    0b01001,
    0b00000
    };
byte bykvaU[8] = {
    0b00000,
    0b00000,
    0b10001,
    0b10001,
    0b11001,
    0b10101,
    0b11001,
    0b00000
    };
byte bykvaii[8] = {
    0b00000,
    0b01010,
    0b00100,
    0b10001,
    0b10011,
    0b10101,
    0b11001,
    0b00000
    };

enum state_t {PumpOFF = 0, PumpON} state;
unsigned long past;
const unsigned long time2sec = 2000; /*время 2 секунды*/
/*переключающая функция автомата*/
void stand (state_t s) {
  state = s;
    switch (state) {
    case PumpOFF :
      digitalWrite(OUT2, LOW);
      break;
    case PumpON :
      digitalWrite(OUT2, HIGH);
      break;
  }
}
void outOff(){ // выключает выходы
    digitalWrite(OUT1, HIGH); // выключаем реле
    digitalWrite(OUT2, HIGH);
}

void erorr(){ // останавливает работу программы и сигнализирует ошибку
  outOff();// выключаем выходы
  lcd.clear();
  lcd.print("sensor error");
   while(1){ // крутим бесконечный цикл
       analogWrite(10, 0);
       delay(500);
       analogWrite(10, 255);
       delay(500);
   }
}
    byte key(){
    //// для кнопок ЛСДшилда
    int val = analogRead(0);
    if (val < 50) return 5;
    else if (val < 150) return 3;
    else if (val < 350) return 4;
    else if (val < 500) return 2;
    else if (val < 800) return 1;
    else return 0;
    } ////

void setMenu(){ // установка температуры
    byte pos;
    digitalWrite(OUT1, HIGH); // выключаем реле
    digitalWrite(OUT2, HIGH);

    lcd.clear();
    lcd.setCursor(0, 0); // что нужно отрисовать один раз
    lcd.print("1B:");
    lcd.setCursor(0, 1);
    lcd.print("2B:");
    lcd.setCursor(8, 0);
    lcd.print("1H:");
    lcd.setCursor(8, 1);
    lcd.print("2H:");
    lcd.blink();

    while(1){ // крутим бесконечный цикл
    byte KEY = key(); // читаем состояние кнопок

    lcd.setCursor(3, 0); // выводим на экран
    lcd.print(tempOUT1);
    lcd.write(1);
    lcd.print("C ");
    lcd.setCursor(3, 1);
    lcd.print(tempOUT2);
    lcd.write(1);
    lcd.print("C ");
    lcd.setCursor(11, 0);
    lcd.print(tempOUT3);
    lcd.write(1);
    lcd.print("C ");
    lcd.setCursor(11, 1);
    lcd.print(tempOUT4);
    lcd.write(1);
    lcd.print("C ");

    ////// обработка кнопок

 if (pos == 0){ // если в первой позиции
    lcd.setCursor(3, 0); // устанавливаем курсор
    if (KEY == 2) { // если нажата кнопка
    tempOUT1--; // изменяем значение
    EEPROM.write(1, tempOUT1); // сохраняем в еепром
    }
    else if (KEY == 5){
    tempOUT1++;
    EEPROM.write(1, tempOUT1);
    }
    }
 if (pos == 1){
    lcd.setCursor(3, 1);
    if (KEY == 2) {
    tempOUT2--;
    EEPROM.write(2, tempOUT2);
    }
    else if (KEY == 5){
    tempOUT2++;
    EEPROM.write(2, tempOUT2);
    }
    }
 if (pos == 2){ // если в третей позиции &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    lcd.setCursor(11, 0); // устанавливаем курсор &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    if (KEY == 2) { // если нажата кнопка &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    tempOUT3--;// изменяем значение &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    EEPROM.write(3, tempOUT3);// сохраняем в еепром &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    }
    else if (KEY == 5){
    tempOUT3++;
    EEPROM.write(3, tempOUT3);
    }
    }
 if (pos == 3){ // если в четвертой позиции
    lcd.setCursor(11, 1); // устанавливаем курсор
    if (KEY == 2) { // если нажата кнопка
    tempOUT4--; //изменяем значение
    EEPROM.write(4, tempOUT4); // сохраняем в еепром
    }
    else if (KEY == 5){
    tempOUT4++;
    EEPROM.write(4, tempOUT4);
    }
    }
  if (KEY == 3) pos--; // крутим позицию
  else if (KEY == 4) pos++;
  if (pos > 3) pos = 0;
  delay(200);
    }
 }
void setup() {
    lcd.createChar(1, gradus);
    lcd.createChar(2, bykvaPE);
    lcd.createChar(3, bykvaL);
    lcd.createChar(4, bykvaU);
    lcd.createChar(5, bykvaii);
    lcd.begin(16, 2);
    lcd.print("Te");
    lcd.write (2);
    lcd.write (3);
    lcd.write (4);
    lcd.write (5);
    lcd.print(" ");
    lcd.write (2);
    lcd.print("o");
    lcd.write (3);
    lcd.setCursor(0, 1);
    lcd.print("AndryGladky 2018");
    delay(10000);
    pinMode(OUT1, OUTPUT);
    pinMode(OUT2, OUTPUT);
    tempOUT1 = EEPROM.read(1); //читаем настройки
    tempOUT2 = EEPROM.read(2); //из еепром
    tempOUT3 = EEPROM.read(3);
    tempOUT4 = EEPROM.read(4);
    stand(PumpOFF);
        } 
void loop() {
    sensor_1.requestTemperatures();// читаем температуру 1 датчик
    sensor_2.requestTemperatures();// читаем температуру 2 датчик
    sensor_3.requestTemperatures();// читаем температуру 2 датчик
    if (key() == 1) setMenu(); // если нажата селект, уходим в меню
    else if (key() == 4) analogWrite(10, 0); // если вниз, глушим подсветку
    else if (key() == 3) digitalWrite(10, HIGH);
    float temperature1 = sensor_1.getTempCByIndex(0); //считывание температуры 1 датчика
    float temperature2 = sensor_2.getTempCByIndex(0); //считывание температуры 2 датчика
    float temperature3 = sensor_3.getTempCByIndex(0); //считывание температуры 3 датчика
    if (temperature1 < -125) erorr (); //если нет датчика ошибка
    if (temperature2 < -125) erorr (); //если нет датчика ошибка
    if (temperature3 < -125) erorr (); //если нет датчика ошибка
    // сверяем температуру и управляем выходами
    if (temperature3 < tempOUT5) //если температура подачи(датчик3) ниже заданого порога выключаем реле
   {
    digitalWrite(OUT1, HIGH); 
    digitalWrite(OUT2, HIGH);
    OUT3 = HIGH; //показываем что отключеный вход по 3 датчику
   }
   else { //если температура подачи выше порога проверяем остальные условия
    OUT3 = LOW; //показываем что включено по 3 датчику
    if (temperature1 < tempOUT3) {digitalWrite(OUT1, LOW);} //если температура ниже порога 1Н включаем
    else if (temperature1 > tempOUT1) {digitalWrite(OUT1, HIGH);} //если температура выше порога 1В выключаем
   }
    //цыфровой автомат
    switch (state) {
    case PumpOFF :/* состояние насос выключен*/
      if (temperature2 == tempOUT2) past = millis();/*подтормаживаем таймер*/
      else if (millis() - past >= time2sec)stand(PumpON); /*стало холодно 2 секунды то включить насос*/
      break;
    case PumpON : /* состояние насос включен*/
      if (temperature2 == tempOUT4) past = millis();/*подтормаживаем таймер*/
      else if (millis() - past >= time2sec)stand(PumpOFF);/*стало жарко 2 секунды то выключить насос*/
      break;
    }
    //цыфровой автомат  
    lcd.setCursor(0, 0);//вывод инфы на экран
    lcd.print(temperature3, 1);
    lcd.write(1);//выводим знак градуса
  // показываем состояние выхода
    if (digitalRead(OUT1)) lcd.print(" OFF");
    else lcd.print(" ON ");
    lcd.setCursor(0, 1);  // устанавливаем курсор
    if (OUT3) lcd.print(" OFF");
    else lcd.println (" ON ");
    if (digitalRead(OUT2)) lcd.print("  OFF");
    else lcd.print("  ON ");

    lcd.setCursor(9, 0);// устанавливаем курсор
    lcd.print("|");//выводим горизонтальную палочку
    lcd.print(temperature1, 1);// показываем температуру с датчика 1
    lcd.write(1);//выводим знак градуса&nbsp;
    lcd.print ("C");//выводим С&nbsp;
    lcd.setCursor(9, 1);// устанавливаем курсор
    lcd.print("|");//выводим горизонтальную палочку
    lcd.print(temperature2, 1); // показываем температуру с датчика 2
    lcd.write(1); //выводим знак градуса
    lcd.print("C"); //выводим С
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

похоже мало читали статей. Попробуйте увеличить объем прочитаных статей раз в 10.  У вас (!!) две независимые задачи. 1- что бы устройство работало без человека и 2- а если человеку хочется , то дать ему возможность порулить. Их надо и разделить и главное не смешивать при написании кода.

/**/
/* устройство */
namespace device {
void init() {}
void run() {}
}

/* пользователь */
namespace user {
void init() {}
void run() {}
}

void setup() {
  device::init();
  user::init();
}

void loop() {
  device::run();
  user::run();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Как минимум так 

/**/
const byte pump1pin =/*пин*/2;
const byte pump2pin =/*пин*/3;
const int temp1min = 15;
const int temp1max = 25;
const int temp2min = 15;
const int temp2max = 25;
/* устройство */
namespace device {
enum state_t {PumpOFF = 0, PumpON };
state_t state1,state2;
void stand1(state_t s) {
  device::state1 = s;
  switch (device::state1) {
    case PumpOFF :
      digitalWrite(pump1pin, LOW);
      break;
    case PumpON :
      digitalWrite(pump1pin, HIGH);
      break;
  }
}
void stand2(state_t s) {
  device::state2 = s;
  switch (device::state2) {
    case PumpOFF :
      digitalWrite(pump2pin, LOW);
      break;
    case PumpON :
      digitalWrite(pump2pin, HIGH);
      break;
  }
}
void init() {
  pinMode(pump1pin, OUTPUT);
  stand1(PumpOFF);
  pinMode(pump2pin, OUTPUT);
  stand2(PumpOFF);
}
void run() {
  int temp1 = 20;/*получили некую температуру*/
  int temp2 = 20;/*получили некую температуру*/
  switch (device::state1) {
    case PumpOFF :/* состояние насос выключен*/
      if (temp1 < temp1min)stand1(PumpON);/*стало холодно то включить насос*/
      break;
    case PumpON : /* состояние насос включен*/
      if (temp1 > temp1max)stand1(PumpOFF);/*жарко то выключить насос*/
      break;
  }
  switch (device::state2) {
    case PumpOFF :/* состояние насос выключен*/
      if (temp2 < temp2min)stand2(PumpON);/*стало холодно то включить насос*/
      break;
    case PumpON : /* состояние насос включен*/
      if (temp2 > temp2max)stand2(PumpOFF);/*жарко то выключить насос*/
      break;
  }
}

/* пользователь */
namespace user {
void init() {}
void run() {}
}

void setup() {
  device::init();
  user::init();
}

void loop() {
  device::run();
  user::run();
}
/**/

 

AndryGladky
Offline
Зарегистрирован: 09.10.2014

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