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

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

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

Кстати, а если всё таки решу два датчика установить то, так пойдёт отслеживать?:

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

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

void loop() {

    
    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;}

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

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







    if ((millis()-time)>=t_time2){
    time=millis();
    temp2=analogRead(termo2);//получаем температуру
    temp2=(pre_temp2*0.2)+(temp2*0.8);//фильтр
    //   w=abs((ust-temp)*(pre_temp-temp));//время выхода на уставку
    pre_temp2=temp2;}

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

if(c<zad){
digitalWrite(outten2,1);
}
else{
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;
  }
}







 

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

Попробовал ваш код последний, на отдельной никуда не подпаяной ардуино мега, так замыкаю А0 на землю, в мониторе последовательного порта 0 градусов и 100% мощности, вот только на выводе 9 и 12 меги ничего нету, зато на выводе 10 появляется лог.1(ну так как 100% мощности), причём здесь вывод 10, не пойму, перепроверил 100 раз.

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

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

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

Перекачайте класс DigOut

andreyR
Offline
Зарегистрирован: 23.05.2016

Добрый вечер. Я только начинаю изучение ардуион и наткнулся на эту тему. Сразу всплыла одна идея, которая меня волнует.  Есть у меня надаче ящик с ТЭНом, порядка 1500 ватт. Есть регулятор, который держит определнную температуру в нем, за счет замыкания\размыкания реле. Так же в регуляторе есть аналоговый выход 0(4)-20 мА с функцией ПИДрегулипрвания. Так вот, как бы мне сделать плавное регулирование ТЭНами?? Я хочу чтоб при температуре близкой к уставке, потребление электричесва было минимальное. Я хочу услышать от Вас все плюсы и минусы такого подключения, есть смысл в таком регулировании??  И можно ли реализовать проект на ардуине без промышленного регулятора?? Так же у меня есть регулятор мощьностидля ТЭНа,  который управляется переменным резистором, ну не вешать же на него сервопривод =))) Вообщем пока у меня тьма в котелке. Жду от вас помощи, пока только в теории.

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

А последний класс DigOut работает только с Дунами или с УНо и другими на меге 328 тоже,  или для меги 328 предыдущий класс, а для меги этот?

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

andreyR, с реле не очень хорошо вдруг что можно оптосимистор с симистором поставить, 4-20мА, тебе не к чему, это универсальный КИПовский сигнал

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

Вот тема была на форуме как измерить 4-20мА. Я так понимаю это будет 0-100% выходной мощности.

В начале темы я ссылки выкладывал, ПИ регулятор вроде я себе на дачу делал в прошлом году. Всю зиму отработал без проблемм +-0.3С.

Если хотите полностью на Ардуино собрать, просто возмите код из этой темы.

Из кода нужно будет только второй тен выбросить и всё.

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

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

Roman2344 пишет:

А последний класс DigOut работает только с Дунами или с УНо и другими на меге 328 тоже,  или для меги 328 предыдущий класс, а для меги этот?

Последний работает на всех дуинах поддерживаемых средой (но он медленней - скорость как у стандартной функции digitalWrite()).

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

В функции корректировки мощности закралась ошибочка.

Исправил, замените на это

//корректировка мощности
byte pwr(byte zad, byte correct)
{
  byte res = zad+correct;
  if(res>100){
    return 100;
  }
  if(res<0){
    return 0;
  }
  return zad+correct;
}

В этой функции осталась еще ошибка, как исправлю выложу.

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

Предложу использовать встроенный светодиод для индикации выходной мощности.

Нужно его прописать вначале

DigOut PwrInd (13,0);//индикатор мощности

И в коде где выдаем мощность

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

 

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

Наверное окончательный варийант

//корректировка мощности
byte pwr(int zad, int correct)
{
  int res = zad+correct;
  if(res>100){
    return 100;
  }
  if(res<0 || zad == 0){
    return 0;
  }
  return res;
}

 

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

Спасибо yul-i-an, поисправляю у себя и проверю, на чистой меге, хотя проблема у меня была в том что один бак охлаждаю, а второй частично и разница была в стартовых температурах, а так как мощность одинаковая даётся в одинаковый промежуток времени то они догнать по температуре друг друга не могли)

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

Roman2344 пишет:

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

Кстати, а если всё таки решу два датчика установить то, так пойдёт отслеживать?:

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

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

void loop() {

    
    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;}

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

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







    if ((millis()-time)>=t_time2){
    time=millis();
    temp2=analogRead(termo2);//получаем температуру
    temp2=(pre_temp2*0.2)+(temp2*0.8);//фильтр
    //   w=abs((ust-temp)*(pre_temp-temp));//время выхода на уставку
    pre_temp2=temp2;}

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

if(c<zad){
digitalWrite(outten2,1);
}
else{
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;
  }
}

Чтобы установить второй датчик температуры достаточно будет прописать его тут

  if(currentMillis-preTempMillis>=t_time){//пришлло время мерить температуру
    temp=analogRead(termo);//получаем температуру с первого
    temp=temp/2.06;
    temp=(pre_temp*0.2)+(temp*0.8);//фильтр
    pre_temp=temp;

    temp2=analogRead(termo2);//получаем температуру со второго
    temp2=temp2/2.06;
    temp=(pre_temp2*0.2)+(temp2*0.8);//фильтр
    pre_temp2=temp2;
    preTempMillis=currentMillis;
  }

Но ввиду усложнения код лучше написать функцию в которую передовать аналоговых вход на котором сидит датчик, а она вернет отфильтрованную температуру

например

    float getTempLM35(byte Ain)
    {
        static float pre_temp=0;
       float temp=analogRead(Ain);//получаем значение АЦП
       temp=temp/2.06;//переводим в градусы
       temp=(pre_temp*0.2)+(temp*0.8);//фильтруем
       pre_temp=temp;//для фильтра в следующем цикле
       return temp;
    }

тогда вместо

  if(currentMillis-preTempMillis>=t_time){//пришлло время мерить температуру
    temp=analogRead(termo);//получаем температуру с первого
    temp=temp/2.06;
    temp=(pre_temp*0.2)+(temp*0.8);//фильтр
    pre_temp=temp;

    temp2=analogRead(termo2);//получаем температуру со второго
    temp2=temp2/2.06;
    temp=(pre_temp2*0.2)+(temp2*0.8);//фильтр
    pre_temp2=temp2;
    preTempMillis=currentMillis;
  }

будет

  if(currentMillis-preTempMillis>=t_time){
    temp=getTempLM35(termo);//получаем температуру 1
    temp2=getTempLM35(termo2);//получаем температуру 2
    preTempMillis=currentMillis;
  }

 

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

Roman2344 пишет:

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

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

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

yul-i-an, а какой симулятор для ардуино вы используете?

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

Симулятор использую Proteus 7.7

Ну как Ваш аппарат, заработал?

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

outten.blink(t_pwm, (t_pwm/100)*zad);

на

outten.blink(t_pwm, ((t_pwm+200)/100)*zad);

то количество полупериодов сети прошедших в нагрузку получается пропорционально мощности (7% - 7 полупериодов).

Вот графики при мощности в 10%

Желтый - напряжение в нагрузку

Зеленый - управление на симистр

Но особой разницы в работе на глаз не заметите.

Может в классе DigOut переименовать blink в Lpwm думаю? А то будут думать что он только для мигания годиться.

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

Аппарат работает, разница в ТЭНах есть около 3-4 градусов но не критично, вообще разница около 7-8 градусов, но с учётом погрешности китайских мультиметров между ними разница порядка 3-4 градусов. Пока работаю на первом варианте.

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 1000//период опроса температуры
float t1=A0;// Вход АЦП 0
int outten=13;
//для ПИ регулятора
float p,i;

long time;//интервал замера температуры

long on_time=0;//для периода ШИМ
int zad=0;
float temp=0.0;//текущее значение температуры
float pre_temp=0.0;//предыдущее значение температуры
int w=0;
float ust=489;//115 градусов
int c=0;//пройденные циклы мощности

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;
  }
}

Для первого варианта осциллограма выглядит так как всё время лог. 1 стоит, ну это понятно это же период ШИМ =1с. ( развёртка на осциле 50мс, осцил Хамелион, показания снимал задавая на вход АЦП вместо температурного датчика около 90-95% от необходимого входного для АЦП(от уставки)), так вот прямоугольные импульсы появляются как - то хаотично через разные промежутки времени , бывают как будтя два вместе соединяются, так то всё работает на симисторе, в моём устройстве, может это так осцил рисует.

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

С этим кодом(который на два выходы с коректировкой по мощности) всё по другому при том же периоде ШИМ=1с., прямоугольные импульсы появляются через одинаковые промежутки времени, и прямоугольные импульсы друг на друга не накладываются, в реальной работе не проверял. Праметры осцыла и задачи входного сигнала на АЦП те же. Коректировка мощности на другой канал работает.

#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;
}

 

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

А вот такой код тоже на два выхода с корректировкой, в мониторе последовательного порта показывает 200%, на выходе только как я понимаю период ШИМ, а прямоугольные импульсы не появляются

#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){
    return 100;
  }
  if(res<0 || zad == 0){
    return 0;
  }
  return res;
}

 

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

Насчёт кода для применения двух датчиков и двух выходов разных, пост 64, а как выдать мощность на разные выхода, после получения показания с двух датчиков, не пойму.

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

Ну второй код мне кажеться получился более читаемым и прозрачным. А картинки с осцилогрофа какнибудь можете выложить, для второго кода?

Я на выходных этот код мучал, мне кажеться что он полностью рабочий


#include <DigOut.h>//подключаем библиотеку выходов yadi.sk/d/NM4S6HmFrTRu6
#define t_time 1000//период опроса температуры
#define power_time 1000//период расчета мощности
DigOut outten(9), outten2(8), ind(13,0);//инициализация цифровых выходов на тен 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 100//температура средний режим=100

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

void loop() {
  ust=ust4;//уставка
  unsigned long currentMillis=millis();

  if(currentMillis-preTempMillis>=t_time){
    temp = getTempLM35(termo);
//сюда второй датчик
    preTempMillis=currentMillis;//сброс таймера замера температуры
  } 

  if(currentMillis-prePIctl_time>=power_time){//если подошло время расчитать мощность
    zad=PIctl(temp, ust);//расчет мощности
//если два датчика то zad2= PIctl(temp2, ust);
    zad2=zad;//мощность одинаковая

    prePIctl_time=currentMillis;//сброс таймера расчета мощности
    //Вывод в порт температуры и мощности    
    serialPrint();
  }
  if (currentMillis>5000){//разрешаем управление нагрузкой через 3 сек после включения устройства
    outten.blink(t_pwm, ((t_pwm)/100)*zad);//управление теном 1
    outten2.blink(t_pwm, ((t_pwm)/100)*zad2);//управление теном 2
    ind=outten;
  }
}//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;
}

//получение температуры с LM35
float getTempLM35(byte Ain)
{
  static float pre_temp=0;
  float temp=analogRead(Ain);//получаем значение АЦП
  temp=temp/2.06;//переводим в градусы
  temp=(pre_temp*0.3)+(temp*0.7);//фильтруем
  pre_temp=temp;//для фильтра в следующем цикле
  return temp;
}

//вывод в монитор для отладки
void serialPrint()
{
  Serial.print(temp);
  Serial.print("-T ");
  Serial.print(zad);
  Serial.print("-% ");
  Serial.print(zad2);
  Serial.println("-%");
}

Единственное останется настроить ПИ регулятор и если всётаки две разные емкости добавить второй датчик температуры, темболее что теперь это не составит труда.

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

Roman2344 пишет:

А вот такой код тоже на два выхода с корректировкой, в мониторе последовательного порта показывает 200%, на выходе только как я понимаю период ШИМ, а прямоугольные импульсы не появляются

#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){
    return 100;
  }
  if(res<0 || zad == 0){
    return 0;
  }
  return res;
}

 

Надо сравнить функцию ПИ регулятора с кодом из поста #75 (самая последняя версия), там помоему глюки были но я их исправил.

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

Выложу картинки попозже, а насчёт кода со вторым датчиком, то почему, мощность одинаковая,  если допустим баки хоть и одинаковые, но допустим тот стартует с 30 градусов, а другой с 20 градусов ну если их не равномерно охладить, да и разница в ТЭНах в 3-4 градуса всё равно есть, хотя и мультиметры с термопарами около 2градусов погрешность, причём разница изначально в мультиметрах 2 градуса, а мы будем одинаковую мощность давать, или я что-то не пойму?

if(currentMillis-prePIctl_time>=power_time){//если подошло время расчитать мощность
033     zad=PIctl(temp, ust);//расчет мощности
034 //если два датчика то zad2= PIctl(temp2, ust);
035     zad2=zad;//мощность одинаковая

 

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

Roman2344 пишет:

Насчёт кода для применения двух датчиков и двух выходов разных, пост 64, а как выдать мощность на разные выхода, после получения показания с двух датчиков, не пойму.

Есть секция получения температуры

  if(currentMillis-preTempMillis>=t_time){
    temp = getTempLM35(termo);
    temp2 = getTempLM35(termo2);//добавили второй датчик
    preTempMillis=currentMillis;//сброс таймера замера температуры
  } 

Есть секция расчета мощности по ПИ закону

  if(currentMillis-prePIctl_time>=power_time){//если подошло время расчитать мощность
    zad=PIctl(temp, ust);//расчет мощности для первой емкости
    zad2=PIctl(temp2, ust);//расчет мощности для второй емкости
    prePIctl_time=currentMillis;//сброс таймера расчета мощности
    //Вывод в порт температуры и мощности    
    serialPrint();
  }

Есть секция управления нагрузкой

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

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

Это изменения для последнего кода из поста #75 для работы с двумя каналами измерения/регулирования.

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

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

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

Ну а если бы ёмкости были разные то можно же греть их на разные уставки и всё

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

Roman2344 пишет:

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

outten.blink(t_pwm, ((t_pwm)/100)*zad);//управление теном

Вот эта строчка формирует управляющие сигналы на симистор, в неё мы передаем период ШИМ - 1000мс (1с) и задание в %, для того чтобы % перевести в длину управляющего импульса мы период делим на 100% и получаем продолжительность импульса для 1-го %, а затем умножаем его на zad что нам дает в результате продолжительность управляющего воздействия на симистор для получения расчетной мощности zad.

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

Roman2344 пишет:

Ну а если бы ёмкости были разные то можно же греть их на разные уставки и всё

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

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

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

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

Вот рабочая версия функции расчета мощности

//функция расчета мощности по ПИ закону регулирования
byte PIctl(float temp, float ust)
{
  byte zad=0;
  static float i=0;
  if(temp>(ust-0.5)&&temp<(ust+0.5))//зона нечувствительности +-0,5C
  {
    zad=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){zad = 100;}
    if(zad<0){zad = 0;}

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

 

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

Если всё еще актуально?!

Переписал ПИ регулятор. (более удобная настройка)


//расчет мощности по ПИ закону регулирования
byte PIctl(float temp, float ust)
{
#define kP 65//коэффициент пропорциональности
#define p_min 0.0//минимум П составляющей - не < 0
#define p_max 100.0//максимум П составляющей - не > 100 
#define kI 0.014//коэффициент интегрирования
#define i_max 50.0//максимум И составляющей
#define i_min -50.0//минимум И составляющей
#define no_ctl 0,5//зона от уставки нечувствительности +-
#define d_ctl 2//зона +- от уставки - за пределами или 100% или 0%
#define out_min 0//минимальный выходной %
#define out_max 100//максимальный выходной % 
  byte zad=0;
  static float i=0;
  if(temp>(ust-no_ctl)&&temp<(ust+no_ctl))//зона нечувствительности +- no_ctl
  {
    return byte(i);
  }
  else//иначе
  {
    float e, p;
    e=(ust-temp);//ошибка регулирования
    p=(kP*e);//расчет пропорциональной состовляющей
    (p<p_min)? p=p_min: (p>p_max)? p=p_max: p=p;//ограничение p
    i=(i+(e*kI));//расчет интегральной составляющей
    (i>i_max)? i=i_max: (i<i_min)? i=i_min: i=i;//ограничение i
    zad=byte(p+i);//вычесленное воздействие на объект в %
    (zad>out_max)? zad=out_max: (zad<out_min)? zad=out_min: zad=zad;//ограничение zad
    //При отклонении температуры более чем на +-d_ctl
    // для быстрого выхода на уставку
    if (temp<(ust-d_ctl))//если темп < уст на d_ctl
    {
      zad=out_max;//то мощность максимум
      i=0;
    }
    if (temp>(ust+d_ctl))//если темп > уст на d_ctl
    {
      zad=out_min;//то мощность минимум
      i=0;
    }
    return zad;
  }
}
Roman2344
Offline
Зарегистрирован: 09.09.2015

Спасибо, как - нибудь опробую.

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

Еще к теме, последняя версия функции ПИ регулятора

//расчет мощности по ПИ закону регулирования
#define kP 6//коэффициент пропорциональности
#define p_min 0.0//минимум П составляющей - не < 0
#define p_max 100.0//максимум П составляющей - не > 100 
#define kI 0.025//коэффициент интегрирования
#define i_min 0.0//минимум И составляющей
#define i_max 30.0//максимум И составляющей
#define d_ctl 4.0//зона пропорциональности ust-d_ctl
#define out_min 0//минимальный выходной %
#define out_max 100//максимальный выходной % 
byte PIctl(float temp, uint8_t ust)//возвращает необходимую мощность
{
  uint8_t out=0;//uint8_t
  static float i=0;
  float e, p;
  e=(ust-temp);//ошибка регулирования
  //расчет p
  p=(temp<ust-d_ctl)?p_max:(temp>ust)?p_min:(kP*e);
  //расчет i
  i=(i<i_min)?i_min:(i>i_max)?i_max:i+(kI*e);
  out=(p+i<out_min)?out_min:(p+i>out_max)?out_max:p+i;
  return out;
}

График выхода на уставку с 36 до 41С в течении 5-7 минут, точно не засекал. Ну и конечно всё зависит от kI и kP коэффициентов.

Синяя линия - текущая температура (С)
Красная - уставка (С)
Желтая - мощность (%)
Зеленая - ошибка регулирования (С)
Сиреневая - П составляющая (%)
Голубая - И составляющая (%)

Синяя - температура

Красная - уставка

Желтая - мощность

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

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

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

График выхода на уставку с 36 до 41С в течении 5-7 минут

А почему так долго? И что в вашем коде и вообще в коде Ардуино ИДЕ означают вопросительные знаки?

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

Долго из за не оптимальных настроек коэффициентов. И варийантов не много, или быстро с перерегулированием или дольше но без перерегулирования, выбирается под свои нужды.
Про знаки вопросов - (условие)? если истина : если лож ;

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Roman2344 пишет:

И что в вашем коде и вообще в коде Ардуино ИДЕ означают вопросительные знаки?

https://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D1%80%D0%BD%D0%B0%D1%80%D0%BD...

https://habrahabr.ru/post/205848/

http://cppstudio.com/post/304/

http://purecodecpp.com/archives/554

Bizard2000
Offline
Зарегистрирован: 08.09.2016

Здравствуйте yul-i-an

Заинтересовал ваш код
интересует будет ли он работоспособен для arduino uno + ssr реле + тэн 2кВт(от эл.плиты)
хочу это все приспособить для коптильни

ps (arduino uno + ssr реле) заказал должно скоро прийти

 

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

Все будет работатть, только ж реле бери 15А и нужное напряжение коммутации, или ддва реле в параллель контакты, или у одного если есть две пары контактов по 10А в параллель.

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

Bizard2000 пишет:

Здравствуйте yul-i-an

Заинтересовал ваш код
интересует будет ли он работоспособен для arduino uno + ssr реле + тэн 2кВт(от эл.плиты)
хочу это все приспособить для коптильни

ps (arduino uno + ssr реле) заказал должно скоро прийти

 

Будет. Для этого и писалось.

Bizard2000
Offline
Зарегистрирован: 08.09.2016

yul-i-an пишет:

outten.blink(t_pwm, ((t_pwm)/100)*zad);//управление теном

Вот эта строчка формирует управляющие сигналы на симистор, в неё мы передаем период ШИМ - 1000мс (1с) и задание в %, для того чтобы % перевести в длину управляющего импульса мы период делим на 100% и получаем продолжительность импульса для 1-го %, а затем умножаем его на zad что нам дает в результате продолжительность управляющего воздействия на симистор для получения расчетной мощности zad.

Ругается на эту строчку, на blink

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

Bizard2000 пишет:

yul-i-an пишет:

outten.blink(t_pwm, ((t_pwm)/100)*zad);//управление теном

Вот эта строчка формирует управляющие сигналы на симистор, в неё мы передаем период ШИМ - 1000мс (1с) и задание в %, для того чтобы % перевести в длину управляющего импульса мы период делим на 100% и получаем продолжительность импульса для 1-го %, а затем умножаем его на zad что нам дает в результате продолжительность управляющего воздействия на симистор для получения расчетной мощности zad.

Ругается на эту строчку, на blink

Попробуйте outten.lpwm(период, заполнение%);

В Классе DigOut blink был заменен на lpwm

Bizard2000
Offline
Зарегистрирован: 08.09.2016

Спасибо, попробую.

Bizard2000
Offline
Зарегистрирован: 08.09.2016

Здравствуйте yul-i-an
Пришла плата и остальные детали
Пробую ваш код, если можно глянете правильно ли я все сделал.

[code]
#include <DigOut.h>//подключаем библиотеку выходов yadi.sk/d/NM4S6HmFrTRu6
#define t_time 1000//период опроса температуры
#define power_time 1000//период расчета мощности
DigOut outten(9);//инициализация цифровых выходов на тен
unsigned long time;//интервал замера температуры
byte zad=0;//задание мощности ТЭНа1
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 85//температура средний режим=100

///------------------------ temp
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2//вход основного датчика температуры
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature datchik(&oneWire);
//-----------------------------------------



//функция расчета мощности по ПИ закону регулирования
//расчет мощности по ПИ закону регулирования
#define kP 6//коэффициент пропорциональности
#define p_min 0.0//минимум П составляющей - не < 0
#define p_max 100.0//максимум П составляющей - не > 100 
#define kI 0.025//коэффициент интегрирования
#define i_min 0.0//минимум И составляющей
#define i_max 30.0//максимум И составляющей
#define d_ctl 1.5//зона пропорциональности ust-d_ctl
#define out_min 0//минимальный выходной %
#define out_max 100//максимальный выходной % 
byte PIctl(float temp, uint8_t ust)//возвращает необходимую мощность
{
  uint8_t out=0;//uint8_t
  static float i=0;
  float e, p;
  e=(ust-temp);//ошибка регулирования
  //расчет p
  p=(temp<ust-d_ctl)?p_max:(temp>ust)?p_min:(kP*e);
  //расчет i
  i=(i<i_min)?i_min:(i>i_max)?i_max:i+(kI*e);
  out=(p+i<out_min)?out_min:(p+i>out_max)?out_max:p+i;
   
  return out;
}


//вывод в монитор для отладки
void serialPrint()
{
  Serial.print(temp);
  Serial.println("-T ");
  Serial.print(zad);
  Serial.print("-% ");
  
}

void setup() {
    datchik.begin();
  Serial.begin (9600); 
}

void loop() {
  ust=ust4;//уставка
  unsigned long currentMillis=millis();
  if(currentMillis-preTempMillis>=t_time){
  temp=datchik.getTempCByIndex(0);//получаем температуру
  preTempMillis=currentMillis;//сброс таймера замера температуры
  } 

  if(currentMillis-prePIctl_time>=power_time){//если подошло время расчитать мощность
    zad=PIctl(temp, ust);//расчет мощности
    prePIctl_time=currentMillis;//сброс таймера расчета мощности
    //Вывод в порт температуры и мощности    
     serialPrint();
  }
  if (currentMillis>5000){//разрешаем управление нагрузкой через 3 сек после включения устройства
    outten.lpwm(t_pwm, zad);//управление теном 1
    //ind=outten;// ?
  }
}//END loop


[/code]

При компиляции скетча ругался на ind=outten; убрал вроде все пошло.
Также заменил как вы писали outten.lpwm(t_pwm, zad);
Вопрос, нужную мне температуру я задаю переменной zad ?
Не могу понять для чего #define ust4 85//температура средний режим, что значит средний режим?
Для чего две ust и ust4 если всеровно ust=ust4;

Спасибо.

 

 

 

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

ust - это уставка температуры

ust4 - можете выбросить

необходимую температуру просто передовайте в переменную ust (ust=54; например) или любым иным способом.

чтобы работал индикатор на 13 пине (ind) нужно после строки

DigOut outten(9);//инициализация цифровых выходов на тен

добавить

DigOut ind(13);//инициализация цифровых выходов на индикатор

и раскоментировать

ind=outten;

Встроеный светодиод на 13 пине отображает состояние выхода на тен.

 

Bizard2000
Offline
Зарегистрирован: 08.09.2016

Спасибо. Попробую. Блин Ind пропустил... А так на ваш взгляд всё правильно?

Номер тел или карты для возногрождения?