Терморегулятор MAX6675 с таймером (Arduino)

Ранее в статье http://rcl-radio.ru/?p=110938 был показан пример терморегулятора на основе цифрового датчика DS18B20, на этой странице показан аналогичный пример создания терморегулятора, но на базе преобразователя (АЦП) MAX6675 (http://rcl-radio.ru/?p=45839).

При помощи MAX6675 (модуль) можно измерить ТЭДС термопары типа К (ХА), результат измерения выводится в градусах Цельсия и Фаренгейта, так же микросхема MAX6675 содержит встроенный датчик температуры окружающей среды.

MAX6675 в комплекте с термопарой типа К рассчитан на измерение температуры в диапазоне от 0 до 1024 ºС, с разрешением 0.25 ºС (точность 12 бит). Для передачи данных используется SPI интерфейс.

Используя преобразователь температуры MAX6675, можно собрать простой регулятор температуры. MAX6675 имеет диапазон измерения температуры от 0 до + 999 °C (программно ограничено до 999 °C), показания датчика температуры выводятся на дисплей LCD1602 + I2C (I2C модуль на базе микросхем PCF8574 позволяют подключить символьный дисплей 1602 к плате Arduino всего по двум проводам SDA и SCL (А4 и А5), что дает возможность не использовать цифровые выходы Arduino при подключении дисплея.) Органы управления состоят из энкодера KY-040 и двух кнопок.

Терморегулятор может содержать до 10 программ, в каждой программе можно задать температуру регулирования и время (в минутах) поддержания заданной температуры. Так же можно установить гистерезис. Все данные программ и значение гистерезиса сохраняются в энергонезависимой памяти.

Терморегулятор содержит основное меню, меню активации программ и настройки гистерезиса, а так же меню установки параметров (температуры и времени) программ.

Основное меню

На основном меню выводятся:

  1. данные от текущей температуре (от 0 до 999 °С)
  2. номер программы
  3. индикатор работы нагревательного элемента
  4. температура регулирования заданная в данной программе (0…999 °С)
  5. оставшееся время работы в заданной программе программы (в минутах от 0 до 255)

При нажатии на кнопку энкодера (в основном меню) происходит переход в меню активации программ и установки гистерезиса.

В меню активации программ, при установки параметра «ON» происходит запуск таймера, который отсчитывает время от установленного в программе.

Запуск таймера

Остановка таймера

Настройка гистерезиса от 0.0 до 5.0 °С

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

Терморегулятор будет поддерживать температуру по времени заданной в каждой программе до завершения времени работы программы P_9, после чего выход D13 (выход управления нагревательным элементом) становится не активным, происходит переход на программу P_0, которая будет неактивна (отсчет таймера приостанавливается).

Меню установки температуры и времени

На настройки температуры и времени исполнения программ используются кнопки «PROG» и «TEMP / TIMES». При нажатии на кнопку «PROG» происходит переход в меню настройки программ, кнопка энкодера позволяет пролистывать программы P_0…P_9. Кнопка «TEMP / TIMES» позволяет переключать настройки времени и температуры. Параметр меняется при помощи ручки энкодера, температуру можно установить от 0 до 999 °С, время от 0 до 255 минут.

Если время исполнения программы установить на 0 минут (OFF), то эта программа будет неактивна. Например если Вам нужно только 2 программы, то нужно установить в программах P_0 и P_1 время и температуру, а в остальных программа P_2…P_9 время установить на 0 минут (OFF).

Для выхода из режима программирования нужно нажать кнопку «PROG» или подождать 10 секунд для выхода в основное меню.

#include <EEPROM.h>
#include <max6675.h>            // http://rcl-radio.ru/wp-content/uploads/2018/07/max6675.zip
#include <LiquidCrystal_I2C.h>  // http://forum.rcl-radio.ru/misc.php?action=pan_download&item=45&download=1
#include <Wire.h>
#include <Encoder.h>            // http://rcl-radio.ru/wp-content/uploads/2019/05/Encoder.zip       
#include <EEPROM.h>
#include <MsTimer2.h>           // http://rcl-radio.ru/wp-content/uploads/2018/11/MsTimer2.zip 
 LiquidCrystal_I2C lcd(0x27,16,2);
 Encoder myEnc(8, 9);// DT, CLK
 MAX6675 thermocouple(4, 3, 2);// CLK, CS, DO
 byte v1[8] = {0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07};
 byte v2[8] = {0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00};      
 byte v3[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x1F};
 byte v4[8] = {0x1F,0x1F,0x00,0x00,0x00,0x00,0x1F,0x1F};
 byte v5[8] = {0x1C,0x1C,0x00,0x00,0x00,0x00,0x1C,0x1C};
 byte v6[8] = {0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C};
 byte v7[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07};
 byte v8[8] = {0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00};
 byte d1,d2,d3,d4,d5,d6,e1,e2,e3;
 int a[6],x,i_reg,temp_time;
 int reg_t[10],reg_time[10],reg_t0,reg_time0;
 bool prog,w;
 unsigned long times,times1,times_baza,times_cur,oldPosition  = -999,newPosition;
 int i,tic,tac,power,menu,gis=1,nagrev;
 int t_c,t_sum,t_iz; 
 
void setup(){
  Wire.begin();lcd.init();lcd.backlight();
  MsTimer2::set(1, to_Timer);MsTimer2::start();
  if(EEPROM.read(100)!=0){for(int i=0;i<101;i++){EEPROM.update(i,0);}}// очистка памяти при первом включении
  lcd.createChar(1, v1);lcd.createChar(2, v2);lcd.createChar(3, v3);lcd.createChar(4, v4);
  lcd.createChar(5, v5);lcd.createChar(6, v6);lcd.createChar(7, v7);lcd.createChar(8, v8);
  Serial.begin(9600);  
  pinMode(10,INPUT);       // button SW ENCODER 
  pinMode(5,INPUT_PULLUP); // button PROG
  pinMode(6,INPUT_PULLUP); // button PROG_TEMP_TIME
  pinMode(13,OUTPUT);      // OUTPUT REG TEMP
  for(int i=0;i<10;i++){reg_t[i] = EEPROM.read(i)*10+EEPROM.read(i+10);}
  for(int i=20;i<30;i++){reg_time[i-20] = EEPROM.read(i);}if(reg_time[0]==0){reg_time[0]=1;}
  gis = EEPROM.read(30);
  digitalWrite(13,LOW);
  } 
 
void loop(){
////// BUTTON /////////////////////////////////////////////////////////  
  if(digitalRead(5)==LOW&&prog==0){prog=1;menu=0;temp_time=0;times1=millis();w=1;lcd.clear();delay(300);}
  if(digitalRead(5)==LOW&&prog==1){prog=0;i_reg=0;temp_time=0;times1=millis();w=1;lcd.clear();delay(300);}
  if(digitalRead(6)==LOW&&prog==1){temp_time++;if(temp_time>1){temp_time=0;}times1=millis();w=1;delay(300);lcd.clear();}
  if(digitalRead(10)==LOW&&prog==1){i_reg++;temp_time=0;if(i_reg>9){i_reg=0;}times1=millis();w=1;lcd.clear();delay(300);}
  if(digitalRead(10)==LOW&&prog==0){menu++;times1=millis();w=1;lcd.clear();delay(300);if(menu>2){menu=0;}}
 
///////// REG_TEMP ///////////////////////////////
  if(prog==1&&temp_time==0){
   switch(i_reg){
     case 0: reg_t0 = reg_t[0];break;
     case 1: reg_t0 = reg_t[1];break;
     case 2: reg_t0 = reg_t[2];break;
     case 3: reg_t0 = reg_t[3];break;
     case 4: reg_t0 = reg_t[4];break;
     case 5: reg_t0 = reg_t[5];break;
     case 6: reg_t0 = reg_t[6];break;
     case 7: reg_t0 = reg_t[7];break;
     case 8: reg_t0 = reg_t[8];break;
     case 9: reg_t0 = reg_t[9];break;}
 
 if(newPosition != oldPosition){oldPosition = newPosition;reg_t0=reg_t0+newPosition;myEnc.write(0);newPosition=0;times1=millis();;w=1;temp_func();}
 
   switch(i_reg){
     case 0: reg_t[0] = reg_t0;break;
     case 1: reg_t[1] = reg_t0;break;
     case 2: reg_t[2] = reg_t0;break;
     case 3: reg_t[3] = reg_t0;break;
     case 4: reg_t[4] = reg_t0;break;
     case 5: reg_t[5] = reg_t0;break;
     case 6: reg_t[6] = reg_t0;break;
     case 7: reg_t[7] = reg_t0;break;
     case 8: reg_t[8] = reg_t0;break;
     case 9: reg_t[9] = reg_t0;break;}  
  }  
/////// REG_TIME //////////////////////////////////////////////
  if(prog==1&&temp_time==1){
   switch(i_reg){
     case 0: reg_time0 = reg_time[0];break;
     case 1: reg_time0 = reg_time[1];break;
     case 2: reg_time0 = reg_time[2];break;
     case 3: reg_time0 = reg_time[3];break;
     case 4: reg_time0 = reg_time[4];break;
     case 5: reg_time0 = reg_time[5];break;
     case 6: reg_time0 = reg_time[6];break;
     case 7: reg_time0 = reg_time[7];break;
     case 8: reg_time0 = reg_time[8];break;
     case 9: reg_time0 = reg_time[9];break;}
 
 if(newPosition != oldPosition){oldPosition = newPosition;reg_time0=reg_time0+newPosition;myEnc.write(0);newPosition=0;times1=millis();;w=1;time_func();}
 
   switch(i_reg){
     case 0: reg_time[0] = reg_time0;break;
     case 1: reg_time[1] = reg_time0;break;
     case 2: reg_time[2] = reg_time0;break;
     case 3: reg_time[3] = reg_time0;break;
     case 4: reg_time[4] = reg_time0;break;
     case 5: reg_time[5] = reg_time0;break;
     case 6: reg_time[6] = reg_time0;break;
     case 7: reg_time[7] = reg_time0;break;
     case 8: reg_time[8] = reg_time0;break;
     case 9: reg_time[9] = reg_time0;break;}  
  }  
 
  if(prog==1&&menu==0){
    lcd.setCursor(0,0);if(temp_time==0){lcd.print("*REG_TEMP");}else{lcd.print(" REG_TEMP");}lcd.print(i_reg);
    lcd.print(" ");lcd.print(reg_t[i_reg]);lcd.print(" ");lcd.setCursor(15,0);;lcd.print("C");
    lcd.setCursor(0,1);if(temp_time==1){lcd.print("*REG_TIME");}else{lcd.print(" REG_TIME");}lcd.print(i_reg);
    if(reg_time[i_reg]>0){lcd.print(" ");lcd.print(reg_time[i_reg]);lcd.print("  ");lcd.setCursor(15,1);lcd.print("M");}
    else{lcd.print(" ");lcd.print("OFF     ");}
    }
 ///////// READ TEMP /////////////////////////////////////////////
 if(millis()-times>300){times=millis();i++;t_c=thermocouple.readCelsius();t_sum=t_sum+t_c;}
 if(i>4){i=0;t_iz=t_sum/5;t_sum=0;}
 if(t_iz>999){t_iz=999;}if(t_iz<0){t_iz=0;}
 ///////// LCD BIG ///////////////////////////////////////////////
 if(prog==0&&menu==0){
     a[0]=t_iz/100;
     a[1]=t_iz/10%10;
     a[2]=t_iz%10;
     if(t_iz<100){a[0]=10;}
     if(t_iz<10){a[1]=10;}
   for(x=0;x<3;x++){
    switch(x){
        case 0: e1=0;e2=1,e3=2;break;
        case 1: e1=3,e2=4,e3=5;break;
        case 2: e1=6,e2=7,e3=8;break;
 
   }digit();}
   lcd.setCursor(9,1);lcd.print(char(223)); lcd.print("C"); 
   if(power==1){lcd.setCursor(13,1);lcd.print((reg_time[tac]-tic)/100);lcd.print((reg_time[tac]-tic)/10);lcd.print((reg_time[tac]-tic)%10);}
   else{lcd.setCursor(13,1);lcd.print("OFF");}
   lcd.setCursor(10,0);lcd.print("P");lcd.print(tac);
   lcd.setCursor(13,0);lcd.print(reg_t[tac]/100);lcd.print(reg_t[tac]/10%10);lcd.print(reg_t[tac]%10);}
//////////////////////////////////////////////////////////////////
 
////////// MENU /////////////////
if(prog==0&&menu==1){
  if(newPosition != oldPosition){oldPosition = newPosition;power=power+newPosition;myEnc.write(0);newPosition=0;times1=millis();w=1;if(power>1){power=0;}if(power<0){power=1;}}
  lcd.setCursor(3,0);lcd.print("heating");
  if(power==1){lcd.print(" ON ");}
  if(power==0){lcd.print(" OFF");tac=0;tic=0;}
  }
if(prog==0&&menu==2){
  if(newPosition != oldPosition){oldPosition = newPosition;gis=gis+newPosition;myEnc.write(0);newPosition=0;times1=millis();w=1;gis_fun();}
  lcd.setCursor(3,0);lcd.print("hysteresis ");
  lcd.setCursor(6,1);lcd.print((float)gis/10,1);
  lcd.print(char(223)); lcd.print("C"); 
  }  
 
///////// EEPROM ////////////////////////////////////////////////
  if(millis()-times1>10000 && w==1){
   for(int i=0;i<10;i++){EEPROM.update(i,reg_t[i]/10);EEPROM.update(i+10,reg_t[i]%10);}
   for(int i=20;i<30;i++){EEPROM.update(i,reg_time[i-20]);}
   EEPROM.update(30,gis);
   menu=0;prog=0;i_reg=0;w=0;temp_time=0;lcd.clear();} 
 
//////// AVTO REG TIMER /////////////////////////////////////////////
 
  if(millis()-times_baza>60000 && power==1){tic++;times_baza=millis();}
  if(reg_time[tac]==0){tac++;}
  if(tic>reg_time[tac]-1){tic=0;tac++; if(tac>9){tac=0;tic=0;power=0;}}
  if(power==0){times_baza=millis();digitalWrite(13,LOW);}
  if(power==1){
  if(reg_t[tac]*10 >= t_iz*10 + gis){digitalWrite(13,HIGH);nagrev=1;}
  if(reg_t[tac]*10 <= t_iz*10 - gis){digitalWrite(13,LOW);nagrev=0;}  
  }
  if(nagrev==1&&menu==0&&prog==0){lcd.setCursor(12,0);lcd.print("*");}
  if(nagrev==0&&menu==0&&prog==0){lcd.setCursor(12,0);lcd.print(" ");}
 
  Serial.print(reg_t[tac]*10);Serial.print("  ");Serial.print(t_iz*10);Serial.print("  ");Serial.println(gis);
 
  }// LOOP END 
 
void gis_fun(){if(gis<0){gis=0;}if(gis>50){gis=50;}}  
void time_func(){if(reg_time0>255){reg_time0=255;}if(reg_time0<0){reg_time0=0;}}
void temp_func(){if(reg_t0>999){reg_t0=999;}if(reg_t0<0){reg_t0=0;}}
void to_Timer(){newPosition = myEnc.read()/4;}  
 
void digit(){
  switch(a[x]){
    case 0: d1=1,d2=8,d3=6,d4=1,d5=3,d6=6;break;
    case 1: d1=32,d2=2,d3=6,d4=32,d5=32,d6=6;break;
    case 2: d1=2,d2=8,d3=6,d4=1,d5=4,d6=5;break;
    case 3: d1=2,d2=4,d3=6,d4=7,d5=3,d6=6;break;
    case 4: d1=1,d2=3,d3=6,d4=32,d5=32,d6=6;break;
    case 5: d1=1,d2=4,d3=5,d4=7,d5=3,d6=6;break;
    case 6: d1=1,d2=4,d3=5,d4=1,d5=3,d6=6;break;
    case 7: d1=1,d2=8,d3=6,d4=32,d5=32,d6=6;break;
    case 8: d1=1,d2=4,d3=6,d4=1,d5=3,d6=6;break;
    case 9: d1=1,d2=4,d3=6,d4=7,d5=3,d6=6;break;
    case 10:d1=150,d2=150,d3=150,d4=150,d5=150,d6=150;break;
    }
lcd.setCursor(e1,0);lcd.write((uint8_t)d1);
lcd.setCursor(e2,0);lcd.write((uint8_t)d2);lcd.setCursor(e3,0);lcd.write((uint8_t)d3);lcd.setCursor(e1,1);
lcd.write((uint8_t)d4);lcd.setCursor(e2,1);lcd.write((uint8_t)d5);lcd.setCursor(e3,1);lcd.write((uint8_t)d6);}   
 

 

Comments

Добавить комментарий

Войти с помощью: