Управление ТЭНами пропуском периодов ШИМ

Roman2344
Offline
Зарегистрирован: 09.09.2015

Есть два ТЭНа по 370Вт, 220В, есть бак который греют эти два ТЭНа с двух сторон, есть аналоговый датчик LM35(максимум 155градусов), ТЭНы нужно разогреть в начале до 125градусов и так прогревать 1минуту, потом будет рабочий диапазон всё время 100градусов. Сейчас делаю так в рабочем режиме: если температура допустим больше 100 градусов выключаем ТЭН на 3с., если температура меньше 100градусов то включаем ТЭН на 2с, не плохо конечно но как то во-первых получается удерживать температуру в пределах 10градусов, во - вторых как то то бывает перегрев то не догрев и какой - то отклик системы не очень. Опорное напряжение 2,56В, управление: ардуино мега+МОС3061+ВТ139-800.

Думаю делать через пропуск периодов с помощью функции ШИМ на 64Гц(так как сеть 50Гц), хотелось бы что бы ШИМ зависил от напряжения с датчика LM35, то есть чем больше температура, тем соотвественно больше напряжение на выходе LM35, и следовательно меньше ШИМ, для большей точности делаю 10 измерений температурыю Набросал пока рабочий режим, вот так:

int ten=4;
int term1 = A0;  

int t21 = 0; 
int t22= 0;
int t23= 0;
int t24= 0; 
int t25= 0;
int t26= 0;
int t27= 0; 
int t28= 0;
int t29= 0;
int t30= 0;
   
void setup()
{TCCR0B = TCCR0B & B11111000 | B00000101; //64Гц
analogReference(INTERNAL2V56);
pinMode(term1,INPUT);
}

void loop()

{  t21 = analogRead(term1);
 delay(40);
  t22 = analogRead(term1);
 delay(40);
  t23 = analogRead(term1);
 delay(40);
  t24 = analogRead(term1);
 delay(40);
  t25 = analogRead(term1);
 delay(40);
  t26= analogRead(term1);
 delay(40);
  t27= analogRead(term1);
 delay(40);
  t28= analogRead(term1);
 delay(40);
  t29= analogRead(term1);
 delay(40);
  t30= analogRead(term1);
 delay(40);
 t1=((t21+t22+t23+t24+t25+t26+t27+t28+t29+t30)/10);

  analogWrite(ten,255-t1/1.57);//t1=400-это 100градусов=1000мВ датчика LM35, соответсвенно при опорном 2,56В это равно 400

}

 

Кто что думает по этому поводу, лучше будет чем я сейчас делаю? Соответсвенно так же и режим разогрева буду делать только так как там будет 125градусов то: 

analogWrite(ten,255-t1/1.96);//t1=500-это 125градусов=1250мВ датчика LM35, соответсвенно при опорном 2,56В это равно 500

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Вот мой опыт

http://arduino.ru/forum/proekty/pi-regulyator-otopleniya - для инерционного объекта

http://arduino.ru/forum/programmirovanie/trebuetsya-perenesti-znachenie-... - ПИ регулятор с пропуском полупериодов

http://arduino.ru/forum/programmirovanie/algoritm-ravnomernogo-raspredel... - алгоритм пропуска полупериодов

Roman2344
Offline
Зарегистрирован: 09.09.2015

Есть вопросы по вашему ПИ - регулятору, ноль мы не отслеживаем, правильно?

Далее интересует #define n_f 10.0//температура по умолчанию

#define t_pwm 60000//период 100% мощности      откуда взялось 60000?
#define t_time 1000//период опроса температуры   а если с аналогового температурного датчика брать 
нужна эта задержка, для чего вы её брали для терморезистора?
int zad=0;  это задание нужной уставки?
 
 
 
 
 
Если симистор стоит, это можно вообще убрать со скетча?
if (p<0.0)
  {
    p=0.0;//ограничение P
  }
  i=(i+(e*0.014));//0.7
   if (i>100.0)
  {
    i=100.0;//ограничение I
  } 
     if (i<-100.0)
  {
    i=-50.0;//ограничение I
  } 
  //расчет выходной мощности
  zad=p+i;
  }
  //ограничение управляющего сигнала
  //для исключения частого переключения реле
  //если твердотельное реле, можно не ограничивать
 
 
 
 
 
Что за числа?
 
if (zad<4){
    zad=0;
  }
  if (zad>96){
    zad=100;
  }
 
 
 
И откуда взялось ШИМ именно 2Гц?
 

 

Roman2344
Offline
Зарегистрирован: 09.09.2015


Вот набросал код, только не пойму где задать нужную мне температуру

#define n_f 100.0//температура по умолчанию 100 градусов

#define t_pwm 60000//период 100% мощности
#define t_time 1000//период опроса температуры
float t1=A0;// Вход АЦП 0
int outten=13;
//для ПИ регулятора
float p,i;

long time;//интервал замера температуры
long lcd_time;//интервал отрисовки экрана
long on_time=0;//для периода ШИМ
int zad=0;
float temp=0.0;//текущее значение температуры
float pre_temp=0.0;//предыдущее значение температуры
int w=0;
float ust=n_f;//termostate
int c=0;//пройденые циклы мощности
float addr[25][2] = {
  {
    0,32.0                                                              
  }
  ,
  {
    5,25.5                                                              
  }
  ,
  {
    10,20.0                                                              
  }
  ,
  {
    15,15.7                                                                
  }
  ,
  {
    20,12.62                                                                
  }
  ,
  {
    25,10.0                                                                
  }
  ,
  {
    30,8.24                                                                
  }
  ,
  {
    35,6.63                                                                
  }
  ,
  {
    40,5.41                                                                
  }
  ,
  {
    45,4.41                                                                
  }
  ,
  {
    50,3.62                                                                
  }
  ,
  {
    55,2.99                                                                
  }
  ,
  {
    60,2.48                                                                
  }
  ,
  {
    65,2.08                                                                
  }
  ,
  {
    70,1.75                                                                
  }
  ,
  {
    75,1.47                                                                
  }
  ,
  {
    80,1.258                                                                
  }
  ,
  {
    85,1.063                                                                
  }
  ,
  {
    90,0.905                                                                
  }
  ,
  {
    95,0.776                                                                
  }
  ,
  {
    100,0.669                                                                
  }
  ,
  {
    105,0.581                                                                
  }
  ,
  {
    110,0.505                                                                
  }
  ,
  {
    115,0.442                                                                
  }
  ,
  {
    120,0.387                                                                
  }
  ,
};
void setup(){
pinMode(t1,INPUT);
  pinMode(outten,OUTPUT);
  time = millis();
  on_time = time;

}
void loop(){
 
  //---------------чтение температуры---------------
  if ((millis()-time)>=t_time){
    time=millis();
    temp=analogRead(t1);//получаем температуру
    temp=(pre_temp*0.2)+(temp*0.8);//фильтр
    //   w=abs((ust-temp)*(pre_temp-temp));//время выхода на уставку
    pre_temp=temp;
    PIctl();//расчет мощности
  }
  
  //---------------------управление мощностью--------------------------
  
//выдаем мощность
  if (millis()>3000){
    if((millis()-on_time)>=t_pwm){//период ШИМ
      on_time=millis();

      if(c<zad){
    digitalWrite(outten,1);
      }
      else{
        if (zad != 100){
       digitalWrite(outten,0);
        }
      }
      c=c+1; 
      if(c==100){
        c=0;
        //PIctl();
      }
    }
  }
}
void PIctl()
{
    if(temp>(ust-0.5)&&temp<(ust+0.5))//зона нечувствительности +-0,5C
  {
    zad=i;
  }
  else
  {
  float e;
  e=(ust-temp);
  // расчет выходной мощности:
  p=65.0*e;//130 коффициент пропорциональности 130.0
  if (p<0.0)
  {
    p=0.0;//ограничение P
  }
  i=(i+(e*0.014));//0.7
   if (i>100.0)
  {
    i=100.0;//ограничение I
  } 
     if (i<-100.0)
  {
    i=-50.0;//ограничение I
  } 
  //расчет выходной мощности
  zad=p+i;
  }
  //ограничение управляющего сигнала
  //для исключения частого переключения реле
  //если твердотельное реле, можно не ограничивать
  if (zad<4){
    zad=0;
  }
  if (zad>96){
    zad=100;
  }
//корректировка при отклонении температуры более чем на +-2С
//для быстрого выхода на уставку
  if (temp<(ust-2.0))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    i=0;
  }
  if (temp>(ust+2.0))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    i=0;
  }
}

 

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Roman2344 пишет:

Есть вопросы по вашему ПИ - регулятору, ноль мы не отслеживаем, правильно?

Далее интересует #define n_f 10.0//температура по умолчанию

#define t_pwm 60000//период 100% мощности      откуда взялось 60000?
#define t_time 1000//период опроса температуры   а если с аналогового температурного датчика брать 
нужна эта задержка, для чего вы её брали для терморезистора?
int zad=0;  это задание нужной уставки?
 
 
Если симистор стоит, это можно вообще убрать со скетча?
if (p<0.0)
  {
    p=0.0;//ограничение P
  }
  i=(i+(e*0.014));//0.7
   if (i>100.0)
  {
    i=100.0;//ограничение I
  } 
     if (i<-100.0)
  {
    i=-50.0;//ограничение I
  } 
  //расчет выходной мощности
  zad=p+i;
  }
  //ограничение управляющего сигнала
  //для исключения частого переключения реле
  //если твердотельное реле, можно не ограничивать
 
Что за числа?
 
if (zad<4){
    zad=0;
  }
  if (zad>96){
    zad=100;
  }
 
И откуда взялось ШИМ именно 2Гц?

n_f 10.0 - обозвал от no frost (защита от заморозки), при включении девайса выставляется температура 10С.

t_pwm 60000 - это 1 минута в милисекундах (взята за 100% т.е. цикл длится 1 мин, если весь цикл реле замкнуто то выдали 100%, если замкнуто 30 сек. то выдали 50% и т.д.

Получаеться период PWM - 1мин, а скважность пропорциональна мощности.

t_time 1000 - период опроса датчика температуры каждую секунду.

zad - это задание мощности

Эта часть кода ограничивает управляющее воздействие и не зависит от исполнительного устройства

 if (p<0.0)//мощность не может быть отрицательной
  {
    p=0.0;//ограничение P 
  }
  i=(i+(e*0.014));//вычисление интегральной составляющей
   if (i>100.0)
  {
    i=100.0;//ограничение I сверху
  } 
     if (i<-100.0)
  {
    i=-50.0;//ограничение I снизу
  } 
  //расчет выходной мощности
  zad=p+i;//задание равно сумме пропорциональной составляющей и интегральной
  }

Эта часть кода ограничивает управляющее воздействие для реле, т.к. 60000мс / 100% = 600мс/% = 0.6сек/%.

Чтобы реле при крайних значениях расчитанной мощности не щелкало чаще чем 4*600мс = 2.4сек. (для симистора этоу часть можно выкинуть)

 if (zad<4){//если мощность < 4% или 2.4 сек
    zad=0;//то вообщее не включаем
  }
  if (zad>96){//если мощность >96% или 57.6 (а у нас цикл 60сек)
    zad=100;//то не выключаем
  }

 

Roman2344
Offline
Зарегистрирован: 09.09.2015

Спасибо, буду разбираться, а какая переменная для задания уставки температуры?

Roman2344
Offline
Зарегистрирован: 09.09.2015

t_pwm 60000 - это 1 минута в милисекундах (взята за 100% т.е. цикл длится 1 мин, если весь цикл реле замкнуто то выдали 100%, если замкнуто 30 сек. то выдали 50% и т.д.

А не сильно много аж 1минута? Ведь для инерционной системы, если я ТЭН включу на 1минуту, то он у меня градусов на 40 вверх уползёт, а или это 1минута типа как разогрев, когда ТЭН или обогреватель холодный то 100% мощности 1минуту даётся, а потом регулируется ШИМом в зависимости от температуры меняется скважность?

 p=65.0*e;//130 коэффициент пропорциональности 130.0   Откуда взялось 65, и чему равно е? И как я понял этим коэффициентом (числом 65 или другим)подбираем нужную нам пропорцию в зависимости от инерционности нашего ТЭНа?

И для чего это:

float addr[25][2] = {
  {
    0,32.0                                                              
  }
  ,
  {
    5,25.5                                                              
  }
  ,
  {
    10,20.0                                                              
  }
  ,
  {
    15,15.7                                                                
  }
  ,
  {
    20,12.62                                                                
  }
  ,
  {
    25,10.0                                                                
  }
  ,
  {
    30,8.24                                                                
  }
  ,
  {
    35,6.63                                                                
  }
  ,
  {
    40,5.41                                                                
  }
  ,
  {
    45,4.41                                                                
  }
  ,
  {
    50,3.62                                                                
  }
  ,
  {
    55,2.99                                                                
  }
  ,
  {
    60,2.48                                                                
  }
  ,
  {
    65,2.08                                                                
  }
  ,
  {
    70,1.75                                                                
  }
  ,
  {
    75,1.47                                                                
  }
  ,
  {
    80,1.258                                                                
  }
  ,
  {
    85,1.063                                                                
  }
  ,
  {
    90,0.905                                                                
  }
  ,
  {
    95,0.776                                                                
  }
  ,
  {
    100,0.669                                                                
  }
  ,
  {
    105,0.581                                                                
  }
  ,
  {
    110,0.505                                                                
  }
  ,
  {
    115,0.442                                                                
  }
  ,
  {
    120,0.387                                                                
  }
  ,
};

 

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Roman2344 пишет:

t_pwm 60000 - это 1 минута в милисекундах (взята за 100% т.е. цикл длится 1 мин, если весь цикл реле замкнуто то выдали 100%, если замкнуто 30 сек. то выдали 50% и т.д.

А не сильно много аж 1минута? Ведь для инерционной системы, если я ТЭН включу на 1минуту, то он у меня градусов на 60 вверх уползёт, а или это 1минута типа как разогрев, когда ТЭН или обогреватель холодный то 100% мощности 1минуту даётся, а потом регулируется ШИМом в зависимости от температуры меняется скважность?

 p=65.0*e;//130 коэффициент пропорциональности 130.0   Откуда взялось 65, и чему равно е? И как я понял этим коэффициентом (числом 65 или другим)подбираем нужную нам пропорцию в зависимости от инерционности нашего ТЭНа?

И для чего это:

float addr[25][2] = {
  {
    0,32.0                                                              
  }
  ,
  {
    5,25.5                                                              
  }
  ,
  {
    10,20.0                                                              
  }
  ,
  {
    15,15.7                                                                
  }
  ,
  {
    20,12.62                                                                
  }
  ,
  {
    25,10.0                                                                
  }
  ,
  {
    30,8.24                                                                
  }
  ,
  {
    35,6.63                                                                
  }
  ,
  {
    40,5.41                                                                
  }
  ,
  {
    45,4.41                                                                
  }
  ,
  {
    50,3.62                                                                
  }
  ,
  {
    55,2.99                                                                
  }
  ,
  {
    60,2.48                                                                
  }
  ,
  {
    65,2.08                                                                
  }
  ,
  {
    70,1.75                                                                
  }
  ,
  {
    75,1.47                                                                
  }
  ,
  {
    80,1.258                                                                
  }
  ,
  {
    85,1.063                                                                
  }
  ,
  {
    90,0.905                                                                
  }
  ,
  {
    95,0.776                                                                
  }
  ,
  {
    100,0.669                                                                
  }
  ,
  {
    105,0.581                                                                
  }
  ,
  {
    110,0.505                                                                
  }
  ,
  {
    115,0.442                                                                
  }
  ,
  {
    120,0.387                                                                
  }
  ,
};

В моём случае нет, т.к. у меня этот девайс управляет 1.5кВт нагревателем на 30м2 помещения, и управление теном по средствам реле. С симистором можно гораздо меньше (например 1 сек).

В коде есть корректировка быстрого выхода на уставку. Если разница между текущей температурой и заданой большая то управление в зависимости от знака или 100% или 0%.

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

р-коэффициент пропорциональности (влияет на скорость реакции), на 130 необращайте внимания, это пока подбирал как памятку написал.

е-это ошибка регулирования (разница между заданием и уставкой)

Почитайте тут

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Roman2344 пишет:

Спасибо, буду разбираться, а какая переменная для задания уставки температуры?

ust - уставка

Roman2344
Offline
Зарегистрирован: 09.09.2015

В моём случае нет, т.к. у меня этот девайс управляет 1.5кВт нагревателем на 30м2 помещения, и управление теном по средствам реле. С симистором можно гораздо меньше (например 1 сек).

Я же и смотрю то у вас время это 60с., то на другом сайте 6с.

В коде есть корректировка быстрого выхода на уставку. Если разница между текущей температурой и заданой большая то управление в зависимости от знака или 100% или 0%.

То есть t_pwm если и будет 1минуту, то даже если время 1минута не прошла но как только превысит уставку температуры то мощность на 0 упадёт? р-коэффициент пропорциональности (влияет на скорость реакции), на 130 необращайте внимания, это пока подбирал как памятку написал. Ну он же подбирается под каждую систему, или он приблизительно для всех одинаковый будет? 

 

ust - уставка

А почему она у вас в градусах задаётся, а не числом, ну допустим у меня 100градусов = 400, так как опорное напряжение меги 2,56В, АЦП 10битный(1023) 1023/2,56=0,4, а с датчика 1градус=10мВ, получается 100градусов =1000мВ=400, просто вопрос такой мне задавать эту уставку моим числом, или 100градусов писать?

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Я в посте #4 картинку вставил. Так вот растояние между импульсами это период = 100%, а продолжительность импульса это часть выдаваемой мощности от 100% соответственно.

Коэффициенты подбираються индивидуально.

Почитайте всётаки о  законах регулирования.

В чем получаете температуру (ваша цель - ust) в том и задавайте.

 

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

У Вас какой датчик температуры? Вы показания в каких еденицах получаете?

Необходимо для начала с датчика получить температуру в понятном виде (С)

затем сравнивать получиную температуру с уставкой.

Roman2344
Offline
Зарегистрирован: 09.09.2015

Спасибо огромное 

Последний пока вопрос насчёт того к чему это 

float addr[25][2] = {
  {
    0,32.0                                                              
  }
  ,
  {
    5,25.5                                                              
  }
  ,
  {
    10,20.0                                                              
  }
  ,
  {
    15,15.7                                                                
  }
  ,
  {
    20,12.62                                                                
  }
  ,
  {
    25,10.0                                                                
  }
  ,
  {
    30,8.24                                                                
  }
  ,
  {
    35,6.63                                                                
  }
  ,
  {
    40,5.41                                                                
  }
  ,
  {
    45,4.41                                                                
  }
  ,
  {
    50,3.62                                                                
  }
  ,
  {
    55,2.99                                                                
  }
  ,
  {
    60,2.48                                                                
  }
  ,
  {
    65,2.08                                                                
  }
  ,
  {
    70,1.75                                                                
  }
  ,
  {
    75,1.47                                                                
  }
  ,
  {
    80,1.258                                                                
  }
  ,
  {
    85,1.063                                                                
  }
  ,
  {
    90,0.905                                                                
  }
  ,
  {
    95,0.776                                                                
  }
  ,
  {
    100,0.669                                                                
  }
  ,
  {
    105,0.581                                                                
  }
  ,
  {
    110,0.505                                                                
  }
  ,
  {
    115,0.442                                                                
  }
  ,
  {
    120,0.387                                                                
  }
  ,
};

 

У Вас какой датчик температуры? Вы показания в каких еденицах получаете?

Необходимо для начала с датчика получить температуру в понятном виде (С)

затем сравнивать получиную температуру с уставкой.

 

Датчик аналоговый, естественно для СИ я задаю с учётоми опорного напржения и разрядности АЦП

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Roman2344 пишет:

Спасибо огромное 

Последний пока вопрос насчёт того к чему это 

float addr[25][2] = {
  {
    0,32.0                                                              
  }
  ,
  {
    5,25.5                                                              
  }
  ,
  {
    10,20.0                                                              
  }
  ,
  {
    15,15.7                                                                
  }
  ,
  {
    20,12.62                                                                
  }
  ,
  {
    25,10.0                                                                
  }
  ,
  {
    30,8.24                                                                
  }
  ,
  {
    35,6.63                                                                
  }
  ,
  {
    40,5.41                                                                
  }
  ,
  {
    45,4.41                                                                
  }
  ,
  {
    50,3.62                                                                
  }
  ,
  {
    55,2.99                                                                
  }
  ,
  {
    60,2.48                                                                
  }
  ,
  {
    65,2.08                                                                
  }
  ,
  {
    70,1.75                                                                
  }
  ,
  {
    75,1.47                                                                
  }
  ,
  {
    80,1.258                                                                
  }
  ,
  {
    85,1.063                                                                
  }
  ,
  {
    90,0.905                                                                
  }
  ,
  {
    95,0.776                                                                
  }
  ,
  {
    100,0.669                                                                
  }
  ,
  {
    105,0.581                                                                
  }
  ,
  {
    110,0.505                                                                
  }
  ,
  {
    115,0.442                                                                
  }
  ,
  {
    120,0.387                                                                
  }
  ,
};

 

У Вас какой датчик температуры? Вы показания в каких еденицах получаете?

Необходимо для начала с датчика получить температуру в понятном виде (С)

затем сравнивать получиную температуру с уставкой.

 

Датчик аналоговый, естественно для СИ я задаю с учётоми опорного напржения и разрядности АЦП

Это таблица соответствия темпратура С / сопротивление кОм

Roman2344
Offline
Зарегистрирован: 09.09.2015

Ясно, спасибо, значить удалю так как мне она не нужна.

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Roman2344 пишет:

Ясно, спасибо, значить удалю так как мне она не нужна.

Удачи.

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Код расчета мощности

void PIctl()
{
    if(temp>(ust-0.5)&&temp<(ust+0.5))//зона нечувствительности +-0,5C
  {
    zad=i;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
  float e;
  e=(ust-temp);//вычисление ошибки регулирования
  // расчет выходной мощности:
  p=65.0*e;//расчет пропорциональной состовляющей
  if (p<0.0)//мощность не может быть отрицательной
  {
    p=0.0;//ограничение P
  }
  i=(i+(e*0.014));//расчет интегральной составляющей = тепловым потерям
   if (i>100.0)//мощность не может быть больше 100%
  {
    i=100.0;//ограничение I
  } 
     if (i<-100.0)
  {
    i=-50.0;//ограничение I
  } 
  //расчет выходной мощности
  zad=p+i;
  }

  //ограничение управляющего сигнала
  //для исключения частого переключения реле
  //если твердотельное реле, можно не ограничивать
  if (zad<4){
    zad=0;
  }
  if (zad>96){
    zad=100;
  }

//корректировка при отклонении температуры более чем на +-2С
//для быстрого выхода на уставку
  if (temp<(ust-2.0))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    i=0;
  }
  if (temp>(ust+2.0))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    i=0;
  }
}

Если интересно последняя версия

И на последок ШИМ`ом можно регулировать постоянный ток, а печременный или пропуском полупериодов (т.к. в 1сек. проходит 100 полупериодов, то точность 1% или 10сек. точность 0.1%) или продолжительностью полупериода (отсчетом времени от начала прохождения переменного напряжения через 0 в течении одного полупериода)

Roman2344
Offline
Зарегистрирован: 09.09.2015

Это вроде как понятно, я не пойму почему тогда у вас 60с., это вроде как обычно же ШИМ берётся за секунду мощность от того открыт или закрыт ключ в этой 1с., а вы берёте это время не 1с., а аж 60с.? Через ноль не вариант так как не хочу детектор нуля лепить. И пин для управления ТЭНом, нужно брать те которые поддерживают ШИМ, или любой, всё таки здесь же не применяется функция ШИМ, а она сделана по функциям времени?

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

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

ШИМ на пине ардуино не получится применить для управления симистором, т.к. его частота выше в разы частоты питающей сети.

Надо делать следующее. Без детектора 0, взять период 1с-100полупериодов=100%. Если каждую секунду подавать управление на симитр в течении аремени пропорциональном необходимой мощности 1%-100мс.
Вобщем как у меня только масштаб времени меньше.

gena
Offline
Зарегистрирован: 04.11.2012

   Ознакомтесь с https://geektimes.ru/company/unwds/blog/271090/

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

gena пишет:

   Ознакомтесь с https://geektimes.ru/company/unwds/blog/271090/

Традиционная дилемма здесь — чем, собственно, коммутировать. Как убедились многие на своём печальном опыте, китайские реле не обладают должной надёжностью — при коммутации мощной индуктивной нагрузки контакты сильно искрят, и в один прекрасный момент могут попросту залипнуть. Приходится ставить два реле — второе для подстраховки на размыкание.

У человека ТЭН, а это не индуктивная нагрузка. И залипание контактов это проблемма не только китайских реле.

Вот этой простой схемы для управления ТЭНом достаточно и она контролирует включение нагрузки в момент прохождения нуля. Я её использовал, работает отлично.

Roman2344
Offline
Зарегистрирован: 09.09.2015

Всё работает спасибо огромное yul-i-an стабильность порядка +-3градуса.

 

Roman2344
Offline
Зарегистрирован: 09.09.2015

1

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Roman2344 пишет:

Всё работает спасибо огромное yul-i-an стабильность порядка +-3градуса.

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

Ну и конечно хочется фото или видео девайса посмотреть если есть.

Разброс температуры можно уменьшить подбором коэффициентов.

Roman2344
Offline
Зарегистрирован: 09.09.2015

Да в течении промежутка времени, то как всегда скобку не там поставил, вот и работало не так). ну а разброс в +-3градуса, как по мне лучше не придумаешь. Фото или видео, подумаю, как в корпус оформлю. 

Roman2344
Offline
Зарегистрирован: 09.09.2015

Может кто подскажет есть два бака и 4 ТЭНа каждый по 370Вт, 220В, два ТЭНа греют один бак, соответственно 2 другие ТЭНа второй бак, температура ТЭНов в режиме разогрева одинакова(ТЭНЫ подключены были по два на симистор, сейчас даже 4 повесил на один симистор, а разница в температуре ТЭНов первого бака и второго бака составляет 8градусов, соответственно и баки имеют разницу около 8 градусов, зато разница в сопротивлении ТЭНов всего лишь 2Ома, а это около 6Вт ) датчик температуры один стоит на ТЭНе который больше греется, как уровнять разницу, но что бы один датчик температурный был, можно как - то на вторые ТЭНы больше мощности выдавать?

Сейчас приблизительно такое:

  if (millis()>3000){
    if((millis()-on_time)>=t_pwm){//период ШИМ
      on_time=millis();
PIctl4();//расчет мощности

if(c<zad){
digitalWrite(outten,1);
digitalWrite(outten2,1);
}
else{
if (zad != 100){
digitalWrite(outten,0);
digitalWrite(outten2,0);
}
}
c=c+1;
if(c==100){
c=0;
//PIctl();
}
}
}

 

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Я тут класс писал для управления цифровым выходом, так вот в нем есть функция MyOut.blink(interval, long).


#include <DigOut.h>//подключаем библиотеку
DigOut outten(пин тена 1);//инициализация цифрового выхода на тен 1
DigOut outten2(пин тена 2);//инициализация цифрового выхода на тен 1

void setup() 
{  
}

void loop() {
  //Ваш основной код тут
  //передаем в функцию период и продолжительность
  //тут подготовка значений мощности для передачи на управление
  zad1=pwr(10)//на 10% больше
  zad1=pwr(0)//без изменений
  outten.blink(t_pwm, (t_pwm/100)*zad);//управление теном 1
  outten2.blink(t_pwm, (t_pwm/100)*zad2);//управление теном 2
}

byte pwr(int correct)
{
  int res = zad+correct;
  if(res>100){res=100;}
  if(res<0){res=0;}
  return res;
}

 

Roman2344
Offline
Зарегистрирован: 09.09.2015

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

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Выложте весь код посмотрим.

Roman2344
Offline
Зарегистрирован: 09.09.2015

Сейчас вот играю с этим куском, так как код большой

#define t_pwm 1000//период 100% мощности
#define t_time 100//период опроса температуры
float termo=A0;//  вход основного датчика температуры
//для ПИ регулятора
float ca,cb;

long time;//интервал замера температуры
long on_time=0;//для периода ШИМ
int zad=0;//задание мощности
float temp=0.0;//текущее значение температуры
float pre_temp=0.0;//предыдущее значение температуры
int cd=0;
int c=0;
int w=0;
int ce=0;//пройденые циклы мощности
float ust4=489;//температура средний режим=115
int outten = 9; 
int outten2 = 12; 
int rejim1 = 5; 
int rejim2 = 6; 
void setup() {
analogReference(INTERNAL2V56);
pinMode(outten, OUTPUT);
pinMode(outten2, OUTPUT);
pinMode(termo, INPUT);
pinMode(rejim1, INPUT);
pinMode(rejim2, INPUT);
}

void loop() {
  if (digitalRead(rejim1)==1){
if (millis()>3000){
    if((millis()-on_time)>=t_pwm){//период ШИМ
      on_time=millis();
PIctl4();//расчет мощности

if(c<zad){
digitalWrite(outten,1);
digitalWrite(outten2,1);
}
else{
if (zad != 100){
digitalWrite(outten,0);
digitalWrite(outten2,0);
}
}
c=c+1;
if(c==100){
c=0;
//PIctl();
}
}
}

}





else  if (digitalRead(rejim2)==1){
if (millis()>3000){
    if((millis()-on_time)>=t_pwm){//период ШИМ
      on_time=millis();
PIctl5();//расчет мощности

if(c<zad){
digitalWrite(outten,1);
digitalWrite(outten2,1);
}
else{
if (zad != 100){
digitalWrite(outten,0);
digitalWrite(outten2,0);
}
}
c=c+1;
if(c==100){
c=0;
//PIctl();
}
}
}

}













}








void PIctl4()
{
    if(temp>(ust4-2.12)&&temp<(ust4+2.12))//зона нечувствительности +-0,5C
  {
    zad=cb;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
  float cf;
  cf=(ust4-temp);//вычисление ошибки регулирования
  // расчет выходной мощности:
  ca=65.0*cf;//расчет пропорциональной состовляющей
  if (ca<0.0)//мощность не может быть отрицательной
  {
    ca=0.0;//ограничение P
  }
  cb=(cb+(cf*0.014));//расчет интегральной составляющей = тепловым потерям
   if (cb>100.0)//мощность не может быть больше 100%
  {
    cb=100.0;//ограничение I
  } 
     if (cb<-100.0)
  {
    cb=-50.0;//ограничение I
  } 
  //расчет выходной мощности
  zad=ca+cb;
  }

  //ограничение управляющего сигнала
  //для исключения частого переключения реле
  //если твердотельное реле, можно не ограничивать
  if (zad<4){
    zad=0;
  }
  if (zad>96){
    zad=100;
  }

//корректировка при отклонении температуры более чем на +-2С
//для быстрого выхода на уставку
  if (temp<(ust4-8.5))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    cb=0;
  }
  if (temp>(ust4+8.5))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    cb=0;
  }
}








void PIctl5()
{
    if(temp>(ust5-2.12)&&temp<(ust5+2.12))//зона нечувствительности +-0,5C
  {
    zad=cb;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
  float cf;
  cf=(ust5-temp);//вычисление ошибки регулирования
  // расчет выходной мощности:
  ca=65.0*cf;//расчет пропорциональной состовляющей
  if (ca<0.0)//мощность не может быть отрицательной
  {
    p=0.0;//ограничение P
  }
  cb=(cb+(cf*0.014));//расчет интегральной составляющей = тепловым потерям
   if (cb>100.0)//мощность не может быть больше 100%
  {
    cb=100.0;//ограничение I
  } 
     if (cb<-100.0)
  {
    cb=-50.0;//ограничение I
  } 
  //расчет выходной мощности
  zad=ca+cb;
  }

  //ограничение управляющего сигнала
  //для исключения частого переключения реле
  //если твердотельное реле, можно не ограничивать
  if (zad<4){
    zad=0;
  }
  if (zad>96){
    zad=100;
  }

//корректировка при отклонении температуры более чем на +-2С
//для быстрого выхода на уставку
  if (temp<(ust5-8.5))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    cb=0;
  }
  if (temp>(ust5+8.5))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    cb=0;
  }
}

 

oleg_kazakof
Offline
Зарегистрирован: 24.04.2015

Roman2344 пишет:

Может кто подскажет есть два бака и 4 ТЭНа каждый по 370Вт, 220В, два ТЭНа греют один бак, соответственно 2 другие ТЭНа второй бак, температура ТЭНов в режиме разогрева одинакова(ТЭНЫ подключены были по два на симистор, сейчас даже 4 повесил на один симистор, а разница в температуре ТЭНов первого бака и второго бака составляет 8градусов, соответственно и баки имеют разницу около 8 градусов, зато разница в сопротивлении ТЭНов всего лишь 2Ома, а это около 6Вт ) датчик температуры один стоит на ТЭНе который больше греется, как уровнять разницу, но что бы один датчик температурный был, можно как - то на вторые ТЭНы больше мощности выдавать?

Читал, читал, читал,     ПОСТ "0" и этот пост и так ничего и немогу понять, что Вы греете воду (125 Гр. ?????) или нефть ( нужно ~ 250 Гр.) или воздух ? . А что Вам мешает поставить второй датчик температуры на второй бак, и соответственно контролировать и регулировать температуру в баках. Какой об"ём бака, при мощьности тенов 370Вт. я, думаю литров 20. По моему опыту могу сказать бак 40л. термоизолирован 2 Тена по 1.5 Квт. подерживают температуру впределах +-0.5Гр. от заданной (жидкость), (ордуино(кристал ATMEL mega328p) + LM 335 + программа управления).

 

  

Roman2344
Offline
Зарегистрирован: 09.09.2015

Грею спиртосодержащую смесь, обьём каждого бака литра 2, использую ардуино мега + ТФТ дисплей 4дюйма, датчиков не хочу ставить несколько, так как возможно в дальнейшем будет 3, а может и 4 бака, что ж на каждый датчик ставить, у меня в коде ещё защита если с датчиком что не так, а это на каждый датчик такое делать, долго, это всё, в дальнейшем буду общий бак делать, и два ТЭНа на этот бак

Roman2344
Offline
Зарегистрирован: 09.09.2015

Вот набросал так, как думаете нормально будет?

#define t_pwm 1000//период 100% мощности
#define t_time 100//период опроса температуры
float termo=A0;//  вход основного датчика температуры
//для ПИ регулятора
float ca,cb;

long time;//интервал замера температуры
long on_time=0;//для периода ШИМ
int zad=0;//задание мощности ТЭНа1
int zad2=0;//задание мощности ТЭНа2
float temp=0.0;//текущее значение температуры
float pre_temp=0.0;//предыдущее значение температуры
int cd=0;
int c=0;
int w=0;
int ce=0;//пройденые циклы мощности
float ust4=489;//температура средний режим=115
float ust5=510;//температура средний режим=120
int outten = 9; 
int outten2 = 12; 
int rejim1 = 5; 
int rejim2 = 6; 
void setup() {
analogReference(INTERNAL2V56);
pinMode(outten, OUTPUT);
pinMode(outten2, OUTPUT);
pinMode(termo, INPUT);
pinMode(rejim1, INPUT);
pinMode(rejim2, INPUT);
}

void loop() {

  if (digitalRead(rejim1)==1){
if (millis()>3000){
    if((millis()-on_time)>=t_pwm){//период ШИМ
      on_time=millis();
PIctl4();//расчет мощности

if(c<zad){
 
digitalWrite(outten,1); 
zad2=zad+10;// даём zad2 > 10%
PIctl6();//расчет мощности с zad2
if(c<zad2){
digitalWrite(outten2,1);
}
}
else{
if (zad != 100){
digitalWrite(outten,0);
zad2=zad+10;// даём zad2 > 10%
PIctl6();
if(zad != 100){
digitalWrite(outten2,0);
}
}
}
c=c+1;
if(c==100){
c=0;
//PIctl();
}
}
}

}





else  if (digitalRead(rejim2)==1){
if (millis()>3000){
    if((millis()-on_time)>=t_pwm){//период ШИМ
      on_time=millis();
PIctl5();//расчет мощности

if(c<zad){
 
digitalWrite(outten,1); 
zad2=zad+10;// даём zad2 > 10%
PIctl6();//расчет мощности с zad2
if(c<zad2){
digitalWrite(outten2,1);
}
}
else{
if (zad != 100){
digitalWrite(outten,0);
zad2=zad+10;// даём zad2 > 10%
PIctl6();
if(zad != 100){
digitalWrite(outten2,0);
}
}
}
c=c+1;
if(c==100){
c=0;
//PIctl();
}
}
}

}













}








void PIctl4()
{
    if(temp>(ust4-2.12)&&temp<(ust4+2.12))//зона нечувствительности +-0,5C
  {
    zad=cb;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
  float cf;
  cf=(ust4-temp);//вычисление ошибки регулирования
  // расчет выходной мощности:
  ca=65.0*cf;//расчет пропорциональной состовляющей
  if (ca<0.0)//мощность не может быть отрицательной
  {
    ca=0.0;//ограничение P
  }
  cb=(cb+(cf*0.014));//расчет интегральной составляющей = тепловым потерям
   if (cb>100.0)//мощность не может быть больше 100%
  {
    cb=100.0;//ограничение I
  } 
     if (cb<-100.0)
  {
    cb=-50.0;//ограничение I
  } 
  //расчет выходной мощности
  zad=ca+cb;
  }

  //ограничение управляющего сигнала
  //для исключения частого переключения реле
  //если твердотельное реле, можно не ограничивать
  if (zad<4){
    zad=0;
  }
  if (zad>96){
    zad=100;
  }

//корректировка при отклонении температуры более чем на +-2С
//для быстрого выхода на уставку
  if (temp<(ust4-8.5))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    cb=0;
  }
  if (temp>(ust4+8.5))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    cb=0;
  }
}








void PIctl5()
{
    if(temp>(ust5-2.12)&&temp<(ust5+2.12))//зона нечувствительности +-0,5C
  {
    zad=cb;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
  float cf;
  cf=(ust5-temp);//вычисление ошибки регулирования
  // расчет выходной мощности:
  ca=65.0*cf;//расчет пропорциональной состовляющей
  if (ca<0.0)//мощность не может быть отрицательной
  {
    ca=0.0;//ограничение P
  }
  cb=(cb+(cf*0.014));//расчет интегральной составляющей = тепловым потерям
   if (cb>100.0)//мощность не может быть больше 100%
  {
    cb=100.0;//ограничение I
  } 
     if (cb<-100.0)
  {
    cb=-50.0;//ограничение I
  } 
  //расчет выходной мощности
  zad=ca+cb;
  }

  //ограничение управляющего сигнала
  //для исключения частого переключения реле
  //если твердотельное реле, можно не ограничивать
  if (zad<4){
    zad=0;
  }
  if (zad>96){
    zad=100;
  }

//корректировка при отклонении температуры более чем на +-2С
//для быстрого выхода на уставку
  if (temp<(ust5-8.5))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    cb=0;
  }
  if (temp>(ust5+8.5))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    cb=0;
  }
}











void PIctl6()
{
    if(temp>(ust6-2.12)&&temp<(ust6+2.12))//зона нечувствительности +-0,5C
  {
    zad2=cb;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
  float cf;
  cf=(ust6-temp);//вычисление ошибки регулирования
  // расчет выходной мощности:
  ca=65.0*cf;//расчет пропорциональной состовляющей
  if (ca<0.0)//мощность не может быть отрицательной
  {
    ca=0.0;//ограничение P
  }
  cb=(cb+(cf*0.014));//расчет интегральной составляющей = тепловым потерям
   if (cb>100.0)//мощность не может быть больше 100%
  {
    cb=100.0;//ограничение I
  } 
     if (cb<-100.0)
  {
    cb=-50.0;//ограничение I
  } 
  //расчет выходной мощности
  zad2=ca+cb;
  }

  //ограничение управляющего сигнала
  //для исключения частого переключения реле
  //если твердотельное реле, можно не ограничивать
  if (zad2<4){
    zad2=0;
  }
  if (zad2>96){
    zad2=100;
  }

//корректировка при отклонении температуры более чем на +-2С
//для быстрого выхода на уставку
  if (temp<(ust6-8.5))//если темп < уст на 2С
  {
    zad2=100;//то мощность 100%
    cb=0;
  }
  if (temp>(ust6+8.5))//если темп > уст на 2С
  {
    zad2=0;//то мощность 0%
    cb=0;
  }
}

 

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Вот эта часть кода повторяеться. Её нужно преобразовать в функцию которая будет возвращать мощность

void PIctl6()
{
    if(temp>(ust6-2.12)&&temp<(ust6+2.12))//зона нечувствительности +-0,5C
  {
    zad2=cb;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
  float cf;
  cf=(ust6-temp);//вычисление ошибки регулирования
  // расчет выходной мощности:
  ca=65.0*cf;//расчет пропорциональной состовляющей
  if (ca<0.0)//мощность не может быть отрицательной
  {
    ca=0.0;//ограничение P
  }
  cb=(cb+(cf*0.014));//расчет интегральной составляющей = тепловым потерям
   if (cb>100.0)//мощность не может быть больше 100%
  {
    cb=100.0;//ограничение I
  } 
     if (cb<-100.0)
  {
    cb=-50.0;//ограничение I
  } 
  //расчет выходной мощности
  zad2=ca+cb;
  }

  //ограничение управляющего сигнала
  //для исключения частого переключения реле
  //если твердотельное реле, можно не ограничивать
  if (zad2<4){
    zad2=0;
  }
  if (zad2>96){
    zad2=100;
  }

//корректировка при отклонении температуры более чем на +-2С
//для быстрого выхода на уставку
  if (temp<(ust6-8.5))//если темп < уст на 2С
  {
    zad2=100;//то мощность 100%
    cb=0;
  }
  if (temp>(ust6+8.5))//если темп > уст на 2С
  {
    zad2=0;//то мощность 0%
    cb=0;
  }
}

Вынести за loop

byte PIctl(float temp, float u,int zad)
{
    if(temp>(u-2.12)&&temp<(u+2.12))//зона нечувствительности +-0,5C
  {
    zad=cb;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
  float cf;
  cf=(u-temp);//вычисление ошибки регулирования
  // расчет выходной мощности:
  ca=65.0*cf;//расчет пропорциональной состовляющей
  if (ca<0.0)//мощность не может быть отрицательной
  {
    ca=0.0;//ограничение P
  }
  cb=(cb+(cf*0.014));//расчет интегральной составляющей = тепловым потерям
   if (cb>100.0)//мощность не может быть больше 100%
  {
    cb=100.0;//ограничение I
  } 
     if (cb<-100.0)
  {
    cb=-50.0;//ограничение I
  } 
  //расчет выходной мощности
  zad=ca+cb;
  }

  //ограничение управляющего сигнала
  //для исключения частого переключения реле
  //если твердотельное реле, можно не ограничивать
  if (zad<4){
    zad=0;
  }
  if (zad>96){
    zad=100;
  }

//корректировка при отклонении температуры более чем на +-2С
//для быстрого выхода на уставку
  if (temp<(u-8.5))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    cb=0;
  }
  if (temp>(u+8.5))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    cb=0;
  }
  return zad;
}
oleg_kazakof
Offline
Зарегистрирован: 24.04.2015

Roman2344 пишет:

Грею спиртосодержащую смесь, обьём каждого бака литра 2, использую ардуино мега + ТФТ дисплей 4дюйма, датчиков не хочу ставить несколько, так как возможно в дальнейшем будет 3, а может и 4 бака, что ж на каждый датчик ставить, у меня в коде ещё защита если с датчиком что не так, а это на каждый датчик такое делать, долго, это всё, в дальнейшем буду общий бак делать, и два ТЭНа на этот бак

А как Вы нагревали спитросодержащую смесь больще 100Гр. ( это возможно только под давлением),( Вы пишете----- у меня в коде защита если с датчиком что не так, а это на каждый датчик такое делать, долго, ----------- )это пара строк кода -  функция и её вызов. А как происходит проверка если с датчиком что не так ???. Если это самагоноварение то могу сказать что у меня в системе для получения качественного продукта (бак 40л.) установленно 3 датчика тепрературы и 2 датчика давления. На этом форуме есть тема - ГОНЬЩИК САМОГОНЬЩИК- правда сейчас там много флуда.

 

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Предлогаю Вам с 0 написать код коректней, но для этого изложите тз.

Допустим, греем бак двумя тенами на выходах №№

при нажатии кнопки на входе №, изменяеться уставка (100, 125, 80, 150) примерно

...

Ну и в таком духе.

Roman2344
Offline
Зарегистрирован: 09.09.2015

Вот, по крайней мере скомпилировалось, нужно конечно осцил прилепить или светодиоды посмотреть по разным выводам по разному или нет

#include <DigOut.h>//подключаем библиотеку

#define t_pwm 1000//период 100% мощности
#define t_time 100//период опроса температуры
DigOut outten(9);//инициализация цифрового выхода на тен 1
DigOut outten2(12);//инициализация цифрового выхода на тен 2
float termo=A0;//  вход основного датчика температуры
//для ПИ регулятора
float ca,cb;

long time;//интервал замера температуры
long on_time=0;//для периода ШИМ
int zad=0;//задание мощности ТЭНа1
int zad2=0;//задание мощности ТЭНа2
float temp=0.0;//текущее значение температуры
float pre_temp=0.0;//предыдущее значение температуры
int cd=0;
int c=0;
int w=0;
int ce=0;//пройденые циклы мощности
float ust4=489;//температура средний режим=115
float ust5=510;//температура средний режим=120
int rejim1 = 5; 
int rejim2 = 6; 
void setup() {
analogReference(INTERNAL2V56);
pinMode(outten, OUTPUT);
pinMode(outten2, OUTPUT);
pinMode(termo, INPUT);
pinMode(rejim1, INPUT);
pinMode(rejim2, INPUT);
}

void loop() {

  if (digitalRead(rejim1)==1){
if (millis()>3000){
    if((millis()-on_time)>=t_pwm){//период ШИМ
      on_time=millis();
zad=pwr(0);//без изменений
zad2=pwr(10);//на 10% больше
PIctl4();//расчет мощности


 
if(c<zad){
 outten.blink(t_pwm, (t_pwm/100)*zad);//управление теном 1
  outten2.blink(t_pwm, (t_pwm/100)*zad2);//управление теном 2
}
else{
if (zad != 100){
DigOut outten(9,0);//выключить тен 1
DigOut outten2(12,0);//выключить тен 2
}
}
c=c+1;
if(c==100){
c=0;
//PIctl();
}
}
}

}





else  if (digitalRead(rejim2)==1){
if (millis()>3000){
    if((millis()-on_time)>=t_pwm){//период ШИМ
      on_time=millis();
zad=pwr(0);//без изменений
zad2=pwr(10);//на 10% больше
PIctl5();//расчет мощности

if(c<zad){
 outten.blink(t_pwm, (t_pwm/100)*zad);//управление теном 1
  outten2.blink(t_pwm, (t_pwm/100)*zad2);//управление теном 2
}
else{
if (zad != 100){
DigOut outten(9,0);//выключить тен 1
DigOut outten2(12,0);//выключить тен 2
}
}
c=c+1;
if(c==100){
c=0;
//PIctl();
}
}
}

}













}








void PIctl4()
{
    if(temp>(ust4-2.12)&&temp<(ust4+2.12))//зона нечувствительности +-0,5C
  {
    zad=cb;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
  float cf;
  cf=(ust4-temp);//вычисление ошибки регулирования
  // расчет выходной мощности:
  ca=65.0*cf;//расчет пропорциональной состовляющей
  if (ca<0.0)//мощность не может быть отрицательной
  {
    ca=0.0;//ограничение P
  }
  cb=(cb+(cf*0.014));//расчет интегральной составляющей = тепловым потерям
   if (cb>100.0)//мощность не может быть больше 100%
  {
    cb=100.0;//ограничение I
  } 
     if (cb<-100.0)
  {
    cb=-50.0;//ограничение I
  } 
  //расчет выходной мощности
  zad=ca+cb;
  }

  //ограничение управляющего сигнала
  //для исключения частого переключения реле
  //если твердотельное реле, можно не ограничивать
  if (zad<4){
    zad=0;
  }
  if (zad>96){
    zad=100;
  }

//корректировка при отклонении температуры более чем на +-2С
//для быстрого выхода на уставку
  if (temp<(ust4-8.5))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    cb=0;
  }
  if (temp>(ust4+8.5))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    cb=0;
  }
}








void PIctl5()
{
    if(temp>(ust5-2.12)&&temp<(ust5+2.12))//зона нечувствительности +-0,5C
  {
    zad=cb;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
  float cf;
  cf=(ust5-temp);//вычисление ошибки регулирования
  // расчет выходной мощности:
  ca=65.0*cf;//расчет пропорциональной состовляющей
  if (ca<0.0)//мощность не может быть отрицательной
  {
    ca=0.0;//ограничение P
  }
  cb=(cb+(cf*0.014));//расчет интегральной составляющей = тепловым потерям
   if (cb>100.0)//мощность не может быть больше 100%
  {
    cb=100.0;//ограничение I
  } 
     if (cb<-100.0)
  {
    cb=-50.0;//ограничение I
  } 
  //расчет выходной мощности
  zad=ca+cb;
  }

  //ограничение управляющего сигнала
  //для исключения частого переключения реле
  //если твердотельное реле, можно не ограничивать
  if (zad<4){
    zad=0;
  }
  if (zad>96){
    zad=100;
  }

//корректировка при отклонении температуры более чем на +-2С
//для быстрого выхода на уставку
  if (temp<(ust5-8.5))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    cb=0;
  }
  if (temp>(ust5+8.5))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    cb=0;
  }
}




byte pwr(int correct)
{
  int res = zad+correct;
  if(res>100){res=100;}
  if(res<0){res=0;}
  return res;
}

 

Roman2344
Offline
Зарегистрирован: 09.09.2015

И вопрос такой работая с библиотекой DigOut.h, нужно в сетапе 

pinMode(outten, OUTPUT);

pinMode(outten2, OUTPUT);
или нет?
yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Сейчас подправлю

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

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

#include <DigOut.h>//подключаем библиотеку
#define t_time 100//период опроса температуры
DigOut outten(9);//инициализация цифрового выхода на тен 1
DigOut outten2(12);//инициализация цифрового выхода на тен 2
#define termo A0;//  вход основного датчика температуры
unsigned long time;//интервал замера температуры
unsigned long on_time=0;//для периода ШИМ
byte zad=0;//задание мощности ТЭНа1
byte zad2=0;//задание мощности ТЭНа2
float temp=0.0;//текущее значение температуры
float pre_temp=0.0;//предыдущее значение температуры
#define t_pwm 1000//период ШИМ 1сек
#define ust4 489//температура средний режим=115
#define ust5 510//температура средний режим=120
#define rejim1 5 
#define rejim2 6 

void setup() {
  analogReference(INTERNAL);
  pinMode(rejim1, INPUT);
  pinMode(rejim2, INPUT);
}

void loop() {
  static float ust=20;//уставка при включении
  if (digitalRead(rejim1)==1){
    ust=ust4;
  }
  if (digitalRead(rejim2)==1){
    ust=ust5;
  }  
  zad=PIctl(ust);//расчет мощности
  zad=pwr(zad,0);//корректировка мощности
  zad2=PIctl(ust);//расчет мощности
  zad2=pwr(zad2,0);//корректировка мощности
  if (millis()>3000){//разрешаем управление нагрузкой через 3 сек после включения
    outten.blink(t_pwm, (t_pwm/100)*zad);//управление теном 1
    outten2.blink(t_pwm, (t_pwm/100)*zad2);//управление теном 2
  }
}

//расчет мощности
byte PIctl(float ust)
{
  float ca,cb;
  if(temp>(ust-2.12)&&temp<(ust+2.12))//зона нечувствительности +-0,5C
  {
    zad=cb;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
    float cf;
    cf=(ust-temp);//вычисление ошибки регулирования
    // расчет выходной мощности:
    ca=(65.0*cf);//расчет пропорциональной состовляющей
    if (ca<0.0)//мощность не может быть отрицательной
    {
      ca=0.0;//ограничение P
    }
    cb=(cb+(cf*0.014));//расчет интегральной составляющей = тепловым потерям
    if (cb>100.0)//мощность не может быть больше 100%
    {
      cb=100.0;//ограничение I
    } 
    if (cb<-100.0)
    {
      cb=-50.0;//ограничение I
    } 
    //расчет выходной мощности
    zad=ca+cb;
  }

  //корректировка при отклонении температуры более чем на +-2С
  //для быстрого выхода на уставку
  if (temp<(ust4-8.5))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    cb=0;
  }
  if (temp>(ust4+8.5))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    cb=0;
  }
}

byte pwr(int zad, int correct)
{
  int res = zad+correct;
  if(res>100){
    res=100;
  }
  if(res<0){
    res=0;
  }
  else
  {
    res=zad;
  }
  return res;
}

 

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Roman2344 пишет:

И вопрос такой работая с библиотекой DigOut.h, нужно в сетапе 

pinMode(outten, OUTPUT);

pinMode(outten2, OUTPUT);
или нет?

НЕТ

Roman2344
Offline
Зарегистрирован: 09.09.2015

Спасибо огромное, с меня причитается, если вы с Украины, давайте хотя бы сотку на тел. скину, или переведу на карту.

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


#include <DigOut.h>//подключаем библиотеку
#define t_time 100//период опроса температуры
DigOut outten(9);//инициализация цифрового выхода на тен 1
DigOut outten2(12);//инициализация цифрового выхода на тен 2
#define termo A0;//  вход основного датчика температуры
unsigned long time;//интервал замера температуры
unsigned long on_time=0;//для периода ШИМ
byte zad=0;//задание мощности ТЭНа1
byte zad2=0;//задание мощности ТЭНа2
float temp=0.0;//текущее значение температуры
float pre_temp=0.0;//предыдущее значение температуры
#define t_pwm 1000//период ШИМ 1сек
#define ust4 489//температура средний режим=115
#define ust5 510//температура средний режим=120
#define rejim1 5 
#define rejim2 6 

void setup() {
  analogReference(INTERNAL2V56);
  pinMode(rejim1, INPUT);
  pinMode(rejim2, INPUT);
}

void loop() {
  static float ust=20;//уставка при включении
  if (digitalRead(rejim1)==1){
    ust=ust4;
  }
  if (digitalRead(rejim2)==1){
    ust=ust5;
  }  
 if ((millis()-time)>=t_time){
    time=millis();
    temp=analogRead(termo);//получаем температуру
    temp=(pre_temp*0.2)+(temp*0.8);//фильтр
    //   w=abs((ust-temp)*(pre_temp-temp));//время выхода на уставку
    pre_temp=temp;}

  zad=PIctl(ust);//расчет мощности
  zad=pwr(zad,0);//корректировка мощности
  zad2=PIctl(ust);//расчет мощности
  zad2=pwr(zad2,0);//корректировка мощности
  if (millis()>3000){//разрешаем управление нагрузкой через 3 сек после включения
    outten.blink(t_pwm, (t_pwm/100)*zad);//управление теном 1
    outten2.blink(t_pwm, (t_pwm/100)*zad2);//управление теном 2
  }
}

//расчет мощности
byte PIctl(float ust)
{
  float ca,cb;
  if(temp>(ust-2.12)&&temp<(ust+2.12))//зона нечувствительности +-0,5C
  {
    zad=cb;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
    float cf;
    cf=(ust-temp);//вычисление ошибки регулирования
    // расчет выходной мощности:
    ca=(65.0*cf);//расчет пропорциональной состовляющей
    if (ca<0.0)//мощность не может быть отрицательной
    {
      ca=0.0;//ограничение P
    }
    cb=(cb+(cf*0.014));//расчет интегральной составляющей = тепловым потерям
    if (cb>100.0)//мощность не может быть больше 100%
    {
      cb=100.0;//ограничение I
    } 
    if (cb<-100.0)
    {
      cb=-50.0;//ограничение I
    } 
    //расчет выходной мощности
    zad=ca+cb;
  }

  //корректировка при отклонении температуры более чем на +-2С
  //для быстрого выхода на уставку
  if (temp<(ust4-8.5))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    cb=0;
  }
  if (temp>(ust4+8.5))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    cb=0;
  }
}

byte pwr(int zad, int correct)
{
  int res = zad+correct;
  if(res>100){
    res=100;
  }
  if(res<0){
    res=0;
  }
  else
  {
    res=zad;
  }
  return res;
}




  

 

  
 
yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Нашел некоторые ошибки подправил

//СПАСИБО можно СЮДА money.yandex.ru/to/41001603404940

#include <DigOut.h>//подключаем библиотеку
#define t_time 100//период опроса температуры
DigOut outten(9);//инициализация цифрового выхода на тен 1
DigOut outten2(12);//инициализация цифрового выхода на тен 2
#define termo A0//вход основного датчика температуры
unsigned long preTempMillis=0;//для опроса температуры
unsigned long time;//интервал замера температуры
unsigned long on_time=0;//для периода ШИМ
byte zad=0;//задание мощности ТЭНа1
byte zad2=0;//задание мощности ТЭНа2
float temp=0.0;//текущее значение температуры
float pre_temp=0.0;//предыдущее значение температуры
#define t_pwm 1000//период ШИМ в мс
#define ust4 489//температура средний режим=115
#define ust5 510//температура средний режим=120
#define rejim1 5 
#define rejim2 6 

void setup() {
  analogReference(INTERNAL);
  pinMode(rejim1, INPUT);
  pinMode(rejim2, INPUT);
}

void loop() {
  unsigned long currentMillis=millis();
  if(currentMillis-preTempMillis>=t_time){
    temp=analogRead(termo);//получаем температуру
    //а тут неплохобы в градусы целсия перевести
    //temp=temp/4.25;
    temp=(pre_temp*0.2)+(temp*0.8);//фильтр
    pre_temp=temp;
    preTempMillis=currentMillis;
  }

  static float ust=20;//уставка при включении
  if (digitalRead(rejim1)==1){
    ust=ust4;
  }
  if (digitalRead(rejim2)==1){
    ust=ust5;
  }  
  zad=PIctl(temp, ust);//расчет мощности
  zad=pwr(zad,0);//корректировка мощности
  zad2=PIctl(temp, ust);//расчет мощности
  zad2=pwr(zad2,0);//корректировка мощности
  if (millis()>3000){//разрешаем управление нагрузкой через 3 сек после включения
    outten.blink(t_pwm, (t_pwm/100)*zad);//управление теном 1
    outten2.blink(t_pwm, (t_pwm/100)*zad2);//управление теном 2
  }
}

//расчет мощности
byte PIctl(float temp, float ust)
{
  static float p, i;
  if(temp>(ust-2.12)&&temp<(ust+2.12))//зона нечувствительности +-0,5C
  {
    zad=i;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
    float e;
    e=(ust-temp);//вычисление ошибки регулирования
    // расчет выходной мощности:
    p=(65.0*e);//расчет пропорциональной состовляющей
    if (p<0.0)//мощность не может быть отрицательной
    {
      p=0.0;//ограничение P
    }
    i=(i+(e*0.014));//расчет интегральной составляющей = тепловым потерям
    if (i>100.0)//мощность не может быть больше 100%
    {
      i=100.0;//ограничение I
    } 
    if (i<-100.0)
    {
      i=-50.0;//ограничение I
    } 
    //расчет выходной мощности
    zad=p+i;
  }

  //корректировка при отклонении температуры более чем на +-2С
  //для быстрого выхода на уставку
  if (temp<(ust-8.5))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    i=0;
  }
  if (temp>(ust+8.5))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    i=0;
  }
}

byte pwr(int zad, int correct)
{
  int res = zad+correct;
  if(res>100){
    res=100;
  }
  if(res<0){
    res=0;
  }
  else
  {
    res=zad;
  }
  return res;
}

Тестируйте.

 

 

Roman2344
Offline
Зарегистрирован: 09.09.2015

Спасибо, проверю всё и отпишусь.

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

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

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

//СПАСИБО можно СЮДА money.yandex.ru/to/41001603404940

#include <DigIn.h>//подключаем библиотеку входов yadi.sk/d/7tGp_zlVsBt7s
#include <DigOut.h>//подключаем библиотеку выходов yadi.sk/d/NM4S6HmFrTRu6
#define t_time 100//период опроса температуры
DigOut outten(9), outten2(12);//инициализация цифровых выходов на тен 1 и 2
DigIn rejim1(5,1), rejim2 (6,1);//инициализация цифровых входов
#define termo A0//вход основного датчика температуры
unsigned long preTempMillis=0;//для опроса температуры
byte zad=0;//задание мощности ТЭНа1
byte zad2=0;//задание мощности ТЭНа2
float temp=0.0;//текущее значение температуры
float pre_temp=0.0;//предыдущее значение температуры
#define t_pwm 1000//период ШИМ в мс
#define ust4 489//температура средний режим=115
#define ust5 510//температура средний режим=120

void setup() {
  analogReference(INTERNAL);
}

void loop() {
  unsigned long currentMillis=millis();
  if(currentMillis-preTempMillis>=t_time){
    temp=analogRead(termo);//получаем температуру
    //а тут неплохобы в градусы целсия перевести
    //temp=temp/4.25;
    temp=(pre_temp*0.2)+(temp*0.8);//фильтр
    pre_temp=temp;
    preTempMillis=currentMillis;
  }

  static float ust=20;//уставка при включении
  if (rejim1.valid(currentMillis)){//если нажата rejim1
    ust=ust4;
  }
  if (rejim2.valid(currentMillis)){//если нажата rejim2
    ust=ust5;
  }  
  zad=PIctl(temp, ust);//расчет мощности
  zad=pwr(zad,0);//корректировка мощности
  zad2=PIctl(temp, ust);//расчет мощности
  zad2=pwr(zad2,0);//корректировка мощности
  if (millis()>3000){//разрешаем управление нагрузкой через 3 сек после включения
    outten.blink(t_pwm, (t_pwm/100)*zad);//управление теном 1
    outten2.blink(t_pwm, (t_pwm/100)*zad2);//управление теном 2
  }
}//END loop

//расчет мощности
byte PIctl(float temp, float ust)
{
  static float p, i;
  if(temp>(ust-2.12)&&temp<(ust+2.12))//зона нечувствительности +-0,5C
  {
    zad=i;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
    float e;
    e=(ust-temp);//вычисление ошибки регулирования
    // расчет выходной мощности:
    p=(65.0*e);//расчет пропорциональной состовляющей
    if (p<0.0)//мощность не может быть отрицательной
    {
      p=0.0;//ограничение P
    }
    i=(i+(e*0.014));//расчет интегральной составляющей = тепловым потерям
    if (i>100.0)//мощность не может быть больше 100%
    {
      i=100.0;//ограничение I
    } 
    if (i<-100.0)
    {
      i=-50.0;//ограничение I
    } 
    //расчет выходной мощности
    zad=p+i;
  }

  //корректировка при отклонении температуры более чем на +-2С
  //для быстрого выхода на уставку
  if (temp<(ust-8.5))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    i=0;
  }
  if (temp>(ust+8.5))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    i=0;
  }
}

byte pwr(int zad, int correct)
{
  int res = zad+correct;
  if(res>100){
    res=100;
  }
  if(res<0){
    res=0;
  }
  else
  {
    res=zad;
  }
  return res;
}

 

Roman2344
Offline
Зарегистрирован: 09.09.2015

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

static unsigned long millis_prev1;

  if(millis()-100 > millis_prev1) 

  millis_prev1 = millis();  

 

+ кондёры 0,1мкФ, хоть и функция милис говорят и не работает в обработчике прерываний, но все почему - то её там используют.

Roman2344
Offline
Зарегистрирован: 09.09.2015

Вгрузил ничего не работает, сейчас даже такой кусок пробую ничего вообще, буду наверно осцилом глядеть


#include <DigOut.h>//подключаем библиотеку выходов yadi.sk/d/NM4S6HmFrTRu6
#define t_time 100//период опроса температуры
DigOut outten(9), outten2(12);//инициализация цифровых выходов на тен 1 и 2
#define termo A0//вход основного датчика температуры
unsigned long time;//интервал замера температуры
byte zad=0;//задание мощности ТЭНа1
byte zad2=0;//задание мощности ТЭНа2
float temp=0.0;//текущее значение температуры
float pre_temp=0.0;//предыдущее значение температуры
unsigned long preTempMillis=0;//для опроса температуры
float ust=0;
#define t_pwm 1000//период ШИМ в мс
#define ust4 489//температура средний режим=115


void setup() {
  analogReference(INTERNAL2V56);
  
}

void loop() {
  unsigned long currentMillis=millis();
  if(currentMillis-preTempMillis>=t_time){
    temp=analogRead(termo);//получаем температуру
    //а тут неплохобы в градусы целсия перевести
    //temp=temp/4.25;
    temp=(pre_temp*0.2)+(temp*0.8);//фильтр
    pre_temp=temp;
    preTempMillis=currentMillis;
  }

 
 
    ust=ust4;
  
  zad=PIctl(temp, ust);//расчет мощности
  zad=pwr(zad,0);//корректировка мощности
  zad2=PIctl(temp, ust);//расчет мощности
  zad2=pwr(zad2,10);//корректировка мощности
  if (millis()>3000){//разрешаем управление нагрузкой через 3 сек после включения
    outten.blink(t_pwm, (t_pwm/100)*zad);//управление теном 1
    outten2.blink(t_pwm, (t_pwm/100)*zad2);//управление теном 2
  }
}//END loop

//расчет мощности
byte PIctl(float temp, float ust)
{
  static float p, i;
  if(temp>(ust-2.12)&&temp<(ust+2.12))//зона нечувствительности +-0,5C
  {
    zad=i;//если ошибка+-0.5С то мощность = И состовляющей
  }
  else//иначе
  {
    float e;
    e=(ust-temp);//вычисление ошибки регулирования
    // расчет выходной мощности:
    p=(65.0*e);//расчет пропорциональной состовляющей
    if (p<0.0)//мощность не может быть отрицательной
    {
      p=0.0;//ограничение P
    }
    i=(i+(e*0.014));//расчет интегральной составляющей = тепловым потерям
    if (i>100.0)//мощность не может быть больше 100%
    {
      i=100.0;//ограничение I
    } 
    if (i<-100.0)
    {
      i=-50.0;//ограничение I
    } 
    //расчет выходной мощности
    zad=p+i;
  }

  //корректировка при отклонении температуры более чем на +-2С
  //для быстрого выхода на уставку
  if (temp<(ust-8.5))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    i=0;
  }
  if (temp>(ust+8.5))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    i=0;
  }
}

byte pwr(int zad, int correct)
{
  int res = zad+correct;
  if(res>100){
    res=100;
  }
  if(res<0){
    res=0;
  }
  else
  {
    res=zad;
  }
  return res;
}

 

Roman2344
Offline
Зарегистрирован: 09.09.2015

И вроде в коде всё правильно, или что - то я не вижу.

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Попробуйте в строках 36-39 жостко задать zad1, zad2 и t_pwm задать побольше - 10000 например. Доберусь до компьютера в симуляторе попробую.

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

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

#include <DigOut.h>//подключаем библиотеку выходов yadi.sk/d/NM4S6HmFrTRu6
DigOut outten(9), outten2(12);//инициализация цифровых выходов на тен 1 и 2
#define t_pwm 1000//период ШИМ в мс (можно увеличить)

void setup() {
  analogReference(INTERNAL);
}

void loop() {
  byte zad=50;//мощность на 1 тен в %
  byte zad2=30;//мощность на 2 тен в %
  if (millis()>3000){//разрешаем управление нагрузкой через 3 сек после включения
    outten.blink(t_pwm, (t_pwm/100)*zad);//управление теном 1
    outten2.blink(t_pwm, (t_pwm/100)*zad2);//управление теном 2
  }
}//END loop

В симуляторе работает. Попробуйте на железе.

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Вот немного подшаманил, в симуляторе заработал (это код из поста #46)


#include <DigOut.h>//подключаем библиотеку выходов yadi.sk/d/NM4S6HmFrTRu6
#define t_time 100//период опроса температуры
DigOut outten(9), outten2(12);//инициализация цифровых выходов на тен 1 и 2
#define termo A0//вход основного датчика температуры
unsigned long time;//интервал замера температуры
byte zad=0;//задание мощности ТЭНа1
byte zad2=0;//задание мощности ТЭНа2
float temp=0.0;//текущее значение температуры
float pre_temp=0.0;//предыдущее значение температуры
unsigned long preTempMillis=0;//для опроса температуры
unsigned long prePIctl_time=0;//для расчета мощности
float ust=0;//уставка
#define t_pwm 1000//период медленного ШИМ в мс
#define ust4 115//температура средний режим=115


void setup() {
  //analogReference(INTERNAL2V56);
 Serial.begin (9600); 
}

void loop() {
  unsigned long currentMillis=millis();
  if(currentMillis-preTempMillis>=t_time){
    temp=analogRead(termo);//получаем температуру
    //а тут неплохобы в градусы целсия перевести
    temp=temp/2.06;//переводим показания АЦП в градусы С
    temp=(pre_temp*0.3)+(temp*0.7);//фильтр от резких изменений температуры
    pre_temp=temp;
    preTempMillis=currentMillis;//сброс таймера замера температуры
  }

 
 
    ust=ust4;//уставка
  if(currentMillis-prePIctl_time>1000){//если подошло время расчитать мощность
  zad=PIctl(temp, ust);//расчет мощности
  zad=pwr(zad,0);//корректировка мощности
  zad2=pwr(zad,10);//корректировка мощности
 prePIctl_time=currentMillis;//сброс таймера расчета мощности
 //Вывод в порт температуры и мощности    
    Serial.print(temp);
    Serial.print("-T ");
    Serial.print(zad);
    Serial.print("-% ");
    Serial.print(zad2);
    Serial.println("-%");
  }
  if (millis()>3000){//разрешаем управление нагрузкой через 3 сек после включения устройства
    outten.blink(t_pwm, (t_pwm/100)*zad);//управление теном 1
    outten2.blink(t_pwm, (t_pwm/100)*zad2);//управление теном 2
  }
}//END loop

//функция расчета мощности по ПИ закону регулирования
byte PIctl(float temp, float ust)
{
  byte zad=0;
  static float i=0;
  if(temp>(ust-0.5)&&temp<(ust+0.5))//зона нечувствительности +-0,5C
  {
    return byte(i);
  }
  else//иначе
  {
    float e, p;
    e=(ust-temp);//вычисление ошибки регулирования
    // расчет выходной мощности
    p=(1.5*e);//расчет пропорциональной состовляющей
    if (p<0.0)//мощность не может быть отрицательной
    {
      p=0.0;//ограничение P
    }
    i=(i+(e*0.014));//расчет интегральной составляющей = тепловым потерям
    if (i>100.0)//мощность не может быть больше 100%
    {
      i=100.0;//ограничение I
    } 
    if (i<-100.0)
    {
      i=-50.0;//ограничение I
    } 
    //расчет выходной мощности
    zad=byte(p+i);
    if(zad>100){return 100;}
    if(zad<0){return 0;}
  //корректировка при отклонении температуры более чем на +-2С
  //для быстрого выхода на уставку
  if (temp<(ust-8.5))//если темп < уст на 2С
  {
    zad=100;//то мощность 100%
    i=0;
  }
  if (temp>(ust+8.5))//если темп > уст на 2С
  {
    zad=0;//то мощность 0%
    i=0;
  }
  return zad;
}///
}

byte pwr(int zad, int correct)
{
  int res = zad+correct;
  if(res>100){
    res=100;
  }
  if(res<0){
    res=0;
  }
  else
  {
    res=zad;
  }
  return res;
}

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

Как испытаете отпишитесь. Напомню что в этом коде кнопки не задействованы.