как выполнить функцию по событию и времени

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

Smarodina пишет:

помогите примером пожалуйста, как хранить переменную char у которой диапазон от -30 до 30. спасибо

это один байт. так что никаких ухищрений не надо, просто пишешь ее туда и все. только когда читаешь - читай в знаковую переменную. а то твои -127... 127 превоатяться в 0..255

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

Smarodina пишет:

и попутно вопрос, ячейка EEPROM Хранит значение 0...255 и только? или -128...127

Это решает программист.

 

Smarodina пишет:

помогите примером пожалуйста, как хранить переменную char у которой диапазон от -30 до 30. спасибо

Используйте signed char вместо char.

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

Smarodina пишет:

помогите примером пожалуйста, как хранить переменную char у которой диапазон от -30 до 30. спасибо

Берите пример с меня! Я любые переменные, независимо от типа, храню очень БЕРЕЖНО 

У переменной char размер сколько бит? Размер одной адресуемой ячейки EEPROM сколько бит? Намек ясен? EEPROM-у пофиг что хранить. Важно то, как вы это интерпретируете

 

УПС, не заметил, что вторая страница уже пошла )) Припоздал с разжевыванием очевидного

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Smarodina пишет:

помогите примером пожалуйста, как хранить переменную char у которой диапазон от -30 до 30. спасибо

Пилять - char  это 0-255. И никаких минусов. Читайте мануалы к си.

Пример дам из своей программы. Не правил - вставил "как есть":

#define EEPROM_Kp 0 //Адрес Kp в EEPROM
#define EEPROM_Tset 1
#define EEPROM_Tinset 5
#define EEPROM_init 9

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

  EEPROM_In=EEPROM.read(EEPROM_init);
  if(EEPROM_In!=22){
    EEPROM.put(EEPROM_Kp,3);
    EEPROM.put(EEPROM_Tset,(float)40.00);
    EEPROM.put(EEPROM_Tinset,(float)23.00);
    EEPROM.put(EEPROM_init,22);
  }
 
// ************************ Чтение установок из памяти ************************************************
    Kp=EEPROM.read(EEPROM_Kp); //Коэффициент пропорциональности. Пока предполагаем не более 15
    if (Kp!=3) { // пока так
      Kp=3;
   
      EEPROM.put(EEPROM_Kp,Kp);
    }

    
    
    EEPROM.get(EEPROM_Tset,Tset); //Установленная температура теплоносителя
   
    if ((Tset <20.00f)||(Tset>80.00f)) { // если в EEPROM не поймешь чего
      Tset=20.00f;
  
      EEPROM.put(EEPROM_Tset,Tset);
    }

    
    EEPROM.get(EEPROM_Tinset,Tinset); //Установленная температура внутренняя
    if ((Tinset <20.00f)||(Tinset>40.00f)) { // если в EEPROM не поймешь чего
      Tset=23.00f;
   
      EEPROM.put(EEPROM_Tinset,Tinset);
    }
}

 

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

mykaida пишет:

Пилять - char  это 0-255. И никаких минусов. Читайте мануалы к си.

Хочется человеку signed char ))

Кстати, когда использовал набортную EEPROM ардуины, всегда использовал UPDATE вместо PUT. Очень во многих сценариях с большой вероятностью в ячейку пишется одно и то-же значение. Хотя, если разобраться, практического смысла в этом не много. Больше для успокоения нервов

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Rumata пишет:

Кстати, когда использовал набортную EEPROM ардуины, всегда использовал UPDATE вместо PUT. Очень во многих сценариях с большой вероятностью в ячейку пишется одно и то-же значение. Хотя, если разобраться, практического смысла в этом не много. Больше для успокоения нервов

put интересен тем, что он перед записью проверяет содержимое. Тем самым сохраняя EEPROM. update -  это какая-то часть put, ну мне так кажется...

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

mykaida пишет:

Пилять - char  это 0-255. И никаких минусов. Читайте мануалы к си.

Уверены?

Smarodina
Offline
Зарегистрирован: 03.02.2018

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

Smarodina
Offline
Зарегистрирован: 03.02.2018

починил коррекцию, запись в EEPROM выглядела так EEPROM.put(0,fan_val); и я не мог изменить fan_val, сделал EEPROM.update(0,fan_val); и все заработало...

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

Smarodina пишет:

починил коррекцию, запись в EEPROM выглядела так EEPROM.put(0,fan_val); и я не мог изменить fan_val, сделал EEPROM.update(0,fan_val); и все заработало...

Щито? 

Smarodina
Offline
Зарегистрирован: 03.02.2018

Rumata пишет:

Smarodina пишет:

починил коррекцию, запись в EEPROM выглядела так EEPROM.put(0,fan_val); и я не мог изменить fan_val, сделал EEPROM.update(0,fan_val); и все заработало...

Щито? 

 

не понял вопроса

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

Smarodina пишет:

не понял вопроса

Это я не понял предыдущего сообщения. fan_val у вас 8 бит, поэтому put и update в вашем случае по результату и по синтаксису эквивалентны. Про остальное вообще не понял. 

Smarodina
Offline
Зарегистрирован: 03.02.2018

ну я же написал, через put не работало, написал update заработало 

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

полтергейст

Smarodina
Offline
Зарегистрирован: 03.02.2018

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

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

Smarodina пишет:

теперь жду комментариев где не правильно!

Обалдеть! Ощущеие, что Вам должны.

Ну, ладно, держите:

В строке №189 неправильно используется локальная автоматическая переменная timer_pid. Он не будет запоминать время начала между вызовами функции, как Вам того, похоже, хотелось бы. А потому функция pid_timer (условие в ней) срабатывает когда ей вздумается и предсказать когда она сработает, а когда - нет, невозможно.

Ровно та же байда в строке №221 с переменной filter_temp_timer. Точно также условие в функции average_tempсрабатывает когда ему заблагорассудится.

Вот, как раз и Вы это заметили

Smarodina пишет:
таймеры своей жизнью жить вздумали...

Пока хватит.

Smarodina пишет:

и попутно вопрос, ячейка EEPROM Хранит значение 0...255 и только? или -128...127

Это Вам кажется, что между  "0..255" и "-128..127" есть какая-то разница. На самом деле это одно и то же.

Smarodina
Offline
Зарегистрирован: 03.02.2018

спасибо за ответ. 

 

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

Smarodina
Offline
Зарегистрирован: 03.02.2018

классный форум, глаза болят читать:) 

 

мне подсказывают что не правильно обращаюсь с датчиком ds18b20 

void average_temp(){                                                                         //Функция обработки сигнала датчика температуры
   int currentTemp;
   sensors.requestTemperatures();
   currentTemp = sensors.getTempC(insideThermometer)*10;
   if (millis() - filter_temp_timer > FILTER_STEP_temp) {
    filter_temp_timer = millis();   
    val_temp = currentTemp;
    val_Ftemp = val_temp * FILTER_COEF_temp + val_Ftemp * (1 - FILTER_COEF_temp);
    }
 }

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

 

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

 

или спрашивать надо по таймеру? а не долбить?

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

Smarodina пишет:

классный форум, глаза болят читать:) 

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

или спрашивать надо по таймеру? а не долбить?

Если вместо форума почитать инструкцию на датчик, то можно легко узнать сколько нужно ждать конвертацию и что будет если не ждать. 

А люди, которые любят долбить чего не поподя - долболюбы. Или как-то так..

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Smarodina пишет:

классный форум, глаза болят читать:) 

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

или спрашивать надо по таймеру? а не долбить?

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

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

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

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

v258 пишет:

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

Точно!

И, в принципе, можно даташит почитать. Он не просто так написан и не людьми с улицы, а разработчиками микросхемы...

ИгорьЛабспирт
ИгорьЛабспирт аватар
Offline
Зарегистрирован: 08.03.2021

считывай через секунду. Или, если процесс позволяет, реже.

Smarodina
Offline
Зарегистрирован: 03.02.2018

в общем получился вот такой контроллер на данный момент 

 


#define PID_INTEGER
#define BTN1 4
#define BTN2 5
#define BTN3 2
#define BTN4 3
#define BTN5 A0

#include <EEPROM.h>
#include <GyverButton.h>
#include <GyverTimer.h>
#include <GyverTM1637.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <GyverPID.h>

#define CLK A4
#define DIO A5
#define ONE_WIRE_BUS 11
#define FILTER_STEP_temp 100
#define FILTER_COEF_temp 0.05

GyverTM1637 disp(CLK, DIO);
GyverPID pid(0.35, 0, 0, 3000);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer {0x28, 0xB8, 0x86, 0xD5, 0x33, 0x20, 0x01, 0xCA  };  //УКАЗАТЬ имя  датчика
////////////////////кнопки////////////////////////////////////////////
GButton startButtonPin(BTN1);            //пин кнопки Старт
GButton stopButtonPin(BTN2);             //пин кнопки Стоп
GButton plusButtonPin(BTN3);             //пин кнопки "+"
GButton minusButtonPin(BTN4);            //пин кнопки "-"
GButton disp_ButtonPin(BTN5);            //пин кнопки дисплея
////////////////////датчики///////////////////////////////////////////
const int photoresistorPin = 12;         //пин фоторезистора
const int infraredSensorPin = A3;        //пин ИК датчика
////////////////////иполнители////////////////////////////////////////
const int feederAugerPin = 6;            //пин шнека питателя
const int pumpPin = 7;                   //пин цикуляционного насоса
const int heatingElementPin = 8;         //пин зажигалки
const int stokerAugerPin = 9;            //пин шнека стокера
const int pwmPin = 10;                   //пин для ШИМ
const int firebarPin = 13;               //пин подвижного колосника 
////////////////////переменные///////////////////////////////////////
int desiredTemperature;
byte working;
byte start_count;
byte photoresistor;
int p_pause;
int w_pause;
byte start1;
int val_f;
int val[3];
int index;
int val_temp;
int val_Ftemp;
byte starting;                                    
byte finishing;                                    
byte plusButton;
byte minusButton;
byte dispButton;
int dose;
byte displ;
signed char fan_value;
int PWM_val;
byte start_work;
byte stop_FP;
byte dozig;
byte fanspeed_pr;
byte pid_out_last;
int switch_start;
int switch_stop;
int stop_FPB;
  
GTimer start_timer0(MS);
GTimer start_timer1(MS);
GTimer start_timer2(MS);
GTimer start_timer3(MS);
GTimer stop_timer1(MS);
GTimer AS_timer(MS);

int middle_of_3(int a, int b, int c) {
 int x[2];
if (a > b) {x[0] = b; x[1] = a;} 
else {x[0] = a; x[1] = b;} 
if (x[1] > c) {return (x[0]< c) ? c : x[0];} 
else {return x[1];} 
}

void setup() {
  switch_stop=9;
  switch_start=9;
  pid_out_last=100;
  dozig=0;
  PWM_val=0;
  displ=0;
  working=0;
  start1=0;
  start_count=0;
  start_work=0;
  desiredTemperature=400;
  stop_FP=1;
  
  disp.clear();
  disp.brightness(0);  // яркость, 0 - 7 (минимум - максимум)
  
    startButtonPin.setTickMode(AUTO);
    stopButtonPin.setTickMode(AUTO);
    plusButtonPin.setTickMode(AUTO);
    minusButtonPin.setTickMode(AUTO);
    disp_ButtonPin.setTickMode(AUTO);
	
	  pinMode(photoresistorPin, INPUT);
    pinMode(infraredSensorPin, INPUT);
    pinMode(A1, INPUT);
    pinMode(pumpPin, OUTPUT);
    pinMode(feederAugerPin, OUTPUT);
    pinMode(stokerAugerPin, OUTPUT);
    pinMode(pwmPin, OUTPUT);
    pinMode(heatingElementPin, OUTPUT);
    pinMode(firebarPin, OUTPUT);
    
    digitalWrite(feederAugerPin, HIGH);
    digitalWrite(stokerAugerPin, HIGH);
    digitalWrite(heatingElementPin, HIGH);
    digitalWrite(pumpPin, HIGH);
    digitalWrite(firebarPin, HIGH);
    
  pid.setDirection(NORMAL); 
  pid.setLimits(0,9);
  pid.setpoint = desiredTemperature; 
  sensors.begin();
  start_timer0.setTimeout(5000);
  start_timer1.setTimeout(15000);
  start_timer2.setTimeout(180000);
  start_timer3.setTimeout(10000);
  stop_timer1.setTimeout(120000);
  AS_timer.setTimeout(60000);
  EEPROM.put(2,(signed char)fan_value);
}

void loop() {
  button();
  fillPillets();
  pid_timer();
  average_fire();
  average_temp();
  work();
  startWork();
  finishWork();
  auto_start();
  //fire_bar();
  startPWM();
  screen();
}

void pid_timer(){                                                                            //Функция таймер ПИД регулятора
static uint32_t timer_pid;
if(working==1){
  if(millis() - timer_pid >= 1000){
    timer_pid = millis();
    pid.input = val_Ftemp;
    pid.setpoint = desiredTemperature;
    pid.getResult();
  }
}
}

void fire_bar(){                                                                             //Функция таймера работы подвижного колосника
    static uint32_t oldMillis = millis();
    static uint32_t onOffTime=200000;
    uint32_t newMillis = millis();
    boolean firebar_On = digitalRead(firebarPin);
    
    if(newMillis-oldMillis>=onOffTime){
        oldMillis=millis();
        firebar_On=!firebar_On;
        onOffTime=5000+(300000*firebar_On);//!firebar_On для мосфета, firebar_On для реле управление по LOW.
        digitalWrite(firebarPin,firebar_On);
    }    
}

void average_temp(){                                                                         //Функция обработки сигнала датчика температуры
   int currentTemp;
   static uint32_t filter_temp_timer;
   static uint32_t temp_timer;
   sensors.requestTemperatures();
   if(millis()-temp_timer>1000){
   temp_timer=millis(); 
   currentTemp = sensors.getTempC(insideThermometer)*10;}
   if (millis() - filter_temp_timer > FILTER_STEP_temp) {
    filter_temp_timer = millis();   
    val_temp = currentTemp;
    val_Ftemp = val_temp * FILTER_COEF_temp + val_Ftemp * (1 - FILTER_COEF_temp);
    }
 }
 
void average_fire(){                                                                         //Функция обработки сигнала датчика огня   
 if (++index > 2) index = 0; 
  val[index] = analogRead(A3); 
  val_f = middle_of_3(val[0], val[1], val[2]);
 
 }

void startPWM() {                                                                            //функция управления ШИМ вентилятора
  static int fan_val_last;
  static int fanspeed;
  fan_value=constrain(fan_value,-20,20);
  fanspeed_pr = PWM_val+fan_value;
  fanspeed_pr = constrain(fanspeed_pr, 0, 100);
  fanspeed = map(fanspeed_pr, 0, 100, 0, 253);
  analogWrite(pwmPin, fanspeed);
  if(fan_value!=fan_val_last){
    EEPROM.update(2, fan_value);
  }
    fan_val_last=fan_value;

}

void button(){                                                                               //Функция обработки кнопок
  desiredTemperature = constrain(desiredTemperature, 300, 800);
  stop_FP = digitalRead(stokerAugerPin);
  
  if(disp_ButtonPin.isClick()){
    displ+=1;
    if(displ >= 4){
      displ=0;
    }
  }
  if(startButtonPin.isClick() and photoresistor==1 and val_f>900){
    switch_start=0;
    }
  if(startButtonPin.isPress() and val_f<900){
    working=1;
    start1=1;
	  }
  if(stopButtonPin.isClick()){
      stop_FPB=1;
	  working=0;
      start1=0;
      switch_stop=0;
    }
	if(val_Ftemp>=800){
      stop_FPB=1;
	  working=0;
      start1=0;
	  switch_stop=0;
	  }
	if(val_Ftemp>400){
	digitalWrite(pumpPin, LOW);}
	else{digitalWrite(pumpPin, HIGH);
	}
	if(val_Ftemp<50 and start_count>=3){
		digitalWrite(pumpPin, LOW);
	}
}

void auto_start(){                                                                           //Функция автостарта горелки при потере огня
  int val_fire=analogRead(A3);
  if(val_fire>1010 and start1==1 and start_count<2){
    if(AS_timer.isReady()){
      start1=0;
      working=0;
      switch_start=5;}
   }else{AS_timer.start();}
  
  if(start_count>=3){
    start1=0;
	  working=0;
    //сюда надо подкючить сирену или какое то еще оповещение о аварии.
    }
 
}

void screen(){                                                                               //функция вывода информации на дисплей
 static int for_disp;
 switch (displ){
  //вывод температур, изменение заданной температуры
  case 0 :
    for_disp = desiredTemperature * 10;
      for_disp = for_disp + val_temp/10;
      disp.displayInt(for_disp);                                                      
      disp.point(true);
    if(plusButtonPin.isPress()){
      desiredTemperature+=10;
      }
      if(minusButtonPin.isPress()){
      desiredTemperature-=10;
      }
    break;
  //вывод расхода грамм\час
  case 1 :
    disp.displayInt(dose);
      disp.point(false);
    break;
  //вывод скорости вентилятора в процентах с возможностью корректировки
  case 2 :
    disp.displayInt(fanspeed_pr);
    disp.displayByte(0, 0x71);
    disp.point(false);
    if(plusButtonPin.isClick()){
      fan_value+=1;
      }
      if(minusButtonPin.isClick()){
      fan_value-=1;
      }
    break;
  //вывод уровня пламени 0-1023 где 1023 огня нет.
  case 3 :
    disp.displayInt(val_f);
      disp.point(false);
    break;
  }
}
 
void fillPillets() {                                                                         //Функция подачи пеллет из бункера в стокер
  photoresistor = digitalRead(photoresistorPin);
  if(stop_FPB==0){
  if (photoresistor == 0 and stop_FP==1) {
     digitalWrite(feederAugerPin, LOW);}
  else {
     digitalWrite(feederAugerPin, HIGH);}
  }
}

void startWork(){                                                                            //функция розжига
  switch(switch_start){
	   case 0:
      PWM_val=100;
	  break;
	   
	   case 1:
	    PWM_val=20;
      digitalWrite(feederAugerPin, HIGH);
	    digitalWrite(stokerAugerPin, LOW);
		break;
	   
	   case 2:
	    digitalWrite(stokerAugerPin, HIGH);
	    switch_start=3;
		break;
	   
	   case 3:
	    PWM_val=80;
	    digitalWrite(heatingElementPin, LOW);
        break;
	   
	   case 4:
	    digitalWrite(heatingElementPin, HIGH);
	    PWM_val=80;
       break;
		
	   case 5:
        digitalWrite(heatingElementPin, HIGH);
        start_count+=1;
		if(start_count<=3){
	    switch_start=0;}
        break;

     case 6:
     start1=1;
     working=1;
     switch_start=8;
     break;
    }

if(switch_start==0){
  if(start_timer0.isReady())switch_start=1;}else{start_timer0.start();}

if(switch_start==1){
  if(start_timer1.isReady())switch_start=2;}else{start_timer1.start();}

if(switch_start==3){
  if(val_f<750)switch_start=4;}

if(switch_start==3){
  if(start_timer2.isReady())switch_start=5;}else{start_timer2.start();}

if(switch_start==4){
  if(start_timer3.isReady())switch_start=6;}else{start_timer3.start();}
}

void work() {                                                                                //Функция выбора режима мощности работы горелки
  if (working == 1) { 
    start_count = 0;
    if (pid_out_last != pid.output){
  digitalWrite(stokerAugerPin,HIGH);
    switch (pid.output) {
    //p_pause=пауза подачи. w_pause=подача. PWM_val=вентилятор в процентах. dose=расход грамм\час.
	case 0 :p_pause=10000;w_pause=100;PWM_val=20;dose = 180;break;
    case 1 :p_pause=8520;w_pause=100;PWM_val=25;dose = 210;break;
    case 2 :p_pause=7500;w_pause=100;PWM_val=30;dose = 240;break;
    case 3 :p_pause=6000;w_pause=100;PWM_val=35;dose = 300;break;
    case 4 :p_pause=5000;w_pause=100;PWM_val=40;dose = 360;break;
    case 5 :p_pause=4500;w_pause=100;PWM_val=45;dose = 400;break;
    case 6 :p_pause=3000;w_pause=155;PWM_val=65;dose = 850;break;
    case 7 :p_pause=3750;w_pause=200;PWM_val=80;dose = 1000;break; 
    case 8 :p_pause=3000;w_pause=200;PWM_val=95;dose = 1630;break;
    case 9 :p_pause=3000;w_pause=250;PWM_val=100;dose = 2000;break;            
    }
  }
  pid_out_last = pid.output;
  work_timer();
  }
}

void work_timer(){                                                                           //Функция таймер работы горелки
    static uint32_t oldMillis = millis();
    static uint32_t onOffTime;
    uint32_t newMillis = millis();
    boolean soker_On = digitalRead(stokerAugerPin);
    
    if(newMillis-oldMillis>=onOffTime){
        oldMillis=millis();
        soker_On=!soker_On;
        onOffTime=w_pause+((p_pause - w_pause)*soker_On);//!soker_On для мосфета, soker_On для реле управление по LOW.
        digitalWrite(stokerAugerPin,soker_On);
    }    
}

void finishWork(){                                                                           //Функция остановки работы горелки
  switch(switch_stop){
	 case 0:
	    if(val_f<1000)work_timer();
      break;
	 case 1:
      digitalWrite(stokerAugerPin, HIGH);
      PWM_val=100;
    break;
    case 2:
      stop_FPB=0;
      PWM_val=0;
      switch_stop=3;
      break;
	}
if(switch_stop==0){
 if(val_f>1000){switch_stop=1;}}
if(switch_stop==1){
    if(stop_timer1.isReady())
    switch_stop=2;}
    else{
     stop_timer1.start();}
}

а вот ссылка на плейлист вся боль за три месяца рождения этого скетча 

https://youtube.com/playlist?list=PL5SKdGoX_Z_RHaOFNApHLiNN40W0TvVu1

 

теперь думаю как сделать не фиксированные режимы работы, а выставить минимальный и максимальный и модуляцию между ними

Morroc
Offline
Зарегистрирован: 24.10.2016

какую еще модуляцию ?

Smarodina
Offline
Зарегистрирован: 03.02.2018

Morroc пишет:
какую еще модуляцию ?

Ну чтоб контроллер сам делал режим между минимум и максимум

Ну типо вот тебе рамки, а дальше сам:)

Morroc
Offline
Зарегистрирован: 24.10.2016

А что сам ? ) Температуру поддерживал ?

Smarodina
Offline
Зарегистрирован: 03.02.2018

Morroc пишет:
А что сам ? ) Температуру поддерживал ?

 

режим для работы изобретал чтоб держать заданную температуру