| Ваш IP: 3.91.92.194 | Online(42) - гости: 20, боты: 22 | Загрузка сервера: 1.5 ::::::::::::

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

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

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

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

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

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

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

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

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

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

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

Настройка гистерезиса

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

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

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

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

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

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

#include <LiquidCrystal_I2C.h>  // http://forum.rcl-radio.ru/misc.php?action=pan_download&item=45&download=1
#include <OneWire.h>            // https://rcl-radio.ru/wp-content/uploads/2018/07/OneWire.zip
#include <Wire.h>
#include <Encoder.h>            // https://rcl-radio.ru/wp-content/uploads/2019/05/Encoder.zip       
#include <EEPROM.h>
#include <MsTimer2.h>           // https://rcl-radio.ru/wp-content/uploads/2018/11/MsTimer2.zip 
 LiquidCrystal_I2C lcd(0x27,16,2);
 Encoder myEnc(8, 9);// DT, CLK
 OneWire  ds(2); // Вход датчика 18b20
 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,t_ds,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 tic,tac,power,menu,gis=1,nagrev;
 
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(3,INPUT_PULLUP); // button PROG
  pinMode(4,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);}
  for(int i=10;i<20;i++){reg_time[i-10] = EEPROM.read(i);}if(reg_time[0]==0){reg_time[0]=1;}
  gis = EEPROM.read(20);
  digitalWrite(13,LOW);
  } 
 
void loop(){
////// BUTTON /////////////////////////////////////////////////////////  
  if(digitalRead(3)==LOW&&prog==0){prog=1;menu=0;temp_time=0;times1=millis();w=1;lcd.clear();delay(300);}
  if(digitalRead(3)==LOW&&prog==1){prog=0;temp_time=0;times1=millis();w=1;lcd.clear();delay(300);}
  if(digitalRead(4)==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>1000){times=millis();t_ds = dsRead(0)*10;}// Измерять температуру 1 раз в секунду
 ///////// LCD BIG ///////////////////////////////////////////////
 if(prog==0&&menu==0){
     a[0]=t_ds/1000;
     a[1]=t_ds/100%10;
     a[2]=t_ds/10%10;
     a[3]=t_ds%10;
     if(t_ds<1000){a[0]=10;}
     if(t_ds<100){a[1]=10;}
   for(x=0;x<4;x++){
    switch(x){
        case 0: e1=0;e2=0,e3=1;break;
        case 1: e1=2,e2=3,e3=4;break;
        case 2: e1=5,e2=6,e3=7;break;
        case 3: e1=9,e2=10,e3=11;break;
   }digit();}
   lcd.setCursor(8,1);lcd.print(".");
   if(power==1){lcd.setCursor(13,1);lcd.print((reg_time[tac]-tic)/100);lcd.print((reg_time[tac]-tic)/10%10);lcd.print((reg_time[tac]-tic)%10);}
   else{lcd.setCursor(13,1);lcd.print("OFF");}
   if(millis()-times_cur<=3000){lcd.setCursor(13,0);lcd.print("P_");lcd.print(tac);}
   else if(millis()-times_cur>3000&&millis()-times_cur<6000){lcd.setCursor(13,0);lcd.print(reg_t[tac]/100);lcd.print(reg_t[tac]/10%10);lcd.print(reg_t[tac]%10);}
   else{times_cur=millis();}
 
//////////////////////////////////////////////////////////////////
}
////////// 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(0,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(0,0);lcd.print("hysteresis ");lcd.print((float)gis/10,1);
  }  
 
///////// EEPROM ////////////////////////////////////////////////
  if(millis()-times1>10000 && w==1){
   for(int i=0;i<10;i++){EEPROM.update(i,reg_t[i]);}
   for(int i=10;i<20;i++){EEPROM.update(i,reg_time[i-10]);}
   EEPROM.update(20,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_ds + gis){digitalWrite(13,HIGH);nagrev=1;}
  if(reg_t[tac]*10 <= t_ds - 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_ds);Serial.print("  ");Serial.println(gis);
 
  }// LOOP END 
 
void gis_fun(){if(gis<0){gis=0;}if(gis>30){gis=30;}}  
void time_func(){if(reg_time0>255){reg_time0=255;}if(reg_time0<0){reg_time0=0;}}
void temp_func(){if(reg_t0>125){reg_t0=125;}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;
    }
if(x>0){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);}   
 
float dsRead(byte x) {
  byte data[2], addr[8][8], kol = 0;
  while (ds.search(addr[kol])) {  // поиск датчиков, определение адреса и кол-ва датчиков
    kol++;
  } 
  ds.reset_search();  // Сброс поиска датчика
  ds.reset();         // Инициализация, выполняется сброс шины
  ds.select(addr[x]); // Обращение к датчику по адресу
  ds.write(0x44, 0);  // Измерение температуры с переносом данных в память
  ds.reset();         // Инициализация, выполняется сброс шины
  ds.select(addr[x]); // Обращение к датчику по адресу
  ds.write(0xBE);     // Обращение памяти
  data[0] = ds.read();// Чтение памяти byte low
  data[1] = ds.read();// Чтение памяти byte high
  float value = ((data[1] << 8) | data[0]) / 16.0; return (float)value; // Расчет температуры и вывод
}

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

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

Случайные статьи

  • Параллельное и последовательное соединение резисторов, конденсаторов и катушек индуктивности

    Параллельное и последовательное соединение резисторов, конденсаторов и катушек индуктивности

    Резисторы Последовательное соединение резисторов   Последовательное соединение резисторов это такое соединение когда резисторы подключаются последовательно друг за другом. При этом через все резисторы будет протекать одинаковый ток. Для расчета общего сопротивления всех последовательно соединенных резисторов используется формула: Rобщ = R1 + R2 + R3 + … + Rn. Параллельное соединение …Подробнее...
  • Расчёт стабилизатора напряжения (источника опорного напряжения)

    Расчёт стабилизатора напряжения (источника опорного напряжения)

    Для расчёта стабилизатора, как правило, используются только два  параметра — Uст (напряжение стабилизации) , Iст (ток стабилизации), при условии что ток нагрузки равен или меньше тока стабилизации. Для простого расчета стабилизатора на примере будем использовать следующие параметры: Входное напряжение 10 В Выходное напряжение 6,8 В Ток нагрузки 10 мА Из …Подробнее...
  • Простой стрелочный частотомер

    Частотомер имеет диапазон измеряемых частот от 0-100Гц до 100кГц. Схема весьма проста и не содержит дорогостоящих элементов. Чувствительность частотомера 100мВ. В качестве индикатора используется миллиамперметр 0-100мкА, частотомер имеет 4-е диапазона 100Гц, 1Кгц, 10кГц, 100кГц.  В частотомере использованы две микросхемы — ОУ  CA3130 и таймер LM555. Оу имеет высокое входное сопротивление, тем …Подробнее...
  • Простой УКВ-приемник

    УКВ-приемник работает в диапазоне 64-108МГц. Схема приемника основана на 2-х микросхемах: К174ХА34 и ВА5386, дополнительно в схеме присутствуют 17 конденсаторов и всего 2-а резистора. Колебательный контур один, гетеродинный. На А1 выполнен супергетеродинный УКВ-ЧМ без УНЧ. Сигнал от антенны поступает через С1 на вход ПЧ микросхемы А1(вывод12). Настройка на станцию производится …Подробнее...
  • Регулятор громкости и  тембра на PT2319 (Arduino)

    Регулятор громкости и тембра на PT2319 (Arduino)

    ИМС PT2319 представляет собой аудиопроцессор специально разработанный для регулирования параметров аудиосигнала с минимальными искажениями. Аудиопроцессор включает в себя регулятор громкости, тембра, коммутатор входов и предусилители входа и выхода. Более подробно об аудиопроцессоре можно узнать из статьи Аудиопроцессор PT2319 (Arduino). Регулятор громкости и тембра построен на базе Arduino Nano. Основные параметры …Подробнее...