Четыре состояния - двумя реле.

paf
Offline
Зарегистрирован: 25.01.2013

Термостат.
Есть три нагревателя с состоянием включен, выключен.
Управляются тремя реле. Пин в HIGH - реле выкл.
Нагреватели включаются постепенно. Ниже температура, больше нагревателей.
Для задержки между включениями введен признак включения flag для каждого реле.

if (time_act > time_eco_end && time_act <= time_eco_bg) 
 {
     ust = 23;
	}
	else
	{
     ust = 22;
	}
 
	if (celsius >= ust && flag == true)
	{
	digitalWrite(4, HIGH);
	flag = false;
	}
	else if (celsius < (ust - 0.2) && flag == false)
	{
	digitalWrite(4, LOW);
	flag = true;
	}
	if (celsius > (ust - 1) && flag2 == true)
	{
	digitalWrite(3, HIGH);
	flag2 = false;
	}
	else if (celsius < (ust - 1.2) && flag2 == false)
	{
	digitalWrite(3, LOW);
	flag2 = true;
	} 
	if (celsius > (ust - 1.5) && flag3 == true)
	{
	digitalWrite(2, HIGH);
	flag3 = false;
	}
	else if (celsius < (ust - 1.7) && flag3 == false)
	{
	digitalWrite(2, LOW);
	flag3 = true;  
 }

 

Код работает.
Однако, при этом используются три реле. Хотя четыре необходимых состояния можно обеспечить двумя.
Всё выключено. Включен один. Включены два. Включены все, 2+1.
И будто бы ничего сложного, но какой-то паралич мысли, "все говорит о наличии отсутствия опыта" :)
Подтолкните мыслю, пожалуйста.
 

tsostik
Offline
Зарегистрирован: 28.02.2013

Можно и с двумя реле, но двумя дополнительными логическими элементами. Oдин OR и один AND.

Два сигнала на пинах SWLow и SWHigh

Реле 1 управляется по (SWLow || SWHigh)

Реле 2- SWHigh

Реле 3 - (SWLow && SWHigh)

Код вроде несложно подправить.

paf
Offline
Зарегистрирован: 25.01.2013

Вот тут я засел....:(  и ту-плю! Или просто нужно отдохнуть?



if (celsius >= ust && flag == true)
	{
	digitalWrite(3, HIGH);
        digitalWrite(4, HIGH);
	flag = false;
	}
	else if (celsius >= (ust - 0.99) && celsius <= (ust - 0.2)) &&  flag == false)
	{
	digitalWrite(3, LOW);
        digitalWrite(4, HIGH);
	flag = true;
	}
	if (celsius >= (ust - 1) && celsius <= (ust - 0.95)) && flag2 == true)
	{
	digitalWrite(3, HIGH);
        digitalWrite(4, LOW);
	flag2 = false;
	}
	else if (celsius < (ust - 1.1) && flag2 == false)
	{
	digitalWrite(3, HIGH);
        digitalWrite(4, LOW);
	flag2 = true;
	} 
	if ((celsius >=(ust - 1.3)&&celsius <=(ust - 1.2)) && flag3 == true)
	{
	digitalWrite(3, LOW);
	digitalWrite(4, HIGH);
	flag3 = false;
	}
	else if (celsius < (ust - 1.4) && flag3 == false)
	{
	digitalWrite(3, LOW);
	digitalWrite(4, LOW);
	flag3 = true;  
 }

.............. :)))  оно?  В смысле похоже? Только чур, не подсказывать!

leshak
Offline
Зарегистрирован: 29.09.2011

Немного непонятно что вы хотите. Сказали что у вас "четыре необходимых состояния" и тут же перечислили пять состоний ("2+1" это что?)

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

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

Примерно так

byte heats=0; // тут храним сколько реле нужно включить
// выясняем сколько реле нам нужно

if(celc<10) heats=2 // два реле нужно если меньше 10 градусов
else if(celc<20) heats=1 // от 10 до 20 градусов хватит и одного
else heats=0; // если больше 10-ти вообще ничего не нужно

// а теперь включаем реле
switch(heats){
   case 2:
          digitalWrite(RELE1,LOW); // если LOW - включает нагреватель
          digitalWrite(RELE2,LOW);
         break;
   case 1:
          digitalWrite(RELE1,LOW); // если LOW - включает нагреватель
          digitalWrite(RELE2,HIGH); // выключили второе
         break;
   default:
          digitalWrite(RELE1,HIGH); // выключили первое
          digitalWrite(RELE2,HIGH); // выключили второе   
}

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

leshak
Offline
Зарегистрирован: 29.09.2011

А еще задержка вам нужна... ну это опять-таки отдельно. Нечего все в один огород городить внутрь ифов.

byte prevHeats=0;

loop(){
  .... тут код из прошлого поста, вычисляем/включаем релешки...

  if(prevHeats!=heats){ // количество включенных реле изменилось
     delay(200); // значит нужно чуток подуплить
  }

  prevHeats=heats; // запомнили сколько у нас реле включено
}

 

leshak
Offline
Зарегистрирован: 29.09.2011

tsostik пишет:

Можно и с двумя реле, но двумя дополнительными логическими элементами. Oдин OR и один AND.

....

Реле 3 - (SWLow && SWHigh)

Забавно ;)

tsostik
Offline
Зарегистрирован: 28.02.2013

Ага, с двумя пинами, конечно -)

Количество реле в любом случае определяется количеством термостатов.

paf
Offline
Зарегистрирован: 25.01.2013

Спасибо, друзья! :)  Интересное решение с кейсами.  

Виноват. Очень бестолково описал задачу.  Даже телепаты бессильны.:( Виноват!

Постараюсь поконкретней.  Итак, управлять с помощью двух реле тремя нагревателями.

Может быть четыре состояния.

Выключены все. (оба реле выключены).  

Включен один. (Реле 1).  

Включены два. (Реле 2. Внимание! Реле 2 включает сразу два нагревателя)

Включены оба реле. (Реле1 и Реле2. В работе три нагревателя. Реле 1 - один, Реле 2 - 2 итого 3) 

В первом сообщении в коде кусок:



if (celsius >= ust && flag == true)
	{
	digitalWrite(4, HIGH);
	flag = false;
	}
	else if (celsius < (ust - 0.2) && flag == false)
	{
	digitalWrite(4, LOW);
	flag = true;
	}

включение нагревателя не сразу после того, как температура падает меньше установленной на величину разрешения температурного датчика, а после понижения на 0.2 градуса. Задержка во времени неодинаковая, в зависимости от того, насколько быстро произойдет остывание.  Почему не delay() ?  delay() в цикле конечно есть потому, что используется DS18b20. Но в цикле кроме этого есть обновление дисплея с часами, хотя и без секунд. И DS18b20 при всем его 0.06 разрешении, все равно "качается" (23 - 22.94 - 23 - 22.94.....) чтобы реле не "хлопали" на этих ненужных сотках и сделана задержка по понижению на пару десяток градуса. 

Из-за чего сыр бор?  Релюшки в блоках по две штуки... (Ну, и вот. Если три релюхи, то два блока, а это четыре реле. Жаба начинает свою песню... Ну и просто поискать возможное решение. :)

leshak
Offline
Зарегистрирован: 29.09.2011

Так понятно, но вообщем-то принципиально не меняет идею изложенную в #3. А идея такова: разбивайте на блоки:

1. Блок выяснение сколько должно быть включенно (и кстати тестить его тогда можно даже без реле, простыми Serial.print)
2. Блок включения реле (блок исполнения решений)
3. Блок обеспечения задержки.

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

При переходе к "два реле - три нагревателя" - в блоке два - принципиально ничего не меняется. Просто в switch пропишите что-бы на "case 2:" включалось нужно реле, а не оба, а на "case 3" - оба.

"Без delay()" - ну тоже не очень сложно. Просто изначально небыло про "что-то еще происходит", поэтому его было проще, но и без делай не сумпер сложно

unsigned long lastHeatsChangedTime=0;

loop(){
   if(millis()-lastHeatsChangedTime>500){ // с прошлого включения прошло достаточно времени
       // тут идет логика сколько выключателей нужно включать, само включение и ит.п. 
      // вообщем из #3

     if(prevHeats!=heats)  lastHeatsChangedTime=millis(); // запомнили когда последний раз переключили реле
  }

  prevHeats=heats;
    
}

А гистерезис сделать, что-бы на границах температур не "щелкало" - чуть-чуть изменить if-выснения сколько реле нужно

if(celc<10) heats=3
else if(celc >11 && celc<15) heats=2
else if(celc >16 && clec <20) heats=1
else if(celc >21)heats=0;

Вот так при температуре от 10 до 11, от 15 до 16 и от 20 до 21 - heats не будет менять свое значение.

Скажем если температура растет 9 (включились 3), 9.5,10,10.5 (по прежнему три),11,11.5(один выключился), 12, 11, 10.5 (по прежнему два), 10, 9.5 (опять три).

Вообщем в этих "промежутках" у вас количество включенных будет зависить от того "сверху" или "снизу" мы пришли. В точности как digitalRead решает логическая единица у нас или ноль при промежуточных значениях вольтажа на пине.

Только сам byte heats , нужно будет объявить не внутри loop, а как глобальную переменную, что-бы ее значение тоже сохранялось между проходами loop()  (или объявить ее статической).