Термостат с развитием

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

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

Кроме того в программе я попытался воплотить свои мысли по поводу работы в реальном времени без использования прерываний.

Комментарии к программе я использовал наиболее ёмко, возможно даже чрезмерно. Но так мне проще будет потом.

В этом проекте использовались:

  1. Arduino nano
  2. LCD экран 16Х2 с I2C
  3. Аналоговый джойстик нонейм
  4. Датчик DS18B20 в герметичном корпусе
  5. Блок реле на 4 реле с транзисторами без опторазвязки. (Как что-то сдохнет, переключу на другое)
  6. 3,5мм гнездо 3 пина с дополнительными контактами (миниджек)
  7. Разъём DIN-5
  8. Вилка DIN-5
  9. БП 5В от самсунга
  10. Коробка распаячная под дерево 100х100
  11. Резистор 4,7к
  12. Предполагается еще - Датчик DS18B20 в неизвестном исполнении
  13. Предполагается еще - Вилка 3,5мм 3 пина
  14. Предполагается еще - Резистор 4,7к

 

Распиновка:

Разъём DIN-5

1 — плюс

2 — авто - D4

3 — горелка - D5

4 — датчик - D2

5 — минус

 по часовой стрелке

 

3,5 мм разъем

1 — общий - плюс

2 — центр дата – D6

3 — конец - минус

4 — нз на минус – D7

 

Джойстик

1 — минус

2 — плюс

3 — VRX - A0

4 — VRY – A1

5 — SW – D3

 

LCD экран

1 — минус

2 — плюс

3 — SDA – A4

4 — SCL – A5

//ver. 2.2 arduino nano
// 
#include <Wire.h> 
#include <OneWire.h>  // поставить резисторы   4.7K от плюса на дата
#include <LiquidCrystal_I2C.h>
#include <DS18B20.h> //  AUTHOR: Rob.Tillaart@gmail.com расположение https://github.com/RobTillaart/DS18B20
#include <EEPROM.h> 



#define NoSensor1 0
#define NoSensor2 1

#define BUTTON_NONE 0
#define BUTTON_RIGHT 1
#define BUTTON_UP 2
#define BUTTON_DOWN 3
#define BUTTON_LEFT 4
#define BUTTON_SELECT 5

#define TimeStrobe 1000 // Время стробирования 1 секунда
#define Gisteresis 5 //Гистерезис температуры 5 градусов

#define SensorTN 2 // Датчик теплоносителя на порту 2
#define SensorIN 6 // Датчик внутренний на порту 6
#define Joystik 3 //Порт кнопки джойстика
#define Gorelka 5 //Порт горелки используем нормально замкнутый контакт
#define SensorINput 7 //Контакт подключения датчика в помещении. Подтянуть к плюсу. При отсутствии датчика - замкнут на землю
#define Auto 4 //Порт включения автоматики
#define ValueX A0 //Анлоговый порт подключения джойстика по оси X
#define ValueY A1 //Анлоговый порт подключения джойстика по оси Y
//#define Buzzer=10; //Порт бузера там есть ШИМ



  LiquidCrystal_I2C lcd(0x27,16,2); // Инициализация библиотеку LCD на пинах (для arduino nano) SDA – A4, SCL – A5

  OneWire  OneWire1(SensorTN); //Инициализируем датчик ТН
  DS18B20 TN(&OneWire1); //Создаем экземпляр объекта ТН
  //OneWire  OneWire2(SensorIN); //Инициализируем датчик внутренний
  //DS18B20 TIN(&OneWire2); //Создаем экземпляр объекта TIN






byte newButton;
byte oldButton;

DeviceAddress SensorTN_add; //Адрес датчика ТН
DeviceAddress SensorIN_add; //Адрес датчика внутреннего

boolean flagNagrev; //Флаг нагрева
boolean flagBackLight; //Флаг подсветки


unsigned long lastMillis;
byte temperatureStrobe;

byte sensorStrobe;
byte backLightStrobe;
byte Tset;
//byte plam;
byte lightStrobe;
float Ttn;
char Ttn_char[6]; //Массив под отображение т-ры теплоносителя
char Tset_char[6]; //Массив под отображение т-ры внутренней




// ***********************ПП ошибки датчиков **************************
void SensorsError(int err) {
  
    digitalWrite(Auto, HIGH); //Отключаем автоматику
    lcd.setCursor(15,1);
    lcd.print(" ");
    switch (err) {
      case NoSensor1:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("No sensor TN");
        break; 
      case NoSensor2:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("No sensor IN");  
        break;      
    }
   // Serial.println("ERROR");
    while (true); //затыкаемся здесь
       
}

  
  //**********************************ПП Считывание нажатия клавиш************************************
  int getPressedButton() {
  //int button;
  int buttonValueX = analogRead(ValueX); // считываем значения с аналогового входа ValueX
  int buttonValueY = analogRead(ValueY); // считываем значения с аналогового входа ValueY 
  boolean JoystikValue = digitalRead(Joystik); //считываем значение кнопки
  if ((buttonValueX > 100)&&(buttonValueX < 950)&& (buttonValueY > 100)&&(buttonValueY < 950)&&JoystikValue)  return BUTTON_NONE;
 
  if (buttonValueX > 950) return BUTTON_LEFT;  
  if (buttonValueX < 100) return BUTTON_RIGHT;
  if (buttonValueY < 100) return BUTTON_DOWN;
  if (buttonValueY > 950) return BUTTON_UP;
  if (!JoystikValue)      return BUTTON_SELECT;
  return BUTTON_NONE; //На всякий случай 
  }


//******************* подпрограмма выдачи на экран установленной температуры ***********************

void lcdPrintTset(byte Tt){
    lcd.setCursor(0,1);
    lcd.print("Tset=");
    lcd.print("            ");
    lcd.setCursor(5,1);
    dtostrf(Ttn, 3, 0, Tset_char);     
    lcd.print(Tset_char);
    lcd.print((char)223);     
    lcd.print("C");       
}

// ******************** Подпрограмма считывания и выдачи на экран текущей температуры теплоносителя ************************
float Ttn_print(){
   float _Ttn = TN.getTempC();
    while (Ttn == DEVICE_CRC_ERROR) Ttn=TN.getTempC();
    
    lcd.setCursor(0,0);
    lcd.print("Ttn =");
    lcd.setCursor(4,0);
    lcd.print("            ");
    lcd.setCursor(4,0);
    dtostrf(_Ttn, 4, 1, Ttn_char);     
    lcd.print(Ttn_char);
    lcd.print((char)223);     
    lcd.print("C");
    return _Ttn;
}

// ******************** Сетуп ************************

void setup(void) {
  Serial.begin(9600);
    Tset=EEPROM.read(0);
    if ((Tset <20)|(Tset>80)) { // если в EEPROM не поймешь чего
      Tset=20;
      EEPROM.write(0,Tset);
    }
    
    lcd.init();

    lcd.clear();
    lcd.backlight();                 // Подключение подсветки
    flagBackLight=true;
    oldButton=BUTTON_NONE;
    pinMode(Gorelka, OUTPUT);
    pinMode(Auto, OUTPUT);
    pinMode(Joystik, INPUT);
    pinMode(SensorINput, INPUT);
    
    digitalWrite(Joystik, HIGH); //Подтянем кнопку джойстика
    digitalWrite(SensorINput, HIGH); //Подтянем контакт наличая датчика
    digitalWrite(Gorelka, HIGH); // Выключим горелку
    digitalWrite(Auto, HIGH); //Выключим режим auto
//    Serial.println("Auto OFF");
//      Serial.println("Gorelka OFF");
//      plam=0;

    //         BuzzerBeep();
    if(!TN.begin()) SensorsError(NoSensor1);
    
    TN.requestTemperatures();
    delay(1000);
    Ttn = TN.getTempC();
    while (Ttn == DEVICE_CRC_ERROR) Ttn=TN.getTempC();
    
    lcd.setCursor(0,0);
    lcd.print("Ttn =");
    lcd.setCursor(4,0);
    lcd.print("            ");
    lcd.setCursor(4,0);
    dtostrf(Ttn, 4/*Полная_длина_строки*/, 1/*Количество_символов_после_запятой*/, Ttn_char);     
    lcd.print(Ttn_char);
    lcd.print((char)223);     
    lcd.print("C");
    lastMillis=millis();
    temperatureStrobe=0;
    sensorStrobe=0;
    lightStrobe=0;
    flagNagrev=false;

    lcdPrintTset(Tset); //Отображаем Tset
    
    digitalWrite(Auto, LOW); //Включаем автоматику 
    lcd.setCursor(15,1);
    lcd.print("A");
 }
 

// ---------------------------------------- Основная программа ---------------------------------------------------------------

void loop(void) {
// ***************Стробирование
  if ((millis()-lastMillis)>= TimeStrobe) { //стробируем раз в TimeStrobe
    lastMillis=millis();
    temperatureStrobe++;
    lightStrobe++;
    sensorStrobe++;

  }

// *************Считывание кнопки ***********************************************
  newButton=getPressedButton();
  if (newButton!=oldButton){
    oldButton=newButton;
  if (flagBackLight){ // Если свет горит, то выполняем команды
  switch (newButton){
    case BUTTON_UP:
      Tset++; //увеличение температуры на 1 градус
      if (Tset>80) Tset=80;
      lcdPrintTset(Tset);
      EEPROM.write(0,Tset);
      break;
    case BUTTON_DOWN:
      Tset--; //уменьшение температуры на 1 градус
      if (Tset<20) Tset=20;
      lcdPrintTset(Tset);
      EEPROM.write(0,Tset);
      break;
    case BUTTON_RIGHT:
      Tset+=5; //уменьшение температуры на 5 градусов
      if (Tset>80) Tset=80;
      lcdPrintTset(Tset);
      EEPROM.write(0,Tset);
      break;
    case BUTTON_LEFT:
      Tset-=5; //уменьшение температуры на 5 градусов
      if (Tset<20) Tset=20;
      lcdPrintTset(Tset);
      EEPROM.write(0,Tset);
      break; 
    case BUTTON_SELECT:
      lcd.backlight(); //Обнуление времени подсветки
      flagBackLight=true;
      lightStrobe=0;
      break;                         
  }
  } else { // Если свет не горит, то включаем свет
      lcd.backlight(); //Включение подсветки
      flagBackLight=true;
      lightStrobe=0;
    }
  }
// *************Управление горелкой ************************************
  
  if (flagNagrev){   // Если горит
    if (temperatureStrobe==4) TN.requestTemperatures();
    if (temperatureStrobe==5){ //Смотрим каждые 5 секунд
      temperatureStrobe=0;
      Ttn = Ttn_print();
      
      if (Ttn>=Tset) {
        digitalWrite(Gorelka, HIGH); //Выключаем горелку
        flagNagrev=false;
        lcd.setCursor(15,0);
        lcd.print(" ");
      }
    }
  } else{   //Если не горит
    if (temperatureStrobe==19) TN.requestTemperatures();

     if (temperatureStrobe==20){ //Смотрим каждые 20 секунд
      temperatureStrobe=0;
      
      Ttn = Ttn_print();
      
      if ( Ttn <=(Tset-Gisteresis)) {
        digitalWrite(Gorelka, LOW); //Включаем горелку
        flagNagrev=true;
        lcd.setCursor(15,0);
        lcd.print("F");
      }    
     } 
  }

//*******************Проверка датчика - для особо опасливых таких как я **************************************
  if (sensorStrobe==240){ //Проверяем наличие датчика каждые 240 секунд
    sensorStrobe=0;
    if(!TN.getAddress(SensorTN_add)) SensorsError(NoSensor1); //проверяем наличие датчика ТН
  }
  
//**************** Выключение подсветки через 60 секунд ****************************************
  if (lightStrobe>60){
    if (flagBackLight){
      lcd.noBacklight();
      flagBackLight=false;
    }
    lightStrobe=61;
  }

    }
 //------------------------------------------------------------------------------------------------------------

 

yucan
Offline
Зарегистрирован: 20.04.2015

Здравствуйте! В данный момент это устройство управляет котлом?

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Внес небольшие косметичесике изменения в программу

//ver. 2.2 arduino nano
// 
#include <Wire.h> 
#include <OneWire.h>  // поставить резисторы   4.7K от плюса на дата
#include <LiquidCrystal_I2C.h>
#include <DS18B20.h> //  AUTHOR: Rob.Tillaart@gmail.com расположение https://github.com/RobTillaart/DS18B20
#include <EEPROM.h> 



#define NoSensor1 0
#define NoSensor2 1

#define BUTTON_NONE 0
#define BUTTON_RIGHT 1
#define BUTTON_UP 2
#define BUTTON_DOWN 3
#define BUTTON_LEFT 4
#define BUTTON_SELECT 5

#define TimeStrobe 1000 // Время стробирования 1 секунда
#define Gisteresis 5 //Гистерезис температуры 5 градусов

#define SensorTN 2 // Датчик теплоносителя на порту 2
#define SensorIN 6 // Датчик внутренний на порту 6
#define Joystik 3 //Порт кнопки джойстика
#define Gorelka 5 //Порт горелки используем нормально замкнутый контакт
#define SensorINput 7 //Контакт подключения датчика в помещении. Подтянуть к плюсу. При отсутствии датчика - замкнут на землю
#define Auto 4 //Порт включения автоматики
#define ValueX A0 //Анлоговый порт подключения джойстика по оси X
#define ValueY A1 //Анлоговый порт подключения джойстика по оси Y
#define Led 13 //Светодиодик для мигания - индикатор работы
//#define Buzzer=10; //Порт бузера там есть ШИМ



  LiquidCrystal_I2C lcd(0x27,16,2); // Инициализация библиотеку LCD на пинах (для arduino nano) SDA – A4, SCL – A5

  OneWire  OneWire1(SensorTN); //Инициализируем датчик ТН
  DS18B20 TN(&OneWire1); //Создаем экземпляр объекта ТН
  //OneWire  OneWire2(SensorIN); //Инициализируем датчик внутренний
  //DS18B20 TIN(&OneWire2); //Создаем экземпляр объекта TIN






byte newButton;
byte oldButton;

DeviceAddress SensorTN_add; //Адрес датчика ТН
DeviceAddress SensorIN_add; //Адрес датчика внутреннего

boolean flagNagrev; //Флаг нагрева
boolean flagBackLight; //Флаг подсветки


unsigned long lastMillis;
byte temperatureStrobe;

byte sensorStrobe;
byte backLightStrobe;
byte Tset;
//byte plam;
byte lightStrobe;
float Ttn;
char Ttn_char[6]; //Массив под отображение т-ры теплоносителя
char Tset_char[6]; //Массив под отображение т-ры внутренней




// ***********************ПП ошибки датчиков **************************
void SensorsError(int err) {
  
    digitalWrite(Auto, HIGH); //Отключаем автоматику
    lcd.setCursor(15,1);
    lcd.print(" ");
    switch (err) {
      case NoSensor1:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("No sensor TN");
        break; 
      case NoSensor2:
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("No sensor IN");  
        break;      
    }
   // Serial.println("ERROR");
    while (true); //затыкаемся здесь
       
}

  
  //**********************************ПП Считывание нажатия клавиш************************************
  int getPressedButton() {
  //int button;
  int buttonValueX = analogRead(ValueX); // считываем значения с аналогового входа ValueX
  int buttonValueY = analogRead(ValueY); // считываем значения с аналогового входа ValueY 
  boolean JoystikValue = digitalRead(Joystik); //считываем значение кнопки
  if ((buttonValueX > 100)&&(buttonValueX < 950)&& (buttonValueY > 100)&&(buttonValueY < 950)&&JoystikValue)  return BUTTON_NONE;
 
  if (buttonValueX > 950) return BUTTON_LEFT;  
  if (buttonValueX < 100) return BUTTON_RIGHT;
  if (buttonValueY < 100) return BUTTON_DOWN;
  if (buttonValueY > 950) return BUTTON_UP;
  if (!JoystikValue)      return BUTTON_SELECT;
  return BUTTON_NONE; //На всякий случай 
  }


//******************* подпрограмма выдачи на экран установленной температуры ***********************

void lcdPrintTset(byte Tt){
    float _Tt=Tt;
    lcd.setCursor(0,1);
    lcd.print("Tset=");
    lcd.print("     ");
    lcd.setCursor(5,1);
    dtostrf(_Tt, 3, 0, Tset_char);     
    lcd.print(Tset_char);
    lcd.print((char)223);     
    lcd.print("C");       
}

// ******************** Подпрограмма считывания и выдачи на экран текущей температуры теплоносителя ************************
float Ttn_print(){
   float _Ttn = TN.getTempC();
    while (Ttn == DEVICE_CRC_ERROR) Ttn=TN.getTempC();
    
    lcd.setCursor(0,0);
    lcd.print("Ttn =");
    lcd.setCursor(5,0);
    lcd.print("     ");
    lcd.setCursor(5,0);
    dtostrf(_Ttn, 4, 1, Ttn_char);     
    lcd.print(Ttn_char);
    lcd.print((char)223);     
    lcd.print("C");
    return _Ttn;
}

// ******************** Сетуп ************************

void setup(void) {
  Serial.begin(9600);
    Tset=EEPROM.read(0);
    if ((Tset <20)|(Tset>80)) { // если в EEPROM не поймешь чего
      Tset=20;
   
      EEPROM.write(0,Tset);
    }
    
    lcd.init();

    lcd.clear();
    lcd.backlight();                 // Подключение подсветки
    flagBackLight=true;
    oldButton=BUTTON_NONE;
    pinMode(Gorelka, OUTPUT);
    pinMode(Auto, OUTPUT);
    pinMode(Led, OUTPUT);
    pinMode(Joystik, INPUT);
//    pinMode(SensorINput, INPUT);
    
    digitalWrite(Joystik, HIGH); //Подтянем кнопку джойстика
//    digitalWrite(SensorINput, HIGH); //Подтянем контакт наличая датчика
    digitalWrite(Gorelka, HIGH); // Выключим горелку
    digitalWrite(Auto, HIGH); //Выключим режим auto
    digitalWrite(Led, HIGH); //Включим светодиод
//    Serial.println("Auto OFF");
//      Serial.println("Gorelka OFF");
//      plam=0;

    //         BuzzerBeep();
    if(!TN.begin()) SensorsError(NoSensor1);
    
    TN.requestTemperatures();
    delay(1000);
    Ttn = TN.getTempC();
    while (Ttn == DEVICE_CRC_ERROR) Ttn=TN.getTempC();
    
    lcd.setCursor(4,0);
    lcd.print("            ");
    lcd.setCursor(4,0);
    dtostrf(Ttn, 4/*Полная_длина_строки*/, 1/*Количество_символов_после_запятой*/, Ttn_char);     
    lcd.print(Ttn_char);
    lcd.print((char)223);     
    lcd.print("C");
    lastMillis=millis();
    temperatureStrobe=0;
    sensorStrobe=0;
    lightStrobe=0;
    flagNagrev=false;

    lcdPrintTset(Tset); //Отображаем Tset
    
    digitalWrite(Auto, LOW); //Включаем автоматику 
    lcd.setCursor(15,1);
    lcd.print("A");
 }
 

// ---------------------------------------- Основная программа ---------------------------------------------------------------

void loop(void) {
// ***************Стробирование
  if ((millis()-lastMillis)>= TimeStrobe) { //стробируем раз в TimeStrobe
    lastMillis=millis();
    temperatureStrobe++;
    lightStrobe++;
    sensorStrobe++;
    digitalWrite(Led,!digitalRead(Led)); //Мигаем светодиодом

  }

// *************Считывание кнопки ***********************************************
  newButton=getPressedButton();
  if (newButton!=oldButton){
    oldButton=newButton;
  if (flagBackLight){ // Если свет горит, то выполняем команды
  switch (newButton){
    case BUTTON_UP:
      Tset++; //увеличение температуры на 1 градус
      if (Tset>80) Tset=80;
      lcdPrintTset(Tset);
      EEPROM.write(0,Tset);
      break;
    case BUTTON_DOWN:
      Tset--; //уменьшение температуры на 1 градус
      if (Tset<20) Tset=20;
      lcdPrintTset(Tset);
      EEPROM.write(0,Tset);
      break;
    case BUTTON_RIGHT:
      Tset+=5; //уменьшение температуры на 5 градусов
      if (Tset>80) Tset=80;
      lcdPrintTset(Tset);
      EEPROM.write(0,Tset);
      break;
    case BUTTON_LEFT:
      Tset-=5; //уменьшение температуры на 5 градусов
      if (Tset<20) Tset=20;
      lcdPrintTset(Tset);
      EEPROM.write(0,Tset);
      break; 
    case BUTTON_SELECT:
      lcd.backlight(); //Обнуление времени подсветки
      flagBackLight=true;
      lightStrobe=0;
      break;                         
  }
  } else { // Если свет не горит, то включаем свет
      lcd.backlight(); //Включение подсветки
      flagBackLight=true;
      lightStrobe=0;
    }
  }
// *************Управление горелкой ************************************
  
  if (flagNagrev){   // Если горит
    if (temperatureStrobe==4) TN.requestTemperatures();
    if (temperatureStrobe==5){ //Смотрим каждые 5 секунд
      temperatureStrobe=0;
      Ttn = Ttn_print();
      
      if (Ttn>=Tset) {
        digitalWrite(Gorelka, HIGH); //Выключаем горелку
        flagNagrev=false;
        lcd.setCursor(15,0);
        lcd.print(" ");
      }
    }
  } else{   //Если не горит
    if (temperatureStrobe==19) TN.requestTemperatures();

     if (temperatureStrobe==20){ //Смотрим каждые 20 секунд
      temperatureStrobe=0;
      
      Ttn = Ttn_print();
      
      if ( Ttn <=(Tset-Gisteresis)) {
        digitalWrite(Gorelka, LOW); //Включаем горелку
        flagNagrev=true;
        lcd.setCursor(15,0);
        lcd.print("F");
      }    
     } 
  }

//*******************Проверка датчика - для особо опасливых таких как я **************************************
  if (sensorStrobe==240){ //Проверяем наличие датчика каждые 240 секунд
    sensorStrobe=0;
    if(!TN.getAddress(SensorTN_add)) SensorsError(NoSensor1); //проверяем наличие датчика ТН
  }
  
//**************** Выключение подсветки через 60 секунд ****************************************
  if (lightStrobe>60){
    if (flagBackLight){
      lcd.noBacklight();
      flagBackLight=false;
    }
    lightStrobe=61;
  }

    }
 //------------------------------------------------------------------------------------------------------------

Ну и фото пациента в действии