Контроллер паяльного фена-2 (по мотивам OlegK)

sva_khv
Offline
Зарегистрирован: 19.12.2016

Вдохновившись  проектом ОлегК

(http://arduino.ru/forum/proekty/kontroller-payalnogo-fena)

решил сделать себе паяльный фен.

Заказал фен на али за 700руб.  Пока посылка шла, определился со схемой устройства.

Основные принципы исходя из которых делал:

  1. Элементная база – из запасов, покупать только в крайнем случае. (запасы имеются хорошие J)
  2. Программу пишу сам, соответственно устройство делает все как я хочу. (с программированием  проблем нет)
  3. Между крутым (красивым модным) и практичным выбираю практичность.  (сенсорное управление, графические дисплеи и т.д. всем наигрался, применить не проблема, но только когда это оправдано).

 

sva_khv
Offline
Зарегистрирован: 19.12.2016

Схема

Измерение температуры.

Выполнил по схеме OlegK. Понравилось установка начального смещения на термопаре при комнатной температуре. Я применил ОУ какой был под руками  и решил подать на него такое питающее напряжение при котором при перегрузке по входу на выходе ОУ получается 4.6-4.8 В. Соответственно диапазон напряжений при измерении получается в интервале 0,2-4,4В.  Подобрал стабилитрон КС170. Кстати узнал, что он симметричный.  Настройка аналогично как у OlegK.

Питание.

Подобрал трансформатор чтобы после диодного моста и конденсатора при включении вентилятора фена получилось 23,5В (на холостом ходу 26,5В). Поэтому 24В не стабилизированные.

 

sva_khv
Offline
Зарегистрирован: 19.12.2016

Управление нагревателем.

Сперва начал собирать детали как у OlegK. Но тут подобрал пару плоских ТВ на разборку. Выломал с них высоковольтные  диодные мосты, полевики, конденсаторы. И решил - а почему не попробовать подавать на нагреватель постоянное напряжение 300В и регулировать его ШИМом? Не получиться – всегда под руками комплект с тиристором и детектором нуля.

Вылезла проблема: если ставить после выпрямителя конденсатор большой емкости надо ограничивать бросок тока при зарядке конденсатора при включении. Если маленький кондер – напряжение на нагрузке не постоянное, а пульсирующее. Решил не городить схему с ограничением зарядного тока, а поставить кондер не большой емкости. Поставил на 68мкФ. Подключил лампу накаливания на 150Вт. Согрел полевик. Совсем забыл что при начальном включении спираль лампы накаливания холодная и ток гораздо больше рабочего. Подключил лампу без полевика, напрямую. Пульсации порядка 40В. Прикинул что не критично и продолжил эксперименты. Дальше подводных камней не было. ШИМ ограничил максимум 40% . Собрал макет, запустил.  Транзистор греется прилично, радиатор для него взял так же с раскуроченного ТВ. Диодный мост сразу был на радиаторе, с ним и применил. Но он почти не греется.

Взял железный  корпус от сгоревшего маршрутизатора, в него все запихал.

Платы я не травил – собрал на макетках.

Почитал про ПИД  регулирование. Поэкспериментировал с коэффициентами. Пропорциональный и Интегральный определил опытным путем, Дифференциальный эффекта не дал.

Интервал регулировки ставил 100 и 50 мСек – разницы нет.

Вентилятор регулирую от 50 до 100% ШИМ.

 

sva_khv
Offline
Зарегистрирован: 19.12.2016

Вне зависимости от скорости вентилятора температура на ТП поддерживается с точностью 1-3 отсчета АЦП. Переодически отклонение уплывает до 7-10. При одной и той же температуре на ТП и при разной скорости вентилятора (50 и 100%) разница в температуре воздуха на выходе из фена градусов в 10-15. Причем температура выше при максимальной скорости вентилятора. Получается при малой скорости вентилятора воздух остывает пока дойдет до выхода.  Сейчас ввожу поправочный коэффициент в зависимости от скорости вентилятора.

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

 

sva_khv
Offline
Зарегистрирован: 19.12.2016

Функции которые сделал:

- Время работы 10 мин, за 1 мин до окончания каждые 15 сек звуковой сигнал. Если нажать кнопку старт или  изменить температуру или скорость вентилятора – отсчет начинается с начала.

- Продувка после окончания работы до охлаждения до 50  грС. И потом контрольная додувка 30 сек. Если дуем 10 мин и не остыл – сообщение об ошибке, зумер и дуть не перестаем.

- контролируем обрыв термопары и превышение максимально допустимой температуры.

- во время работы показываем заданную температуру и фактическую на термопаре (с учетом поправки на скорость вентилятора.)

 

Доделываю:

- звуковой сигнал

- коррекцию температруры в зависимости от скорости вентилятора.

 

Геркон использовать не стал – не хватило контактов в разъеме.

 

sva_khv
Offline
Зарегистрирован: 19.12.2016

sva_khv
Offline
Зарегистрирован: 19.12.2016

sva_khv
Offline
Зарегистрирован: 19.12.2016

Программа

/* Фена паяльный  температура от 40 до 400 грС
пищалка за 1 мин до отключения

*/
#include <LedControl.h>   // LED 7-сегментный  8 сим

// ПОРТЫ ВВ  =======================================================
//  2,3,4 - LED
#define PIN_RELE                2
#define PIN_KNOPKA_RABOTA       6
#define PIN_KNOPKA_STOP         7
#define PIN_SIGNAL              8
#define PIN_VKL_REG_NAGR        9
#define PIN_VKL_REG_VENT       10

#define PIN_ACP_TC             A0 
#define PIN_ZAD_VENT           A1 
#define PIN_ZAD_TEMP           A2

// константы =====================================
#define VENT_PROC_MIN         50      // задание мощности вентилятра резистором
#define VENT_PROC_MAX         100
#define VENT_ACP_MIN          10
#define VENT_ACP_MAX          1010

#define TEMP_ZAD_MIN          40      // задание температуры фена резистором
#define TEMP_ZAD_MAX          400
#define TEMP_ACP_ZAD_MIN      10
#define TEMP_ACP_ZAD_MAX      1010

#define KOEF_ACP_TO_GR        1.72 //          2.14    коэфф пересчета значений АЦП ТП в градусы 

//временные интервалы =======================================
#define TIME_REG_TEMP           50ul        // (мс) период контроля темп и регулировки 
#define TIME_POKAZ_INFO         500       // (мс) интервал отображения инфо
#define TIME_RABOTA_AUTO_OFF    10        //10  (мин)  работа до автоматической остановки (за 1 мин до выкл начинает пищать звук)
#define TIME_PRODUV_MAX         10        // (мин) мax время  продувки после окончания прогрева (при превышении этого времени -  ошибка)
#define TIME_PRODUV_DOPOL       30000ul   // (мс) время дополнительной продувки после остывания меньше 50 грС   

int iRerimTek;                  // текущий режим работы
#define REGIM_WORK            5
#define REGIM_ERR             9
#define REGIM_PRODUV          8
#define REGIM_OFF             1
#define REGIM_TEST            2
#define REGIM_OTLADKA        91

//коды текстовых сообщений сообщений на 7сегментном индикаторе
#define KOD_TEXT_ERR            9
#define KOD_TEXT_TEST           2
#define KOD_TEXT_RAB            5
#define KOD_TEXT_OFF            1
#define KOD_TEXT_PRODUV         8

//коды ошибок  1ХХ  - при включении 2ХХ при работе  3ХХ - при выключении
#define KOD_ERR_ACP_TP_MAX        101  //- не работает ТП (обрыв)
#define KOD_ERR_TEMP_MAX          201  //- превышена макс температура
#define KOD_ERR_PROD_MAX_TIME     301  //- превышено макс время продувки
#define KOD_ERR_STOP_PRI_GORIACH  302  //- остановка при горячем фене

// время ==============================
unsigned long ulTimeRegTemp;       // период опроса температуры 
unsigned long ulTimePokazInfo;     // контроль периода отображения инфо
unsigned long ulTimeProduv;        // время продувки 
unsigned long ulTimeProduvDopol;   // время продувки дополнительной после остывания примерно 30 сек
unsigned long ulTimeWork;          // время до автоматического отключения (за 1 мин звуковой сигнал каждые 15 сек) 

// ПИД =====================================================
#define NAGR_SIG_REG_MAX     40    
#define TP_MAX_TEMP          400
#define TP_ACP_ERR           900

#define PID_KOEF_P       1.1   //1.3
#define PID_KOEF_I       0.01  //0.01
#define PID_KOEF_D       -0.05 //-0.05

float flPIDInSig,flPIDInSig_1,flPIDDiSig,flPIDPrSig;
int iPIDRaz,iPIRaz_1;
int iErrKod;

// параметры регулировки ===============================
int iACP_Tp;
int iACPTP_ZAD,iACPTP_ZAD_OLD ;  // задаваемое значение АЦП ТП
int iVentVklProc,iVentVklProcOld;
int iNagrVklProcent;

// индикатор
LedControl led8=LedControl(3,5,4,1);   // 3,5,4  LedControl(dataPin, clkPin, csPin, numDevices=1);   

// звуковой сигнал
#define ZVUK_1K_SIG         1            // один короткий 
#define ZVUK_1D_SIG         2            // один длинный
#define ZVUK_3K_SIG         3            // три коротких
#define ZVUK_1P_SIG         4            // постоянно гудит

int iZvukVid,iZvukTek;     // вид сигнала и этап переключения звука
int iZvukTimeWork15;       // счетчик подачи сигналов перед выключением по таймеру
unsigned long ulZvukTime;   // время с начала подачи сигнала   

// отладка
int iPrintPort=0;

//=====================================================================================
void setup() 
{
    Serial.begin(9600);  
// настройка портов    
    pinMode(PIN_VKL_REG_NAGR, OUTPUT);  
    pinMode(PIN_VKL_REG_VENT, OUTPUT);  
    pinMode(PIN_RELE, OUTPUT);  
    pinMode(PIN_SIGNAL, OUTPUT); 
    
    digitalWrite(PIN_VKL_REG_NAGR, LOW);      
    digitalWrite(PIN_VKL_REG_VENT, LOW);     
    digitalWrite(PIN_RELE, LOW);         
    digitalWrite(PIN_SIGNAL, LOW);   

    pinMode(PIN_KNOPKA_RABOTA, INPUT_PULLUP);  
    pinMode(PIN_KNOPKA_STOP, INPUT_PULLUP);  
// инициализация индикатора    
    led8.shutdown(0,false); 
    led8.setIntensity(0,5); // яркость дисплея    
    led8.clearDisplay(0);  // очистить дисплей      
// переменные по времени
    ulTimePokazInfo=ulTimeRegTemp=0;
// настройка ШИМ  
    flPIDInSig=flPIDInSig_1=flPIDDiSig=flPIDPrSig=0.0;
    iACP_Tp=TempTpACPGet();     
//     
    iErrKod=0;
   iVentVklProcOld=iVentVklProc=0;     
   iACPTP_ZAD=iACPTP_ZAD_OLD=0;
// включение вентилятора на 2 сек
//    digitalWrite(PIN_RELE, HIGH);  
    VentVklSkorost(100); 
//    digitalWrite(PIN_RELE, HIGH);   //  HIGH
//PrintText4L(KOD_TEXT_ERR,1);       delay(50);PrintText4L(KOD_TEXT_TEST,1);      delay(50);PrintText4L(KOD_TEXT_RAB,1);       delay(50);PrintText4L(KOD_TEXT_OFF ,1);      delay(50);PrintText4L(KOD_TEXT_PRODUV ,1);   delay(50);   

    digitalWrite(PIN_RELE, LOW);   //  HIGH
    VentVklSkorost(0);
// при включении режим стоп
    RegimSet(REGIM_OFF); 
//???? RegimSet(REGIM_OTLADKA); 
    
    
// если при включении нагреватель горячий - режим продувка
   if(TempTpToGrad(TempTpACPGet())>70)    RegimSet(REGIM_PRODUV); 
// короткий сигнал при включении   
   ZvukStart(ZVUK_1K_SIG);
}

//===============================================================================
void loop() 
{  
int i,iD,iM,iMF,iMR,i2;  
long lTime2;
  while(true)
  {
// нажатие на кнопок ПУСК/СТОП
    if(digitalRead(PIN_KNOPKA_RABOTA)==LOW)
    { if(iRerimTek!=REGIM_WORK)  RegimSet(REGIM_WORK); 
      else  TimeSetWorkOff();   // обнуление счетчика для отключения работы по таймеру
      ZvukStart(ZVUK_1K_SIG);
    }
    if(digitalRead(PIN_KNOPKA_STOP)==LOW&&(iRerimTek!=REGIM_PRODUV&&iRerimTek!=REGIM_OFF)) 
    { RegimSet(REGIM_PRODUV); 
      ZvukStart(ZVUK_1K_SIG);
    }            
// контроль  неисправности ТП
// неисправность ТП -идем на  продувка по таймеру     
    if(TempTpACPGet()>TP_ACP_ERR) {iErrKod=KOD_ERR_ACP_TP_MAX;RegimSet(REGIM_ERR);}
//первышение максимальной температуры 
    if(TempTpGradGet()>=TP_MAX_TEMP+20) {iErrKod=KOD_ERR_TEMP_MAX;RegimSet(REGIM_ERR);}
// режимы работы 
    switch(iRerimTek)
    {
// ВЫКЛ =====================================================       
       case REGIM_OFF:   // 
         digitalWrite(PIN_RELE, LOW);
         NagrevSetMosh(0);
         VentVklSkorost(0);
    
       break;    
       
// ПРОДУВКА =====================================================       
       case REGIM_PRODUV:   // продувка перед выключением
         digitalWrite(PIN_RELE, LOW);
         NagrevSetMosh(0);
         VentVklSkorost(100);
         i=TempTpToGrad(TempTpACPGet());
         if(i<50) 
         {  if(ulTimeProduvDopol==0) ulTimeProduvDopol=millis();  // засекаем время доп продувки
            else
            {  if(millis()-ulTimeProduvDopol>TIME_PRODUV_DOPOL)   RegimSet(REGIM_OFF);  // переход в режим OFF
            }        
         }
         else
         {  if(millis()-ulTimeProduv>60000ul*TIME_PRODUV_MAX)  // дуем  не более 10 мин
            { iErrKod=KOD_ERR_PROD_MAX_TIME;
              RegimSet(REGIM_ERR);
            } 
            ulTimeProduvDopol=0; 
         }
         break;
         
// ОТЛАДККА  =====================================================      
      case REGIM_OTLADKA:   
        RegimSet(REGIM_OFF); 
      break;
      
// РАБОТА =====================================================      
      case REGIM_WORK:   // работа
        if(millis()-ulTimeRegTemp>TIME_REG_TEMP&&millis()>ulTimeRegTemp)   // регул  темп 
        { ulTimeRegTemp=millis();   
// задание скорости вентилятора
          iVentVklProc=VentGetProc();
          VentVklSkorost(iVentVklProc);  
          if(iVentVklProc!=iVentVklProcOld) 
          {  iVentVklProcOld=iVentVklProc; 
             TimeSetWorkOff();   // обнуление счетчика для отключения работы по таймеру
          }   
//if(iPrintPort!=0){  Serial.print(" iVentVklProc = "); Serial.print(iVentVklProc); }            
// измерение температуры   
          i=TempTpACPGet();
// заданая темп
          i2=TempZadGet();
          iACPTP_ZAD=TempZadFromGrToAcp(i2);
          if(iACPTP_ZAD!=iACPTP_ZAD_OLD) 
          {  iACPTP_ZAD_OLD=iACPTP_ZAD; 
            TimeSetWorkOff();   // обнуление счетчика для отключения работы по таймеру
          }   
// корректировка заданного значения АЦП при изменении (уменьшении) силы потока воздуха
          i2=TempZadKorrVen(iACPTP_ZAD,iVentVklProc); 
//if(iPrintPort!=0){  Serial.print(" iVentVklProc = "); Serial.print(iVentVklProc); Serial.print(" iACPTP_ZAD = "); Serial.print(iACPTP_ZAD);Serial.print(" iACPTP_KORR = "); Serial.println(i2);}            
//if(iPrintPort!=0){  Serial.print(" TempZadGet = "); Serial.println(i2); }           
          if(iACP_Tp-i<30&&iACP_Tp-i>-30) iACP_Tp=i;   // проверка большого отклонение АЦП если большое отклонение - считываем еще раз
          else  iACP_Tp=TempTpACPGet();                //  
          iD=iACPTP_ZAD-iACP_Tp;  // разница
// расчет ПИД      
          iMR=PIDRaschet(iD);
          if(iD<-20||iMR<0) iMF=0; 
          else
          { if(iMR>NAGR_SIG_REG_MAX) iMF=NAGR_SIG_REG_MAX; 
            else iMF=iMR;
          }  
          NagrevSetMosh(iMF);  
//if(iPrintPort!=0&&1==1)
//{  Serial.print(" iACPTP_ZAD = "); Serial.print(iACPTP_ZAD);Serial.print(" iACP_K = "); Serial.print(i2); Serial.print("  ACP = "); 
//Serial.print(i); Serial.print("  iD = "); Serial.print(iD);   Serial.print(" iMF = "); Serial.print(iMF);
//Serial.print(" iVent = "); Serial.print(iVentVklProc); Serial.println(" "); }    
       }
// проверка времени режима REGIM_WORK        
       lTime2=ulTimeWork+60000ul*(TIME_RABOTA_AUTO_OFF)-millis(); // разница между когда закончить и текущим временем <0 - время вышло 
// звуковой сгнал за одну минуту до окончания       
       if(iZvukTimeWork15==0&&lTime2<60000l) {iZvukTimeWork15=1;ZvukStart(ZVUK_1D_SIG);   }  
// звуковой сгнал за 45 сек до окончания       
       if(iZvukTimeWork15==1&&lTime2<45000l) { iZvukTimeWork15=2;  ZvukStart(ZVUK_1D_SIG);  } 
// звуковой сгнал за 30 сек до окончания       
       if(iZvukTimeWork15==2&&lTime2<30000l) { iZvukTimeWork15=3;  ZvukStart(ZVUK_1D_SIG);  } 
// звуковой сгнал за 15 сек до окончания       
       if(iZvukTimeWork15==3&&lTime2<15000l) { iZvukTimeWork15=4;  ZvukStart(ZVUK_1D_SIG);  }  
 // останов по таймеру       
       if(lTime2<0) { RegimSet(REGIM_PRODUV);    }        
       break; 

// ОШИБКА ===================================================== 
       case REGIM_ERR:   // ошибка показываем код, продуваем по таймеру и ТП 
         NagrevSetMosh(0);
         VentVklSkorost(100);
         ZvukStart(ZVUK_1D_SIG);         
       break;        
       
// TEST ===================================================== 
       case REGIM_TEST:   // проверяем состояние устройства
         ;
       break;        
     }
     
// отображение информации =============================
     if(millis()-ulTimePokazInfo>TIME_POKAZ_INFO)
     { ulTimePokazInfo=millis();
// инициализация индикатора    
       led8.shutdown(0,true); 
       delay(5);
       led8.shutdown(0,false);   
       led8.clearDisplay(0);  // очистить дисплей        

       switch(iRerimTek)
       {
         case REGIM_OFF:   // выключено
           PrintText4L(KOD_TEXT_OFF ,1);  
         break;
       
         case REGIM_PRODUV:   // продувка перед выключением         
           PrintText4L(KOD_TEXT_PRODUV ,1);           
// текущая темп
           i=TempTpToGrad(TempTpACPGet());       
           LED8Print4Poz(i,1,0,0);   // число, показ нулей, позиц с права, обнуление всего индикатора           
         break;           

         case REGIM_WORK:   // работа
// надпись  в левой части
// темп факт
           i2=TempZadGet();   
           LED8Print4Poz(i2,1,4,0); 
// надпсь в правой части
 // текущая темп
           i=TempTpToGrad(TempTpACPGet());       
           LED8Print4Poz(i,1,0,0);   // число, показ нулей, позиц с права, обнуление всего индикатора
         break;

         case REGIM_ERR:   // ошибка показываем код, продуваем по таймеру и ТП 
           PrintText4L(KOD_TEXT_ERR,1);
// надпсь в правой части
           LED8Print4Poz(iErrKod,1,0,0);   // число, показ нулей, позиц с права, обнуление всего индикатора            
         break;     
        } 

//        i=RegimTekGet();       PrintText4L(KOD_TEXT_RAB,1);   
//        if(iTekRegim==2) PrintText(KOD_TEXT_RAB,1);        
//        LED8Print4Poz(i,1,4,0);   // текущий режим работы в левой части
//        LED8Print4Poz(i,1,0,0);   // текущяя температура
// текущая темп выше или ниже установленой  в правом индикаторе
//        led8.setRow(0,4,B00011100);    // ниже заданой 
//         led8.setRow(0,4,B01100010);    // выше заданой 
//          led8.setRow(0,4,B00000001);    //  требуемая темп
//        if(iACP_T12<iACP_Zad-10)  led8.setRow(0,3,B00011100);    // ниже заданой на 15 гр 
//        if(iACP_T12>iACP_Zad+10) led8.setRow(0,3,B01100010); // выше заданой на 15 гр 
//Serial.print("T ZAD= ");  Serial.print(iTempZadGr);  Serial.print("  T TEK= ");  Serial.print(iTempTek);    Serial.println("");           
      }     
// звуковые сигналы =============================
      ZvukPley();
// конец постоянного цикла     
  }
}

//===================================================== 
// кооректировка значения заданого АЦП температруры в зависимости от скорости вентилятора
// при скорости вентилятора 50% поднимаем темпеартуру на нагревателе на 5 %
int TempZadKorrVen(int iACP,int iVentPr)
{
int i2,iA=iACP;
  if(iVentPr!=100)
  {  i2=iACP*(10-(iVentPr/10))/100;
     iA=iACP+i2;
  }
  return(iA);  
}  

//===================================================== 
// Сброс таймера авт отключения  
void TimeSetWorkOff(void)
{  ulTimeWork=millis();  // обнуление счетчика для отключения работы по таймеру
   iZvukTimeWork15=0;
}         

//===================================================== 
// запуск подачи звук сигнала  выключение постоянного сигнала iVid=0;
void ZvukStart(int iVid)
{
  iZvukVid=iVid;
  iZvukTek=0;
  ulZvukTime=millis();
  noTone(PIN_SIGNAL);
}  

//=====================================================
// остнов подачи звук сигнала
void ZvukStop(void)
{
  iZvukVid=0;
  iZvukTek=0;
} 

//=====================================================
// получение текщуго значения сигнала
int  ZvukGetTekVid(void)
{
  return(iZvukVid);
}

//=====================================================
// переключение динамика звук сигнала
void ZvukPley(void)
{
    if(iZvukVid!=0)
    { switch(iZvukVid)
      {  case ZVUK_1K_SIG:    // один короткий
           tone(PIN_SIGNAL,1000,500); 
           ZvukStop();           
         break;
      
         case ZVUK_1D_SIG:     // один длинный
           tone(PIN_SIGNAL,1000,2000); 
           ZvukStop();           
         
         break;
         case ZVUK_3K_SIG:      // три коротких
           if(iZvukTek==0) { tone(PIN_SIGNAL,1000,500);iZvukTek=1;}
           if(iZvukTek==1&&ulZvukTime+1000<millis()) { tone(PIN_SIGNAL,1000,500);iZvukTek=2;}
           if(iZvukTek==2&&ulZvukTime+2000<millis()) 
           { tone(PIN_SIGNAL,1000,500);
              ZvukStop();
           }   
         break;
         
         case ZVUK_1P_SIG:      // постоянно гудит выключение ZvukStart(0);
            tone(PIN_SIGNAL,1000);          
            ZvukStop();           
         break;
      }
    }  
} 

//=====================================================
// получение текущего режима
int RegimTekGet(void)
{
   return(iRerimTek);
}  

//=====================================================
// переключение режима
void RegimSet(int iRegim)
{ int i;
  switch(iRegim)
  {  case REGIM_WORK: 
         iRerimTek=iRegim;
         TimeSetWorkOff();         
         digitalWrite(PIN_RELE, HIGH);  //включить рэле  
// переходные процессы перед подачей напряжения на нагреватель, чтоб индикатор не зависал         
         ulTimeRegTemp=millis()+2000;   
//         delay(100);   
if(iPrintPort!=0){  Serial.println("REGIM_WORK "); }          
     break;

     case REGIM_OFF: iRerimTek=iRegim;
        digitalWrite(PIN_RELE, LOW);  
if(iPrintPort!=0){  Serial.println("REGIM_OFF "); }         
     break;

     case REGIM_ERR: iRerimTek=iRegim;
        digitalWrite(PIN_RELE, LOW);    
if(iPrintPort!=0){  Serial.println("REGIM_ERR "); }          
     break;

     case REGIM_PRODUV: 
        iRerimTek=iRegim;
        ulTimeProduv=millis();  // засеккаем время начала продувки
        ulTimeProduvDopol=0;
        digitalWrite(PIN_RELE, LOW);    
if(iPrintPort!=0){  Serial.println("REGIM_PRODUV "); }    
     break;

     case REGIM_TEST: iRerimTek=iRegim;
if(iPrintPort!=0){  Serial.println("REGIM_TEST "); }  
     break;

     case REGIM_OTLADKA: iRerimTek=iRegim;
if(iPrintPort!=0){  Serial.println("REGIM_OTLADKA "); }      
     break;     
  }  
}


//=====================================================================================
// расчет ПИД сигнала управления по значению разности АЦП на термопаре
// результат в интервале от 0 до 100%
//  P (t) = Koef_Pr * Raznost (t);
//  I (t) = I(t — 1) + Koef_In * Raznost (t);
//  D (t) = Koef_Di * { Raznost  (t) — Raznost (t — 1)};
int PIDRaschet(int iRaz) 
{ 
int iPIDSig;
// значение ошибки  
  iPIDRaz=iRaz;  
// пропор сотав 
  flPIDPrSig=PID_KOEF_P*iPIDRaz;
// интеграль  состав
  flPIDInSig=flPIDInSig_1+PID_KOEF_I*iPIDRaz;
  if(flPIDInSig<15.0&&flPIDInSig>-15.0) flPIDInSig_1=flPIDInSig;  // ограничение интегральной составляющей чтоб большая не накопилась при отключении нагревателя
// дифф  состав
  flPIDDiSig=PID_KOEF_D*(iPIDRaz-iPIRaz_1);
// пред ошибка  
  iPIRaz_1=iPIDRaz;
// сумма управляющих сигналов
  iPIDSig=flPIDPrSig+flPIDInSig+flPIDDiSig;

///????  
//int i;
//i=flPIDPrSig; Serial.print("flPIDPrSig = "); Serial.print(i); 
//i=flPIDInSig; Serial.print("  flPIDInSig = "); Serial.print(i);
//i=flPIDDiSig; Serial.print(" flPIDDiSig = "); Serial.println(i); 
// ограниение в интервал от 0 до 100  
//????/
//  if(iPIDSig<0) iPIDSig=0;
//  if(iPIDSig>100) iPIDSig=100;

  return(iPIDSig);
}  

//=====================================================
// получение  значения температуры термопары в градусах
int TempTpGradGet(void)
{ 
 int i;
    i=TempTpToGrad(TempTpACPGet());
    return(i);
}

//=====================================================
// получение  значения температуры термопары в градусах из АЦП
int TempTpToGrad(int iAcp)
{ 
 int i;
 float flTemp;
// пересчет значения термопары в градусы
    flTemp=iAcp/KOEF_ACP_TO_GR;      // 2.12 коэф пресчета
    i=flTemp;
    return(i);
}

//=====================================================
// получение  значения АЦП термопары
int TempTpACPGet(void)
{ int i;
// получение температуры
    i= analogRead(PIN_ACP_TC);
//if(iPrintPort!=0){  Serial.print("TempTpACPGet = "); Serial.println(i); }    
    return(i);
}

//=====================================================
// пересчет заданой температуры в значяения АЦП ТП
int TempZadFromGrToAcp(int iTempGr)
{ 
 int i;
 float flAcp;
// пересчет значения 
    flAcp=iTempGr*KOEF_ACP_TO_GR;      // 2.12 коэф пресчета
    i=flAcp+1;  
    return(i);
}

//=====================================================
// получение заданой температуры с округлением до 10
int TempZadGet(void)
{ 
int i,i2;
float flPr1,flP,flA;
// получение температуры
    i=ACPZadTemp();
    if(i<TEMP_ACP_ZAD_MIN) return(TEMP_ZAD_MIN);
    if(i>TEMP_ACP_ZAD_MAX) return(TEMP_ZAD_MAX);
    flP=TEMP_ZAD_MAX-TEMP_ZAD_MIN;
    flA=TEMP_ACP_ZAD_MAX-TEMP_ACP_ZAD_MIN;
    flPr1=flA/flP;
    flA=i;
    flP=flA/flPr1;
    i=flP+TEMP_ZAD_MIN;
    i2=i/20;
    i=i2*20;
//if(iPrintPort!=0){  Serial.print("TempZadGet = "); Serial.println(i); }         
    return(i);
}

//=====================================================
// получение значение АЦП с регулятора температуры
int ACPZadTemp(void)
{ int i;
// получение температуры
    i=(analogRead(PIN_ZAD_TEMP)+analogRead(PIN_ZAD_TEMP)+analogRead(PIN_ZAD_TEMP))/3;
//if(iPrintPort!=0){  Serial.print("iTempM[0] = "); Serial.println(iTempM[0]); }         
    return(i);
}

//=====================================================
// получение процентов мощности  с регулятора скорости вентилятора
int VentGetProc(void)
{ int i,i2;
float flPr1,flP,flA;
// получение температуры
    i=ACPZadVent();
    flP=VENT_PROC_MAX-VENT_PROC_MIN;
    flA=VENT_ACP_MAX-VENT_ACP_MIN;
    flPr1=flA/flP;
    flA=i;
    flP=flA/flPr1;
    i=flP+VENT_PROC_MIN;
    i2=i/10;
    i=i2*10;
//if(iPrintPort!=0){  Serial.print("VentGetProc = "); Serial.println(i); }         
    return(i);
}

//=====================================================
// получение значение АЦП с регулятора скорости вентилятора
int ACPZadVent(void)
{ int i;
// получение температуры
    i=analogRead(PIN_ZAD_VENT);
//if(iPrintPort!=0){  Serial.print("iTempM[0] = "); Serial.println(iTempM[0]); }         
    return(i);
}

//=====================================================
// задание мощности вент от 50 до 100%
void VentVklSkorost(int iProcent)
{ 
int i;
float flOb;
   if(iProcent<0||iProcent>100) return;
   if(iProcent<50)   digitalWrite(PIN_VKL_REG_VENT, LOW); 
   if(iProcent>=50&&iProcent<100) 
   { flOb=2.55*iProcent;
     i=flOb;
     analogWrite(PIN_VKL_REG_VENT, i);
//if(iPrintPort!=0){  Serial.print("            VentSetSkorost  PWM = "); Serial.println(i); }        
   }
   if(iProcent==100) digitalWrite(PIN_VKL_REG_VENT, HIGH); 
   iVentVklProc=iProcent;
//if(iPrintPort!=0){  Serial.print("VentSetSkorost = "); Serial.println(iProcent); }        
}


//=====================================================
// задание мощности нагревателя
void NagrevSetMosh(int iProcent)
{ 
int i;
float flOb;
   if(iProcent<0||iProcent>100) return;
   if(iProcent<1)   digitalWrite(PIN_VKL_REG_NAGR, LOW); 
   if(iProcent>0&&iProcent<100) 
   { flOb=2.55*iProcent;
     i=flOb;
     analogWrite(PIN_VKL_REG_NAGR, i);
   }
   if(iProcent==100) digitalWrite(PIN_VKL_REG_NAGR, HIGH); 
   iNagrVklProcent=iProcent;
//if(iPrintPort!=0){  Serial.print("NagrevSetMosh = "); Serial.println(iProcent); }    
}

//=================================================================================
// отображение числа в 4-х  разрядах с позиции iPozStart (0-7) 
//  iPokazZero==0 - не показывать нули вообще, ==1 показывать только один 0, >показывать нули с переди
//   iClr!=0 - сброс всего индикатора
void LED8Print4Poz(int iData,int iPokazZero,int iPozStart,int iClr)
{
int i,i2,i9;
int iCif[4]={0,0,0,0};
   if(iClr!=0)
   {// led81.shutdown(0,false); 
     led8.clearDisplay(0); 
   }
   
   i9=iData;
   if(i9>0)
   { i2=i9/10;
     iCif[0]=i9-i2*10;
     i9=i2;

     if(i9>0)   
     { i2=i9/10;
       iCif[1]=i9-i2*10;
       i9=i2;
       if(i9>0)   
       { i2=i9/10;
         iCif[2]=i9-i2*10; 
         i9=i2;

         if(i9>0)   
         { i2=i9/10;
           iCif[3]=i9-i2*10; 
         }
       }
     }   
   }
   i9=0; 
   for(i=3;i>=0;i--)
   { if(i+iPozStart<8)
     { if(iCif[i]!=0||i==0&&iPokazZero==1)  // показывать младший ноль
       { i9=1;
         led8.setDigit(0,iPozStart+i,iCif[i],false);      
       }   
       else
       { if(iPokazZero>1||i9==1)  led8.setDigit(0,iPozStart+i,iCif[i],false);         
         else   led8.setRow(0,iPozStart+i,B00000000);  
       
       }  
     }  
   }
}   


//=================================================================
// отображение на экране слева 4 поз сообщения по его номеру
// iClear4!=0  отчищаем все 4 знакоместа, иначе только те в кторые печатем
void PrintText4L(int iKodInfo,int iClear4)
{
   switch(iKodInfo)
   {  case KOD_TEXT_ERR: // надпись Err  в левой части
         led8.setRow(0,7,0x00);led8.setRow(0,6,0x00);led8.setRow(0,5,0x00);     if(iClear4) led8.setRow(0,4,0x00);
         led8.setRow(0,7,0x4F);  led8.setRow(0,6,0x05);    led8.setRow(0,5,0x05); 
      break;
     
      case KOD_TEXT_TEST: // tESt
         led8.setRow(0,7,0x00);   led8.setRow(0,6,0x00);    led8.setRow(0,5,0x00);     led8.setRow(0,4,0x00);
         led8.setRow(0,7,0x0F);   led8.setRow(0,6,0x4F);    led8.setRow(0,5,0x5B);     led8.setRow(0,4,0x0F);      
      break;
          
      case KOD_TEXT_RAB: // РАБ   67	77	5F (DF-"Б" с точкой)
         led8.setRow(0,7,0x00);led8.setRow(0,6,0x00);led8.setRow(0,5,0x00);     if(iClear4) led8.setRow(0,4,0x00);
         led8.setRow(0,7,0x67);  led8.setRow(0,6,0x77);    led8.setRow(0,5,0xDF); 
      break;

      case KOD_TEXT_OFF: // OFF   7E	47	47
         led8.setRow(0,7,0x00);led8.setRow(0,6,0x00);led8.setRow(0,5,0x00);     if(iClear4) led8.setRow(0,4,0x00);
         led8.setRow(0,7,0x7E);  led8.setRow(0,6,0x47);    led8.setRow(0,5,0x47); 
      break;
      
      case KOD_TEXT_PRODUV: //  67   05   7E  3D
         led8.setRow(0,7,0x00);led8.setRow(0,6,0x00);led8.setRow(0,5,0x00);      led8.setRow(0,4,0x00);
         led8.setRow(0,7,0x67);  led8.setRow(0,6,0x05);    led8.setRow(0,5,0x7E);  led8.setRow(0,4,0x3D); 
      break;
   }  
}

 

sva_khv
Offline
Зарегистрирован: 19.12.2016

sva_khv
Offline
Зарегистрирован: 19.12.2016

Все заработало. Устройством доволен.  Повыпаивал кучу полевиков . Пока не включил корректировку температуры в зависимости от мощности вентилятора, т.к. и от диаметра насадки есть зависимость. Будет желание - поэксперементирую.

Petro-258
Offline
Зарегистрирован: 27.10.2016

Геркон можно добавить ?

sva_khv
Offline
Зарегистрирован: 19.12.2016

Petro-258 пишет:

Геркон можно добавить ?

А какой режим по геркону включать? Вентилятор на 50%, температуру понизить до 100-200 грС ?

 

Petro-258
Offline
Зарегистрирован: 27.10.2016

 Температуру понизить до 100 С , после остывания вентилятор 30%

Petro-258
Offline
Зарегистрирован: 27.10.2016

Дисплей на TM1637 подойдет ?

sva_khv
Offline
Зарегистрирован: 19.12.2016

Petro-258 пишет:

Дисплей на TM1637 подойдет ?

Надо менять библиотеку и править функции вывода. 

И обычно на 1637   4 знакоместа. У меня индикация заточена на 8 знакомест. Предпологается исползование двух 1637?

sva_khv
Offline
Зарегистрирован: 19.12.2016

Petro-258 пишет:

 Температуру понизить до 100 С , после остывания вентилятор 30%

Понятно. Но меньше 50% я вентилятор не делал. Если меньше то в моем фене он почти не дует и как то совсем жалобно хрипит  :-(

Таймер автоматического отключения (10 мин) продолжает тикать или включение/выключение геркона его обнуляет?

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

Petro-258
Offline
Зарегистрирован: 27.10.2016

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

sva_khv
Offline
Зарегистрирован: 19.12.2016

Подключение геркона как будет время  добавлю. 

А переделывать индикацию на один 1637 пробуйте сами. Индикцию я делал в отдельных функциях там не сложно. :-)

Petro-258
Offline
Зарегистрирован: 27.10.2016

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

#include <TM1637.h>
#define CLK 5                            //TM1637 Clock
#define DIO 4                            //TM1637 Data
TM1637 tm1637(CLK, DIO);                 //Дисплей TM1637
 инициализация индикатора    
   // led8.shutdown(0,false); 
   tm1637.init();
    //led8.setIntensity(0,5); // яркость дисплея 
     tm1637.set(3); // яркость дисплея 
   //led8.clearDisplay(0);  // очистить дисплей
     disp.clearDisplay();   // очистить дисплей   

 

sva_khv
Offline
Зарегистрирован: 19.12.2016

Petro-258 пишет:
Я не умею програмировать , так правильно?

Да.

 

Petro-258
Offline
Зарегистрирован: 27.10.2016

Ничего не получаетса не знаю что тут изминить

 { ulTimePokazInfo=millis();
// инициализация индикатора    
       led8.shutdown(0,true); 
       delay(5);
       led8.shutdown(0,false);   
       //led8.clearDisplay(0);  // очистить дисплей        
        disp.clearDisplay();   // очистить дисплей
       switch(iRerimTek)
  LED8Print4Poz(i,1,0,0);   // число, показ нулей, позиц с права, обнуление всего индикатора           
         break;
sva_khv
Offline
Зарегистрирован: 19.12.2016

Ты на правильном пути

Замени  код между коментариями "отображение информации"  и "звуковые сигналы" на приведеный ниже

И удали из программы вызов функций и сам код функций

- PrintText4L    

- LED8Print4Poz

 



// отображение информации =============================
     if(millis()-ulTimePokazInfo>TIME_POKAZ_INFO)
     { ulTimePokazInfo=millis();
// инициализация индикатора    
        disp.clearDisplay();   // очистить дисплей
// текущая темп
        i=TempTpToGrad(TempTpACPGet());  
        disp.display(i);
      }     
// звуковые сигналы =============================