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

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

Bizard2000 пишет:

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

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

Да вроде всё нормально, если будут вопросы обращайтесь.

Благодарности сюда принимаю

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

Принимай благодарность  :)

Спасибо

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

Bizard2000 пишет:

Принимай благодарность  :)

Спасибо

Всегда рад помочь.

soznik
Offline
Зарегистрирован: 20.09.2015

Доброго времени.

Переделал немного код  предоставленый Bizard2000 .

Добавил индикатор LCD1602 и пока две кнопки для установки заданной температуры (ust).

И ещё один датчик температуры  нужный для моей конструкции.



#include <LiquidCrystal.h>
#include <DigOut.h>//подключаем библиотеку выходов yadi.sk/d/NM4S6HmFrTRu6
#define t_time 1000//период опроса температуры
#define power_time 1000//период расчета мощности
DigOut outten(13);//инициализация цифровых выходов на тен
unsigned long time;//интервал замера температуры
byte zad=0;//задание мощности ТЭНа1
float temp=0.0;//текущее значение температуры
float temp2;
float pre_temp=0.0;//предыдущее значение температуры
unsigned long preTempMillis=0;//для опроса температуры
unsigned long prePIctl_time=0;//для расчета мощности
float ust=26;//уставка
float e, p;
int c=99;//пройденые циклы мощности
#define t_pwm 8000//период медленного ШИМ в мс

LiquidCrystal lcd(12,11,7,6,5,4);
int analog=0;

#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS_1 9//вход основного датчика температуры
#define ONE_WIRE_BUS_2 8

OneWire oneWire_in(ONE_WIRE_BUS_1);
OneWire oneWire_out(ONE_WIRE_BUS_2);

DallasTemperature datchik(&oneWire_in);
DallasTemperature datchik2(&oneWire_out);


//-----------------------------------------



//функция расчета мощности по ПИ закону регулирования
//расчет мощности по ПИ закону регулирования
#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 3//зона пропорциональности ust-d_ctl(зона регулировки ПИ)
#define out_min 0//минимальный выходной %
#define out_max 100//максимальный выходной % 
  byte cel[8] =
{
  0b01000,
  0b10100,
  0b01000,
  0b00111,
  0b01000,
  0b01000,
  0b00111
};
byte PIctl(float temp, uint8_t ust)//возвращает необходимую мощность
{
  uint8_t out=0;//uint8_t
  static float i=0;
  
  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 setup() {
  digitalWrite(14,HIGH);//включаем внутренний pull-up резистор
  lcd.begin(16, 2);
  datchik.begin();
  datchik2.begin();
  Serial.begin (9600); 
  lcd.createChar(1, cel);
}

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


void Screen_print()
{
  byte a=0;
 // byte b=0;
 lcd.setCursor(0, 0);
  lcd.print(temp,1);
  lcd.print("\1 "); 
  lcd.setCursor(0, 1);
  lcd.print(ust,0);
  lcd.print("\1 "); 
  lcd.setCursor(8,1);
  lcd.print(zad);
  lcd.print("%  ");
 
  lcd.setCursor(7,0);
  lcd.print(temp2,1);
  lcd.print("\1");
  lcd.setCursor(14, 0);
  lcd.print("  ");
  a=digitalRead(13);
  if (a==1 ){
    lcd.setCursor(13, 1);
    lcd.print("ON ");
  }
  if (a==0 ){
    lcd.setCursor(13, 1);
    lcd.print("OFF");
  }
 
  }


void loop() {
  analog=analogRead(14);//считываем сигнал с пина АЦП
  if(analog>200&&analog<250)
  {
   ust=ust+1 ;
  }
   if(analog>100&&analog<150)
  {
   ust=ust-1 ;
  }
  datchik.requestTemperatures();
  datchik2.requestTemperatures();
  unsigned long currentMillis=millis();
  if(currentMillis-preTempMillis>=t_time){
  temp=datchik.getTempCByIndex(0);//получаем температуру
  temp2=datchik2.getTempCByIndex(0);//получаем температуру
  preTempMillis=currentMillis;//сброс таймера замера температуры
  } 

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

  if (currentMillis>5000){//разрешаем управление нагрузкой через 5 сек после включения устройства
    outten.lpwm(t_pwm, zad);//управление теном 1
     }
  Screen_print();

}

Остались некоторые вопросы по функция расчета мощности по ПИ закону регулирования

Какой коэф. учитывает теплоемкость нагреваемого объекта Кi или Kp .

Где можно почитать по подробнее про предоставленные формулы расчета мощности.

 

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

Зачем так усложнять. Пусть есть ТЭН. Есть частота с которой он включается, есть период времени при котором внутри частоты он будет выключаться. Путь есть некая переменная  0 тен всегда выключен, 100 тен всегда включен. Думаю это всем понятно. Есть вилка температур, максимум и минимум.  Так вот при превышении максимальной температуры переменную немного надо понизить, а при минимально допустимой температуре переменную повысить.  Техническая задача поставлена. Теперь любой может написать программу.

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

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

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

Информация по настройке регуляторов

Для тех кто использует класс DigOut рекомендую его перекачать, т.к. исправлеа ошибка от которой при заполнении периода 100% в конце каждого периода происходил сброс выхода в 0, что не очень приятно при использовании реле. ССЫЛКА на DigOut

Ещё в нем появился флаг (имя_экземпляра.end) который возвращает 1 в конце каждого периода.

Пример

    if (ten.end==1){//если закончился период медленного ШИМ
      setPower=PIctl(currentTemp, taskTemp);//расчет мощности uint8_t
      ten.end=0;//сброс флага конца периода ШИМ
    }

soznic позволил себе Ваш код подправить немного

#include <LiquidCrystal.h>
#include <DigOut.h>//подключаем библиотеку выходов yadi.sk/d/NM4S6HmFrTRu6
#define t_time 1000//период опроса температуры
#define power_time 1000//период расчета мощности
#define PinTen 13//пин управления нагревателем
DigOut outten(PinTen);//инициализация цифровых выходов на тен
unsigned long time;//интервал замера температуры
byte zad=0;//задание мощности ТЭНа1
float temp=0.0;//текущее значение температуры
float temp2;
float pre_temp=0.0;//предыдущее значение температуры
unsigned long preTempMillis=0;//для опроса температуры
unsigned long prePIctl_time=0;//для расчета мощности
float ust=26;//уставка
#define t_pwm 8000//период медленного ШИМ в мс

LiquidCrystal lcd(12,11,7,6,5,4);
int analog=0;

#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS_1 9//вход основного датчика температуры
#define ONE_WIRE_BUS_2 8

OneWire oneWire_in(ONE_WIRE_BUS_1);
OneWire oneWire_out(ONE_WIRE_BUS_2);

DallasTemperature datchik(&oneWire_in);
DallasTemperature datchik2(&oneWire_out);
//-----------------------------------------
byte cel[8] =
{
  0b01000,
  0b10100,
  0b01000,
  0b00111,
  0b01000,
  0b01000,
  0b00111
};
//расчет мощности по ПИД закону регулирования
#define kP 90//коэффициент пропорциональности12
#define p_min 0.0//минимум П составляющей - не < 0
#define p_max 100.0//максимум П составляющей - не > 100 
#define kI 0.2//коэффициент интегрирования 020
#define i_min 0.0//минимум И составляющей
#define i_max 30.0//максимум И составляющей
#define kd 0//коэффициент диференциирования
#define d_ctl 2.0//зона пропорциональности ust-d_ctl
#define out_min 0//минимальный выходной %
#define out_max 100//максимальный выходной % 

uint8_t PIctl(float temp, uint8_t ust)//возвращает необходимую мощность
{
  uint8_t out=0;//uint8_t
  static float i=0;
  static float ed=0;///
  float e, p;
  float d;///
  e=(ust-temp);//ошибка регулирования
  p=(temp<ust-d_ctl)?p_max:(temp>ust)?p_min:(kP*e);//П составляющая
  i=(i<i_min)?i_min:(i>i_max)?i_max:i+(kI*e);//И составляющая
  d=kd*(e-ed);///Д составляющая
  ed=e;///
  out=(p+i+d<out_min)?out_min:(p+i+d>out_max)?out_max:p+i+d;
  return out;
}

void setup() {
  digitalWrite(14,HIGH);//включаем внутренний pull-up резистор
  lcd.begin(16, 2);
  datchik.begin();
  datchik2.begin();
  Serial.begin (9600); 
  lcd.createChar(1, cel);
}

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


void Screen_print()
{
  byte a=0;
  // byte b=0;
  lcd.setCursor(0, 0);
  lcd.print(temp,1);
  lcd.print("\1 "); 
  lcd.setCursor(0, 1);
  lcd.print(ust,0);
  lcd.print("\1 "); 
  lcd.setCursor(8,1);
  lcd.print(zad);
  lcd.print("%  ");

  lcd.setCursor(7,0);
  lcd.print(temp2,1);
  lcd.print("\1");
  lcd.setCursor(14, 0);
  lcd.print("  ");
  a=digitalRead(13);
  if (a==1 ){
    lcd.setCursor(13, 1);
    lcd.print("ON ");
  }
  if (a==0 ){
    lcd.setCursor(13, 1);
    lcd.print("OFF");
  }
}

void loop() {
  analog=analogRead(14);//считываем сигнал с пина АЦП
  if(analog>200&&analog<250)
  {
    ust=(ust<100)?ust+=1:ust;//увеличение с ограничением 100
  }
  if(analog>100&&analog<150)
  {
    ust=(ust>0)?ust-=1:0;//уменьшение с ограничением 0
  }
  datchik.requestTemperatures();
  datchik2.requestTemperatures();
  unsigned long currentMillis=millis();
  if(currentMillis-preTempMillis>=t_time){
    temp=datchik.getTempCByIndex(0);//получаем температуру
    temp2=datchik2.getTempCByIndex(0);//получаем температуру
    preTempMillis=currentMillis;//сброс таймера замера температуры
  } 

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

  }
  serialPrint();

  if (currentMillis>5000){//разрешаем управление нагрузкой через 5 сек после включения устройства
    outten.lpwm(t_pwm, zad);//управление теном 1
  }
  Screen_print();
}


 

soznik
Offline
Зарегистрирован: 20.09.2015

Библиотека DigOut у меня стоит эта версия

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

Это не одно и то-же с вашим примером.

soznik
Offline
Зарегистрирован: 20.09.2015

Теперь вообще запутался откуда появилась Д составляющая .

Дайте формулу расчета . В исправлениях вы ограничели пределы регулировки температуры от 0 до 100. Даллас работает от -55 до +125 °С.

и еще строк 141-146 в испраленом коде можно включить.

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

soznik пишет:

Библиотека DigOut у меня стоит эта версия

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

Это не одно и то-же с вашщим примером.

Это выше я привел пример использования флага окончания периода ШИМ, тот кусок говорит о том что если период шим закончился можно пересчитать регулятор, ну это и по коду видно.

А класс перекачайте, в прошлой версии неприятность была при 100% заполнении ШИМ релюха дергалась в конце каждого периода.

soznik
Offline
Зарегистрирован: 20.09.2015

и еще строк 141-146 в испраленом коде можно включить.

я проверил последняя версия класса.

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

soznik пишет:

Теперь вообще запутался откуда появилась Д составляющая .

Дайте формулу расчета . В исправлениях вы ограничели пределы регулировки температуры от 0 до 100. Даллас работает от -55 до +125 °С.

и еще строк 141-146 в испраленом коде можно включить.

Приделы ставте какие Вам нужны. Это как пример защиты от переполнения добавил.

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

soznik пишет:

и еще строк 141-146 в испраленом коде можно включить.

я проверил последняя версия класса.

Можете включить. Но они не нужны. Это было нужно для того чтобы при очень маленькой и близкой к 100% заполнения ШИМ исключить частое переключение реле (если симистор на управлениии то роли не играет).

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

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

Статья http://lazysmart.ru/osnovy-avtomatiki/nastrojka-pid-regulyatora/  содержит неправильный посыл. Там все может быть верно, но для аналоговых систем. Но у нас все же эпоха цифровых технологий. Возьмем пример. У нас ТЭН включен. У него есть конкретная максимальная скорость нарастания температуры. Теперь ТЭН выключен . У него конкретная темпратура охлаждения.  Что надо сделать что бы задача с ТЭНами успешно решена. Достигнуть нужной температуры и включить режим при котором скорость охлаждения сравнялась со скорость нагрева. Так как у нас ТЭН работает в импульсном режиме, то температура в начале каждого цикла должна совпадать с каждым циклом. Осталось расчитать расчитать пропорцию и все будет нормально.  

 Возьмем аналогию. Берем плотный поток машин движущихся с одинаковой скоростью. Каждая машина находится в коробочке из соседних машин. И если машина начнет отставать то задняя будет бить по "жопе"- поторапливайся. И водителю придется дать газку. Если же скорость будет высока, то уже сам водитель будет бить по "жопе" переднюю машину сбрасывать скорость. Вот эту модель надо реализовывать в регулировке ТЭНов. Вилка температур это "передняя и задняя машины".  Чем она уже, тем чаще надо менять режимы переключения. Педаль газа можно установить с некой точностью. И скорость машины будет + - 1 км/ секунду. Что и вызывает колебание машины внутри "коробочки соседей".

soznik
Offline
Зарегистрирован: 20.09.2015

Что это за коэф. при значении 0 он не будет влиять ни на что.

#define kd 0//коэффициент диференциирования

 

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

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

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

Тоже самое что на тапок в машине давить когда трогаетесь. Сначала посильнее, а как поехали приотпустили и оставили в таком положении при котором реальнаяскорость выравнелась с желаемой, а дальше И работает если под горочку то преотпускаем немного, в горку поттапливаем, если обгон то Д (в полик).

soznik
Offline
Зарегистрирован: 20.09.2015

 //  это понятно ,но надо  kd придать какое-то значение.

Перешел по ссылке http://lazysmart.ru/osnovy-avtomatiki/nastrojka-pid-regulyatora/

понял коэф. надо подбирать буду разбиратся . Спасибо.

 

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

Доброе время суток yul-i-an

Продолжаю мучить код, хочу сделать чтоб можно было управлять с андроида режимами работы(ручной, авто, тэн отключен).
На андроид наброски сделал в ai2.appinventor данные принимаю и подставляю куда надо.
Вопрос встал как правильней прописать в программе переключение режимов работы через if..else, switch...case  ....
Спасибо

[code]
#include <MsTimer2.h>
#include <DigOut.h>//подключаем библиотеку выходов yadi.sk/d/NM4S6HmFrTRu6
#define t_time 1000//период опроса температуры
#define power_time 1000//период расчета мощности
DigOut outten(9);//инициализация цифровых выходов на тэн 1
unsigned long time;//интервал замера температуры
byte zad = 0; //задание мощности ТЭНа1
byte zad_r = 0; //задание мощности ТЭНа1 в ручном режиме
float temp = 0.0; //текущее значение температуры
float pre_temp = 0.0; //предыдущее значение температуры
unsigned long preTempMillis = 0; //время для опроса температуры
unsigned long prePIctl_time = 0; //время для расчета мощности
uint8_t ust = 0; //уставка
#define t_pwm 2000//период медленного ШИМ в мс
unsigned long currentMillis;
byte progMode;//режим работы прибора 0-выкл, 1-авто, 2-ручной.
String myString = "";         // строка, в которую будут записываться входящие данные
boolean mystringComplete = false;  // заполнилась ли строка или нет
//---------------------Подключение термопары через MAX6675------------------------------
#include "max6675.h"
int thermoDO = 2;  //он же SO
int thermoCS = 3;
int thermoCLK = 4;  //он же SCK
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
int vccPin = 5;  //пин для питания
int gndPin = 6;  //пин для земли
float tempv; // для температуры внутр. продукта
//--------------------------------------------------------------------------------------

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

//расчет мощности по ПИ закону регулирования
//_------------------------------------------------------------
#define kP 6//коэффициент пропорциональности 6
#define p_min 0.0//минимум П составляющей - не < 0
#define p_max 100.0//максимум П составляющей - не > 100 
#define kI 0.100//коэффициент интегрирования 0.025
#define i_min 0.0//минимум И составляющей
#define i_max 30.0//максимум И составляющей
#define kd 0//коэффициент диференциирования
#define d_ctl 7.0//зона пропорциональности ust-d_ctl
#define out_min 0//минимальный выходной %
#define out_max 100//максимальный выходной % 
//возвращает необходимую мощность
uint8_t PIctl(float temp, uint8_t ust) { 

  uint8_t out = 0; //uint8_t
  static float i = 0;
  static float ed=0;///
  float e, p;
  float d;///
  e = (ust - temp); //ошибка регулирования
  p=(temp<ust-d_ctl)?p_max:(temp>ust)?p_min:(kP*e);//П составляющая
  //i = (i < i_min) ? i_min : (i > i_max) ? i_max : i + (kI * e);
  i=(i<i_min)?i_min:(i>i_max)?i_max:i+(kI*e);//И составляющая
  d=kd*(e-ed);///Д составляющая
  ed=e;///
  //out = (p + i < out_min) ? out_min : (p + i > out_max) ? out_max : p + i;
  out=(p+i+d<out_min)?out_min:(p+i+d>out_max)?out_max:p+i+d;
  //   Serial.print(" e  ");
  //    Serial.print(e);
  //    Serial.print("  p ");
  //    Serial.print(p);
  //    Serial.print("  i ");
  //    Serial.print(i);
  //    Serial.print("  out ");
  //    Serial.println(out);
  return out;
}
//---------------------------------------------------------------

void setup() {
  sensors.begin();
  Serial.begin (9600);
  MsTimer2::set(500, timerInterupt); // задаем период прерывания по таймеру 500 мс 
  MsTimer2::start();              // разрешаем прерывание по таймеру
  pinMode(vccPin, OUTPUT); digitalWrite(vccPin, HIGH);
  pinMode(gndPin, OUTPUT); digitalWrite(gndPin, LOW);
}

void loop() {
    unsigned long currentMillis = millis();
    if (currentMillis - preTempMillis >= t_time) {
       sensors.setWaitForConversion(false);
       sensors.requestTemperatures();
       sensors.setWaitForConversion(true);
       temp = sensors.getTempCByIndex(0); //получаем температуру
       tempv = thermocouple.readCelsius();
       preTempMillis = currentMillis; //сброс таймера замера температуры
  }
  
  
switch (progMode) {
  case 1://авто.
  if (currentMillis - prePIctl_time >=power_time) { //если подошло время рассчитать мощность
     zad = PIctl(temp, ust); //расчет мощности
     prePIctl_time = currentMillis; //сброс таймера расчета мощности
  }
    if (millis() > 3000) { //разрешаем управление нагрузкой через 3 сек после включения устройства
     outten.lpwm(t_pwm, zad);//управление тэном 1
  }
         
         break;
  case 2://ручной.
     if (millis() > 3000) { 
     outten.lpwm(t_pwm, zad_r);
  }
         break;
  default://Тэн выключен
    zad_r=0;
    outten.lpwm(t_pwm, zad_r);
}

}//END loop
//------------------------- обработчик прерывания 
void  timerInterupt() {
  serial1();  
}

//-------------------отправка данных в serial-------
void serial1(){
 
   Serial.print("|");
   Serial.print(zad);
   Serial.print("|");
   Serial.print(zad_r);
   Serial.print("|");
   Serial.print(temp);
   Serial.print("|");
   Serial.print(tempv);
   Serial.print("|");
   Serial.println("end");
}// end serial1
//---------------------------------------------------------------

//--------------- принимаем данные и разбираем их-
void serialEvent() {
  //while (Serial.available()) {
  // получаем новый байт:
  //char inChar = (char)Serial.read();
    // добавляем его к inputString:
    //myString += inChar;
    // если получили символ новой строки, оповещаем программу об этом,
    // чтобы она могла принять дальнейшие действия.
    //if (inChar == '\n') {
     // mystringComplete = true;
    //}
 // }
}

[/code]

 

 

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

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

Например так

#include <MsTimer2.h>
#include <DigOut.h>//подключаем библиотеку выходов yadi.sk/d/NM4S6HmFrTRu6
#define t_time 1000//период опроса температуры
#define power_time 1000//период расчета мощности
DigOut outten(9);//инициализация цифровых выходов на тэн 1
unsigned long time;//интервал замера температуры
byte zad = 0; //задание мощности ТЭНа1
byte zad_r = 0; //задание мощности ТЭНа1 в ручном режиме
float temp = 0.0; //текущее значение температуры
float pre_temp = 0.0; //предыдущее значение температуры
unsigned long preTempMillis = 0; //время для опроса температуры
unsigned long prePIctl_time = 0; //время для расчета мощности
uint8_t ust = 0; //уставка
#define t_pwm 2000//период медленного ШИМ в мс
unsigned long currentMillis;//текущее время мк
byte progMode;//режим работы прибора 0-выкл, 1-авто, 2-ручной.
String myString = "";         // строка, в которую будут записываться входящие данные
boolean mystringComplete = false;  // заполнилась ли строка или нет
//---------------------Подключение термопары через MAX6675------------------------------
#include "max6675.h"
int thermoDO = 2;  //он же SO
int thermoCS = 3;
int thermoCLK = 4;  //он же SCK
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
int vccPin = 5;  //пин для питания
int gndPin = 6;  //пин для земли
float tempv; // для температуры внутр. продукта
//--------------------------------------------------------------------------------------

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

//расчет мощности по ПИД закону регулирования
//_------------------------------------------------------------
#define kP 6//коэффициент пропорциональности 6
#define p_min 0.0//минимум П составляющей - не < 0
#define p_max 100.0//максимум П составляющей - не > 100 
#define kI 0.100//коэффициент интегрирования 0.025
#define i_min 0.0//минимум И составляющей
#define i_max 30.0//максимум И составляющей
#define kd 0//коэффициент диференциирования
#define d_ctl 7.0//зона пропорциональности ust-d_ctl
#define out_min 0//минимальный выходной %
#define out_max 100//максимальный выходной % 
//возвращает необходимую мощность
uint8_t PIctl(float temp, uint8_t ust) { 

  uint8_t out = 0; //uint8_t
  static float i = 0;
  static float ed=0;///
  float e, p;
  float d;///
  e = (ust - temp); //ошибка регулирования
  p=(temp<ust-d_ctl)?p_max:(temp>ust)?p_min:(kP*e);//П составляющая
  i=(i<i_min)?i_min:(i>i_max)?i_max:i+(kI*e);//И составляющая
  d=kd*(e-ed);//Д составляющая
  ed=e;///
  out=(p+i+d<out_min)?out_min:(p+i+d>out_max)?out_max:p+i+d;
  //вывод для настройки
  //   Serial.print(" e  ");
  //    Serial.print(e);
  //    Serial.print("  p ");
  //    Serial.print(p);
  //    Serial.print("  i ");
  //    Serial.print(i);
  //    Serial.print("  out ");
  //    Serial.println(out);
  return out;
}
//---------------------------------------------------------------

void setup() {
  sensors.begin();
  Serial.begin (9600);
  MsTimer2::set(500, timerInterupt); // задаем период прерывания по таймеру 500 мс 
  MsTimer2::start();              // разрешаем прерывание по таймеру
  pinMode(vccPin, OUTPUT); 
  digitalWrite(vccPin, HIGH);
  pinMode(gndPin, OUTPUT); 
  digitalWrite(gndPin, LOW);
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - preTempMillis >= t_time) {
    sensors.setWaitForConversion(false);
    sensors.requestTemperatures();
    sensors.setWaitForConversion(true);
    temp = sensors.getTempCByIndex(0); //получаем температуру
    tempv = thermocouple.readCelsius();
    preTempMillis = currentMillis; //сброс таймера замера температуры
  }
  void modeSelect();//выбор режима работы
  if (millis() > 3000) {//если с момента включения прошло более 3000мс
    outten.lpwm(t_pwm, zad);//управление теном
  }
}//END loop
//------------------------- обработчик прерывания 
void  timerInterupt() {
  serial1();  
}

//-------------------отправка данных в serial-------
void serial1(){

  Serial.print("|");
  Serial.print(zad);
  Serial.print("|");
  Serial.print(zad_r);
  Serial.print("|");
  Serial.print(temp);
  Serial.print("|");
  Serial.print(tempv);
  Serial.print("|");
  Serial.println("end");
}// end serial1
//---------------------------------------------------------------

//--------------- принимаем данные и разбираем их-
void serialEvent() {
  //while (Serial.available()) {
  // получаем новый байт:
  //char inChar = (char)Serial.read();
  // добавляем его к inputString:
  //myString += inChar;
  // если получили символ новой строки, оповещаем программу об этом,
  // чтобы она могла принять дальнейшие действия.
  //if (inChar == '\n') {
  // mystringComplete = true;
  //}
  // }
}

//-------------установка задания в соответствии с выбранным режимом------------------
void modeSelect(){
  switch (progMode) {
  case 1://авто.
    if (currentMillis - prePIctl_time >=power_time) { //если подошло время рассчитать мощность
      zad = PIctl(temp, ust); //расчет мощности
      prePIctl_time = currentMillis; //сброс таймера расчета мощности
    }
    break;

  case 2://ручной.
    zad=zad_r;
    break;

  default://Тэн выключен
    zad=0;
  }
}

Вы случайно графики выхода на уставку не снимали? интересно былобы посмотреть.

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

Нет не снимал, если честно то даже не знаю как.

soznik
Offline
Зарегистрирован: 20.09.2015

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

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

На прошлой неделе тоже над графиками работал, экранчик тоже 128х64 OLED. Вот что у меня вышло http://arduino.ru/forum/programmirovanie/pomogite-razobratsya-s-displeem...
Но тамошних это не заинтересовало, может Вам мои наработки покажутся интересными. Код конечно не оптимальный но рабочий. У меня стояла задача с помощью одной функции выводить график по данным из разных массивов, в заданом месте экрана и задоных размерах. По пути натыкался на такие камни как начало координат экрана в верхнем левом углу, а у графика нижний левый. Потом долго думал дня 4 над автомасштабированием, перечитал всю школьную геометрию... ,а окащалось всё очень просто. Если мой код смотреть будите то увидите как я там выкрутился, после 4 дней разрыва мозга пришло решение из одной строчки))).

soznik
Offline
Зарегистрирован: 20.09.2015

Как-то делал барограф на дисплее от нокиа . После переделал на дисплей 12864  3,2" http://arduino.ru/forum/proekty/arduino-barometr-barograf#comment-246915

А барограф на нокиа переделал в термограф 

вот код

 #include <DallasTemperature.h>    
   #include <OneWire.h> 
   #include <SPI.h>
   #include <Adafruit_GFX.h>
   #include <Adafruit_PCD8544.h>
   
   #include <Wire.h>
   #include <avr/sleep.h>
   #include <avr/wdt.h>
   #include <EEPROM.h>
  

   #define CNT 2            //  количество циклов по 8 секунд от работы до работы
   int count1 = 0 ;          //  переменная для счётчика циклов по 8 сек
   volatile boolean wdt_tripped=1;
   ////////////  активизируем дисплей  //////////////////
   Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 2, 8);
   #define temp 10    //DS18B20 назначаем вход для датчика,в данном случае 10 
   OneWire oneWire(temp);             
   DallasTemperature sensors(&oneWire); 
   float tempext = 0; 

  
   // float temp = 0 ;

   float tempgraph ;
   byte tempEP    ;       //  высота столбца в памяти
   byte addressP = 0;      //  адрес записи высоты столбца 
   int adresP      ;       //  адрес считывания высоты столбца 
   byte cycle = 0  ;       //  колличество столбцов в графике
   int adrP = 59 ;         //  место столбца графика
   int cons = 0 ;          //  константа высоты столбца
   const int analogInPin = A0;  // Analog input pin 
   float sensorValue = 0;        
   float outputValue = 0;        

   void setup()
   {
   sensors.begin();   // запуск датчика OneWire, в данном случае только один DS18B20 
   wdt_disable();          //  активация пробуждения 
   wdt_reset();            //  по сторожевому таймеру
   wdt_enable(WDTO_8S);    //  каждые 8 сек (меньше - для настройки)             
   Wire.begin();
      //  

   display.begin();        //  старт дисплея
   delay(500); 
   display.setContrast(55);
   display.clearDisplay();
   Serial.begin(9600); 
   adresP = addressP ;     //  начальный адрес чтения - текущий адрес записи
}

void loop()
{
    sensors.requestTemperatures();    //запрос на чтение значений всех датчиков  повешинных на Arduino. в этом случае только один DS18B20 
    tempext=sensors.getTempCByIndex(0); 
    tempgraph= tempext ;
  sensorValue = analogRead(analogInPin);            
  outputValue = float(analogRead(analogInPin))/204,6;
  // 1023 аналог / 5V =204,6
  // просыпаемся смотрим сколько циклов по 8 сек. спали
   wdt_interrupt_mode(); 
   if (wdt_tripped ==1) 
 {
   count1++;
   wdt_tripped = 0; 
   if (count1 == CNT)                   //  если уже "пора" 
   {  
  /////////////  устанавливаем константу величины столбца в зависимости от текущего давления /////////////////

 

  if ( tempgraph< 30)
  {cons = 44;}
  if ( tempgraph< 20)
  {cons = 34;}
  if ( tempgraph< 10)
  {cons = 24;}
  if ( tempgraph < 0)
  {cons = 14;}
  if (tempgraph < -10)
  {cons = 4;}
  if (tempgraph < -20)
  {cons = -6;}
 
 
  delay(100);
  
  /////////////  пишем высоту столбца в EEPROM /////////////////////////////
   
   EEPROM.write(addressP,(cons - tempgraph)*2);  // от константы отнимаем текущее давление , вписываем 10мм давления  в (48 - 28) величину столбца, 1мм давления-2пикселя
                                            
   grafik();                                //  рисуем график       
   addressP = addressP + 1;                 //  устанавливаем следующий адрес  
   if (addressP >= 60)                      //  адреса 0 - 60
   {addressP = 0;}
   count1 = 0;      
 }
 }
    //   и снова "баюшки"
    sleepNow();
}
                     //////  ФУНКЦИИ  //////

/////////////////  рисуем график  ////////////////////////
  void grafik()
  { 
    display.clearDisplay();                //  очищаем дисплей
    temperat();                            //  рисуем текущее давление и все надписи
    display.setTextColor(BLACK);
    adresP = addressP ;                    //  начальный адрес чтения - текущий адрес записи
    for (cycle = 0; cycle <60; cycle ++)   //  60 циклов вывода линий на дисплей
    { 
    stolb();
    }
    display.display();
    delay(100);
  }
//////////////  текущая температура и все надписи на дисплей //////////////
  void temperat()
 {  
   display.clearDisplay();
   display.setTextSize(2);             // покрупнее
   display.setTextColor(BLACK);
   display.setCursor(0,0);
   display.print(tempext,1);             // 
   display.println("*C");
   display.setTextSize(1);
   display.setCursor(1,17);
   display.print("<-24hour->");
   display.println(outputValue,1);
 
   display.setCursor(58,21);
   display.println("_");   
   ////////////  пределы отображения temp  ////////////
   display.setCursor(63,27);
   if (cons == 44)
   {display.println("+30");}  
   if (cons == 34)
   {display.println("+20");}  
   if (cons == 24)
   {display.println("+10");}        
   if (cons == 14)
   {display.println("  0");}
   if (cons == 4)
   {display.println("-10");}
   if (cons == -6)
   {display.println("-20");}
   //display.setCursor(63,34);
   //display.println("-");
   display.setCursor(58,41);
   if (cons == 44)
   {display.println("_+20");}  
   if (cons == 34)
   {display.println("_+10");}  
   if (cons == 24)
   {display.println("_  0");}
   if (cons == 14)
   {display.println("_-10");}
   if (cons == 4)
   {display.println("_-20");}
   if (cons == -16)
   {display.println("_-30");}
 
   display.display();
 }
 //////////////// прорисовка одного столбца  ///////
 void stolb()
 { 
   tempEP = EEPROM.read(adresP);                     //  читаем из памяти высоту столбца
   display.drawLine (adrP, tempEP, adrP,48 , BLACK);  // рисуем столбец (tempEP вместо 48 - получим одну линию)

   adrP = adrP - 1;                                   // устанавливаем место следующего столбца
   if (adrP < 0)                                      // следим за местом
   {adrP = 59 ; }                                     // при переходе через начало ставим в конец
   adresP = adresP - 1 ;                              // устанавливаем следующий адрес памяти
   if (adresP < 0)                                    //  следим за адресом
   {adresP = 59 ;}   
 }

 ///////////  здесь мы просто просыпаемся
   void wdt_interrupt_mode() 
   {
   wdt_reset();
   WDTCSR |= _BV(WDIE);                 // Restore WDT interrupt mode
   }
   ISR(WDT_vect) 
   {
   wdt_tripped=1;                       // set global volatile variable
   }

/////////////  а здесь засыпаем 
   void sleepNow()   
{
   _SFR_BYTE(ADCSRA) &= ~_BV(ADEN);
   set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // Здесь устанавливается режим сна
   sleep_enable();                        // Включаем sleep-бит в регистре mcucr. Теперь возможен слип 
   _SFR_BYTE(ADCSRA) |= _BV(ADEN);
   sleep_mode();                          // Здесь устройство перейдет в режим сна!!!
}

фото      https://drive.google.com/file/d/0B0AIJgNiGhqQYXB2ZVFTVDZwRUk/view?usp=sharing

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

 

Пытаюсь написать код для приёма и сортировки данных от андроид

данные получаю в myString, потом перебераю по первому символу к какой переменной относится значения
но при конвертации byte(myString); данные обнуляются ны выходе 0
что я делаю не так?

[code]
String myString =  "";
byte zad_r = 0; //задание мощности ТЭНа1 в ручном режиме
uint8_t ust = 0; //уставка необходимой темперетыру
byte progMode;//режим работы прибора 0-выкл, 1-авто, 2-ручной.
byte kP= 6;//коэффициент пропорциональности 6
float kI =0.100;//коэффициент интегрирования 0.025
byte kd =0;//коэффициент диференциирования
float d_ctl= 7.0;//зона пропорциональности ust-d_ctl

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

void loop() {
    if(myString.startsWith("a")){//режим работы прибора 0-выкл, 1-авто, 2-ручной.
    myString=myString.substring(1);
    Serial.print("myString - ");
    Serial.println(myString);
    byte(myString);
    Serial.print("BYTEmyString - ");
    Serial.println(myString);
    progMode=myString;
    Serial.print("progMode- ");
    Serial.println(progMode);
    myString="";
    }
    if(myString.startsWith("v")){//задание мощности ТЭНа1 в ручном режиме
    myString=myString.substring(1);
    byte(myString);
    zad_r=myString;
    Serial.print("zad_r- ");
    Serial.println(zad_r);
    myString="";
    }
    if(myString.startsWith("u")){//уставка
   myString=myString.substring(1);
   byte(myString);
   ust=myString;
    Serial.print("ust- ");
    Serial.println(ust);
    myString="";
    }
    if(myString.startsWith("z")){//зона пропорциональности ust-d_ctl
     myString=myString.substring(1);
     byte(myString);
     d_ctl=myString;
    Serial.print("d_ctl- ");
    Serial.println(d_ctl);
    myString="";
    }
    if(myString.startsWith("p")){//коэффициент пропорциональности
    myString=myString.substring(1);
    byte(myString);
    kP=myString;
    Serial.print("kP- ");
    Serial.println(kP);
    myString="";
    }
    if(myString.startsWith("i")){//коэффициент интегрирования
    myString=myString.substring(1);
    byte(myString);
    kI=myString;
    Serial.print("kI- ");
    Serial.println(kI);
    myString="";
    }
    if(myString.startsWith("d")){//коэффициент диференциирования
   myString=myString.substring(1);
   byte(myString);
   kd=myString;
    Serial.print("kd- ");
    Serial.println(kd);
    myString="";
    }
}

void serialEvent(){
  Serial.println("serialEvent");
  myString = Serial.readStringUntil('\n');
  ser2();
  }
  
void ser2(){
  Serial.print("kd- ");
  Serial.println(kd);
  Serial.print("kI- ");
  Serial.println(kI);
  Serial.print("kP- ");
    Serial.println(kP);
    Serial.print("d_ctl- ");
    Serial.println(d_ctl);
    Serial.print("ust- ");
    Serial.println(ust);
    Serial.print("zad_r- ");
    Serial.println(zad_r);
     Serial.print("progMode- ");
    Serial.println(progMode);
  }


[/code]

 

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

Я этим давно не пользовался, но там вроде нужно что то вроде (if (Serial.available>0)//если есть данные....{//обрабатываем}). точно не помню, не пользуюсь пока блютус.

А может в сторону RemoteXY посмотреть, там вроде просто всё.

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

yul-i-an пишет:

Я этим давно не пользовался.......

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


//---------------------для настройки по сериал------------------------------
String myString =  "";
String now_t;
String off_t;
String on_t;
//------------------------------------------------------------------
void loop(){
  set();
  }
//-------------------функция принятия настроек по сериал-------
//-ждет ввода тек.время(в мин):время выкл(в мин):время вкл(в мин)--
void set(){
  if (Serial.available() ==14) {
    myString = Serial.readString();
    now_t = getValue(myString, ':', 0);
    off_t = getValue(myString, ':', 1);
    on_t = getValue(myString, ':', 2);
    Serial.print("NOW:" + now_t);
    Serial.print(" OFF:" + off_t);
    Serial.print(" ON:" + on_t);
    timer=now_t.toInt();
    timer_off=off_t.toInt();
    timer_on=on_t.toInt();
    //float  xvalue = xval.toInt();
    //Serial.println((xvalue)/100.0);    
  }
}
//--парсер данных с сериал---------------------------------
String getValue(String data, char separator, int index){
  int found = 0;
  int strIndex[] = {
    0, -1              };
  int maxIndex = data.length()-1;
  for(int i=0; i<=maxIndex && found<=index; i++){
    if(data.charAt(i)==separator || i==maxIndex){
      found++;
      strIndex[0] = strIndex[1]+1;
      strIndex[1] = (i == maxIndex) ? i+1 : i;
    }
  }
  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
//---------------------------------------------------------------------

Там к стати и программа для appinventor с голосовым управлением.

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

Спасибо, будем думать.

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

Вот еще занятный варийант http://arduino.ru/forum/obshchii/upravlyaem-arduinoi-cherez-internet

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

к посту #119

Не хотит работать так
void modeSelect();//выбор режима работы
я так предполагаю  void лишняя, убрал, в modeSelect(); стал заходить
но там при progMode=1 пролетает мимо switch 

 

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

Попробуйте в начале кода исправит byte progMode на byte progMode=1;

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

это я и сделал сначала , хотел проверить... и упс

в modeSelect() заходит дальше нет

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

Тогда передайте его в виде параметра в void modeSelect(byte mode){
switch (mode)
...

в loop будет modeSelect(progMode);

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

сделал не работает

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

Я с телефона сижу. Мне неудобно сейчас. Вечером гляну. А Вы пока с передачей заданий попробуйте разобраться.

soznik
Offline
Зарегистрирован: 20.09.2015

Знаю что оператор if здесь не кто не любит, а если сделать так

 int regim=1;
  int analog=0;
void setup() {
  // put your setup code here, to run once:

}

void loop() {
      analog=analogRead(16);//считываем сигнал с пина АЦП  кнопки  (А2)

    if(analog<100)//если кнопка 1 нажата   
     { 
       regim=1; 
                }
    if(analog>700&&analog<800)//если кнопка 2 нажата   
     { 
       regim=2; 
                }
    if(analog>800&&analog<900)//если кнопка 3 нажата   
     { 
       regim=3; 
     }
if(regim==1)//первый режим
   { if (currentMillis - prePIctl_time >=power_time) { //если подошло время рассчитать мощность
      zad = PIctl(temp, ust); //расчет мощности
      prePIctl_time = currentMillis; //сброс таймера расчета мощности
    }
   }
                
}

 

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

Можно и так, Вы же не спутник к Марсу запускаете. Главное чтобы работало на данный момент. У меня в коде ссылку на который выше выкладывал тоже примерно так было. Только у меня там отдельная функция была key().

soznik
Offline
Зарегистрирован: 20.09.2015

Если все-же огромное желание прикошачить к устройству смартфон тогда надо подключать ESP-8266

Для контроля и построения графика (хоть на год) сайт narodmon.ru

А если регулировка и контроль то blink https://esp8266.ru/esp8266-blynk/

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

soznik пишет:

Если все-же огромное желание прикошачить к устройству смартфон тогда надо подключать ESP-8266

Для контроля и построения графика (хоть на год) сайт narodmon.ru

А если регулировка и контроль то blink https://esp8266.ru/esp8266-blynk/

Я тоже долго думаю что выбрать для удаленного мониторинга и управления. Мне на дачу нужно. Решил пока следующее, в помещении планшет или смартфон (стационарно, с него ввод и вывод на девайс) подключен к интернету по средствам 3G и т.п. к нему через BT подключен девайс. На него в appinvertor собирается приложение для просмотра и задания настроек, которое в свою очередь сохроняет всю инфу в WebDB, на свой смартфон устанавливливаю это же приложение и использую как RemoteControl, т.к. они используют одну БД. Или осваивать MySql, HTTP и PHP со всеми вытекающими (но пользы больше будет).

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

yul-i-an

если switch перенести в основной цикл все работает
в отдельной функции в case 1 заходит не выполняется условия if
я так предполагаю дело в 
currentMillis, не могу догнать как исправить

Спасибо вроде разобрался, всё заработало.

 

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

Bizard2000, так тоже нормально. Осталрсь только с управлением через смартфон разобратся.
А что Вы собираете? В работе опробовали уже? Как температуру держит?

soznik
Offline
Зарегистрирован: 20.09.2015

sim модули пробовали использовать. У меня с ними ничего не получается уже привез из китая 3 вида ни один не хочет регистрироватся в наших сетях . Один явно надо пробовать менять прошивку SIM900A ,  а neowey m590e должен работать в наших сетях  и ещё один SIM 800-ый регистрировался , но постоянно пропадала связь. Пробовал подключится к телефону alcatel onetouch (у него есть на плате площадки Rx & Tx) , но у него не смог вытащить SMS-ки.

 

 

 

 

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

С управлением через андроид вроде разобрался. Делаю контроллер для управления температурой в коптильной камере, увлекаюсь домашним колбасированием, там надо  температуру держать плюс минус 2 градуса ну и режимы разные,  холодное, горячее копчение и т.д.. В работе сегодня попробовал чуток пока коптил, ПИД настройками пока не шаманил, те что у вас стояли держит  +1 -2, минут 10 в режим выходил.

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

Если на режиме болтаеться немного - kI великоват
Если выходит долго - kP маловат или зона пропорциональности широкая.

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

Перекачайте DigOut или тут DigOut, профиксил немного.

 

obuhanoe
Offline
Зарегистрирован: 18.05.2016

Добрый день.

Озадачил меня друг, гонит самогонку и хочет часть автоматизировать - но в программировании не понимает.

Я немного разбераюсь в программировании, но вот с управлением ТЭНами не сталкивался еще. Прочитал данную тему, но не понял одного - какое реле можно использовать для этого.

Например если взять мегу2560,  твердотельное реле SSR серии как я понял LA (например SSR -25LA) или вместо него нужно другое что-то преобрести?

ТЭН мощностью 3,6Квт.

Спасибо

evgta
Offline
Зарегистрирован: 02.09.2016

Оно пойдет. Тут больше спор о том можно ли шиммировать такую большую нагрузку или нет. У этого реле время переключения 10мс.

При такой нагрузке обязательно радиатор с вентилятором ставить

obuhanoe
Offline
Зарегистрирован: 18.05.2016

Оно подойдет, но одновременно и большая мощность. Какой же тогда выход? Каким образом регулировать ТЭНы ?

Спасибо

evgta
Offline
Зарегистрирован: 02.09.2016

Включаем тэн на 1-бесконечность.выключаем на 1-бесконечность.
секунд .на шиме просто нестоит делать.

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

obuhanoe пишет:

Оно подойдет, но одновременно и большая мощность. Какой же тогда выход? Каким образом регулировать ТЭНы ?

Спасибо

Скорее всего ТЭНы вы будете питать от переменного  220. Если брать за период 100 полуволн. Если пропустить 100 полуволн то у вас 100% мощности . Если 50 полуволн то 50% . Осталось только ловить переход через ноль и считать сколько полуволн пропустить, а сколько оставить.  Но вам же нужна не теория и принцип реализации, а рабочий код. Так ведь не все называющие себя программистами и могущие хоть как то кодить на деле программисты. Это как маляр тоже может себя называть художником, но это не значит, что он может написать картину маслом. А вот с покраской стены в однотонный цвет впролне справится, тем более и этот труд востребован.

obuhanoe
Offline
Зарегистрирован: 18.05.2016

qwone пишет:

obuhanoe пишет:

Оно подойдет, но одновременно и большая мощность. Какой же тогда выход? Каким образом регулировать ТЭНы ?

Спасибо

Скорее всего ТЭНы вы будете питать от переменного  220. Если брать за период 100 полуволн. Если пропустить 100 полуволн то у вас 100% мощности . Если 50 полуволн то 50% . Осталось только ловить переход через ноль и считать сколько полуволн пропустить, а сколько оставить.  Но вам же нужна не теория и принцип реализации, а рабочий код. Так ведь не все называющие себя программистами и могущие хоть как то кодить на деле программисты. Это как маляр тоже может себя называть художником, но это не значит, что он может написать картину маслом. А вот с покраской стены в однотонный цвет впролне справится, тем более и этот труд востребован.

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