Wednesday 13 February 2019

Arduino'da inkübatör termostatı veya PID regülatörü


PID kontrollü bir termostat kullanımı kümes hayvanları yetiştiriciliği ile sınırlı olmamakla
 birlikte, KO , proje demiryolları tarafından banyosunun sıcaklığını korumak için kullanılabilir, damıtıcılardaki damıtıcılar, kazandaki suyu basitçe sıcak bir ısıda tutabilir, küçük değişikliklerden sonra, ev yapımı lehimleme istasyonlarında, mufle fırınlarında, karof Yüksek hassasiyetli sıcaklık kontrolü gereklidir. Çalışma prensibi ve histeresiz banal termostattan farkı videoda gösterilmiştir:









Röle hakkında:

Regülatörde elektromekanik rölelerin kullanılması kesinlikle tavsiye edilmez,
 sık anahtarlamada başarısız olurlar, bu özellikle Çin rölesi modülleri için bir kaç dolara uygulanır.









Doğru çözüm, katı akım rölesi veya gerekli akım için triyak (esas olarak aynı) olan bir modül
 kullanmak olacaktır. Örneğin, 25A'da SSR-25DA , eğer ısıtıcı gücü birkaç kW civarındaysa, 
OMRON G3MB 202P 2A veya 440W'a kadar tutar.











Onları elinde bulundurmadım, yerel radyo
 parçaları deposunda 8A'da BT137x-800 simülatörüyle bir ekmeklik panosunda bir simitör ile 
bir galvanik izolasyon ve "sıfır algılama" için bir optosimistor MOC3063 satın almak zorunda kaldım. Devre MOC3063 üzerindeki veri sayfasından alınmıştır.

Исходные коды:

Датчик температуры TMP102, LCD1602
//Термостат для инкубатора или PID регулятор на arduino
//код из видео https://www.youtube.com/watch?v=9odcsuAquLU
//донат, http://www.donationalerts.ru/r/arduinolab

/// датчик температуры TMP102, LCD1602
 
 

#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#include "SparkFunTMP102.h"
#include <PID_v1.h>

TMP102 tmp102(0x48); 
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
//////////////////////////////////////////
#define ENCODER_A 2     // вход энкодера
#define ENCODER_B 3
#define ENCODER_KEY 11

#define TEMP_MAX 60.0  // Приделы настройки термостата
#define TEMP_MIN 25.0

#define RELAY_PIN 12           // выход на реле

#define WindowSize 512       // периуд, для симистора можно оставить, для
                             // реле увеличить в ~10 раз
////////////////////////////////////////////// 

bool encoderPinALast = LOW;
bool n = LOW;
unsigned long windowStartTime;

double Setpoint, Input, Output;
double Kp=2, Ki=5, Kd=1.5;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
 
float temperature;
 
void setup() {
//   Serial.begin(9600);
   
   tmp102.begin();
   
   lcd.begin(16, 2);
   lcd.clear();

   pinMode(RELAY_PIN, OUTPUT);
   pinMode (ENCODER_A, INPUT);
   pinMode (ENCODER_B, INPUT);
   pinMode (ENCODER_KEY, INPUT);
   
   tmp102.wakeup();

   myPID.SetOutputLimits(0, WindowSize);
   myPID.SetMode(AUTOMATIC); 

      //// проверка ЕЕПРОМ для первого включения 
   if (EEPROM.read(0) == 255 && EEPROM.read(4) == 255){
        EEPROM.write(0, 10);
        EEPROM.write(1, 0);
        EEPROM.write(2, 240);
        EEPROM.write(3, 65);
   }
 
   EEPROM.get(0, Setpoint);

 
}

void loop() {
  temperature = tmp102.readTempC();
  Input = temperature;
  
  myPID.Compute();  

   lcd.setCursor(0, 0);
   lcd.print(temperature);
   lcd.print("C  ");
   lcd.setCursor(8, 0);
   lcd.print(Setpoint, 1);
   lcd.print("C     ");
   lcd.setCursor(0, 1); 
   lcd.print(map(Output, 0, WindowSize, 0, 100)); 
   lcd.print("%  "); 
   lcd.setCursor(8, 1);  
   lcd.print(Output);
   lcd.print("mS "); 
     

///////////////////////


   if(!digitalRead(ENCODER_KEY)){ // если надавили на кнопку, входим в настройки
     lcd.setCursor(13, 0); 
     lcd.print("<<");  
                                  // управление энкодером
   n = digitalRead(ENCODER_A);
   if ((encoderPinALast == LOW) && (n == HIGH)) {
     if (digitalRead(ENCODER_B) == LOW) {
        Setpoint -= .1; 
        if (Setpoint < TEMP_MIN) Setpoint = TEMP_MIN;        
// проверяем приделы настроек
     } else {
        Setpoint += .1; 
        if (Setpoint > TEMP_MAX) Setpoint = TEMP_MAX;
     }  
   } 
   EEPROM.put(0, Setpoint);                        
  // пишим в еепром настройку 
   encoderPinALast = n;
  delay(5);
//  return;
   }


   // * turn the output pin on/off based on pid output   
  if (millis() - windowStartTime >= WindowSize) { //time to shift the Relay Window
    windowStartTime += WindowSize;
    if (windowStartTime > millis()) windowStartTime = 0;   
 // защита от переполнения
  }
  if (Output < millis() - windowStartTime) digitalWrite(RELAY_PIN, LOW);
  else digitalWrite(RELAY_PIN, HIGH);
 

}
Датчик температуры TMP102, LCD0802
//Термостат для инкубатора или PID регулятор на arduino
//код из видео https://www.youtube.com/watch?v=9odcsuAquLU
//донат, http://www.donationalerts.ru/r/arduinolab

/// датчик температуры TMP102, LCD0802
///  отличается только выводом информации на ЖК

#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#include "SparkFunTMP102.h"                   
// https://github.com/sparkfun/SparkFun_TMP102_Arduino_Library
#include <PID_v1.h>                          
 // https://playground.arduino.cc/Code/PIDLibrary

TMP102 tmp102(0x48);                          
// адрес TMP102 на шине, может отличатся.
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
//////////////////////////////////////////
#define ENCODER_A 2                          // вход энкодера
#define ENCODER_B 3
#define ENCODER_KEY 11

#define TEMP_MAX 60.0                        // Приделы настройки термостата
#define TEMP_MIN 25.0

#define RELAY_PIN 12                         // выход на реле

#define WindowSize 512                       
// периуд, для симистора можно оставить, для
                                             
//  реле увеличить в ~10 раз
////////////////////////////////////////////// 

bool encoderPinALast = LOW;
bool n = LOW;
unsigned long windowStartTime;

double Setpoint, Input, Output;
double Kp=2, Ki=5, Kd=1.5;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
 
float temperature;
 
void setup() {
//   Serial.begin(9600);
   
   tmp102.begin();
   
   lcd.begin(8, 2);
   lcd.clear();

   pinMode(RELAY_PIN, OUTPUT);
   pinMode(ENCODER_A, INPUT);
   pinMode(ENCODER_B, INPUT);
   pinMode(ENCODER_KEY, INPUT);
   
   tmp102.wakeup();

   myPID.SetOutputLimits(0, WindowSize);
   myPID.SetMode(AUTOMATIC); 


   //// проверка ЕЕПРОМ для первого включения 
   if (EEPROM.read(0) == 255 && EEPROM.read(4) == 255){
        EEPROM.write(0, 10);
        EEPROM.write(1, 0);
        EEPROM.write(2, 240);
        EEPROM.write(3, 65);
   }
 
   EEPROM.get(0, Setpoint);

 
}

void loop() {
  temperature = tmp102.readTempC();
  Input = temperature;
  
  myPID.Compute(); 
    

/////////////////////// 

   if(!digitalRead(ENCODER_KEY)){                    
// если надавили на кнопку, входим в настройки
                                         
         lcd.setCursor(0, 0);                       
 // отображаем страницу настроек
         lcd.print("settings"); 
         lcd.setCursor(1, 1); 
         lcd.print(Setpoint, 1);
         lcd.print("C   ");   
         
                                                    
 // управление энкодером
   n = digitalRead(ENCODER_A);
   if ((encoderPinALast == LOW) && (n == HIGH)) {
     if (digitalRead(ENCODER_B) == LOW) {
        Setpoint -= .1; 
        if (Setpoint < TEMP_MIN) Setpoint = TEMP_MIN;       
 // проверяем приделы настроек
     } else {
        Setpoint += .1; 
        if (Setpoint > TEMP_MAX) Setpoint = TEMP_MAX;
     }  
   } 
   EEPROM.put(0, Setpoint);                         
 // пишим в еепром настройку 
   encoderPinALast = n;
  delay(5);
 
   }
                                                     
// иначе отобрадаем страницу с текущей 
   else{                                            
 //  температурой и мощьностью
     lcd.setCursor(0, 0);
     lcd.print(temperature);
     lcd.print("C  ");
   
     lcd.setCursor(1, 1); 
     lcd.print(map(Output, 0, WindowSize, 0, 100)); 
     lcd.print("%    "); 
 
   }


      //*urn the output pin on/off based on pid output   
  if (millis() - windowStartTime >= WindowSize) {    // таймер на миллис
    windowStartTime += WindowSize;
    if (windowStartTime > millis()) windowStartTime = 0; // защита от переполнения
  }
  if (Output < millis() - windowStartTime) digitalWrite(RELAY_PIN, LOW);
  else digitalWrite(RELAY_PIN, HIGH);
 

}
Датчик температуры LM35, LCD1602
//Термостат для инкубатора или PID регулятор на arduino
//код из видео https://www.youtube.com/watch?v=9odcsuAquLU
//донат, http://www.donationalerts.ru/r/arduinolab

/// датчик температуры LM35

#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal.h> 
#include <PID_v1.h>                         
// https://playground.arduino.cc/Code/PIDLibrary

 
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
//////////////////////////////////////////
#define ENCODER_A 2                  // вход энкодера
#define ENCODER_B 3
#define ENCODER_KEY 11
#define LM35_PIN A5                  // вход датчика LM35 (1-5V, 2-OUT, 3-GND)

#define TEMP_MAX 60.0             // Приделы настройки термостата
#define TEMP_MIN 25.0

#define RELAY_PIN 12               // выход на реле

#define WindowSize 500         // периуд, для симистора можно оставить, для
                                             // реле увеличить в ~10 раз
////////////////////////////////////////////// 

bool encoderPinALast = LOW;
bool n = LOW;
unsigned long windowStartTime;

double Setpoint, Input, Output;
double Kp=2, Ki=5, Kd=1.5;                    // коэффициенты настройки PID
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
 
float temperature;
 
 
void setup() {
//   Serial.begin(9600); 
   
   lcd.begin(16, 2);
   lcd.clear();

   pinMode(RELAY_PIN, OUTPUT);
   pinMode (ENCODER_A, INPUT);
   pinMode (ENCODER_B, INPUT);
   pinMode (ENCODER_KEY, INPUT);
   
   analogReference(INTERNAL);              
     // включаем внутрений источник опорного 1,1 вольт

   myPID.SetOutputLimits(0, WindowSize);
   myPID.SetMode(AUTOMATIC); 

      //// проверка ЕЕПРОМ для первого включения 
   if (EEPROM.read(0) == 255 && EEPROM.read(4) == 255){
        EEPROM.write(0, 10);
        EEPROM.write(1, 0);
        EEPROM.write(2, 240);
        EEPROM.write(3, 65);
   }
 
   EEPROM.get(0, Setpoint);

 
}

void loop() {
 
  temperature = analogRead(LM35_PIN) / 9.31;  // забераем температуру 
  Input = temperature;
  
  myPID.Compute();  
   

/////////////////////// 

   if(!digitalRead(ENCODER_KEY)){    // если надавили на кнопку, входим в настройки
       digitalWrite(RELAY_PIN, LOW); // и выключаем нагреватель.     
         lcd.clear();                  // очищаем экран и выводим параметр 
         lcd.setCursor(8, 0);
         lcd.print(Setpoint, 1);
         lcd.print("C  "); 
                                                     // управление энкодером
   n = digitalRead(ENCODER_A);
   if ((encoderPinALast == LOW) && (n == HIGH)) {
     if (digitalRead(ENCODER_B) == LOW) {
        Setpoint -= .1; 
        if (Setpoint < TEMP_MIN) Setpoint = TEMP_MIN;// проверяем приделы настроек
     } else {
        Setpoint += .1; 
        if (Setpoint > TEMP_MAX) Setpoint = TEMP_MAX;
     }  
     EEPROM.put(0, Setpoint);                          // пишим в еепром настройку 
   }  
   encoderPinALast = n; 
  delay(5);
  return;
   }

 //
  if (millis() - windowStartTime >= WindowSize) {    // таймер на миллис
    windowStartTime += WindowSize;
     if (windowStartTime > millis()) windowStartTime = 0;// защита от переполнения

       lcd.setCursor(0, 0);                                  
       lcd.print(temperature);              // вывод на экран перенес в таймер
       lcd.print("C  ");                    //  чтение с LM35 происходит быстрее. 
       lcd.setCursor(8, 0);                 //  отсутствует необходимая LCD 
       lcd.print(Setpoint, 1);              //  экрану зарежка
       lcd.print("C  ");
       lcd.setCursor(0, 1); 
       lcd.print(map(Output, 0, WindowSize, 0, 100)); 
       lcd.print("%  "); 
       lcd.setCursor(8, 1);  
       lcd.print(Output);
       lcd.print("mS "); 
  }
  if (Output < millis() - windowStartTime) digitalWrite(RELAY_PIN, LOW);
  else digitalWrite(RELAY_PIN, HIGH);
 

}
Датчик температуры MCP9808, LCD1602
//Термостат для инкубатора или PID регулятор на arduino
//код из видео https://www.youtube.com/watch?v=9odcsuAquLU
//донат, http://www.donationalerts.ru/r/arduinolab

/// датчик температуры MCP9808, LCD1602
 
 

#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#include "Adafruit_MCP9808.h"                
// https://codeload.github.com/adafruit/Adafruit_MCP9808_Library/zip/master
#include <PID_v1.h>                          
// https://playground.arduino.cc/Code/PIDLibrary 

Adafruit_MCP9808 tempsensor = Adafruit_MCP9808();
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
//////////////////////////////////////////
#define ENCODER_A 2                          // вход энкодера
#define ENCODER_B 3
#define ENCODER_KEY 11

#define TEMP_MAX 60.0                        // Приделы настройки термостата
#define TEMP_MIN 25.0

#define RELAY_PIN 12                         // выход на реле

#define WindowSize 512        // периуд, для симистора можно оставить, для
                                             // реле увеличить в ~10 раз
////////////////////////////////////////////// 

bool encoderPinALast = LOW;
bool n = LOW;
unsigned long windowStartTime;

double Setpoint, Input, Output;
double Kp=2, Ki=5, Kd=1.5;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
 
float temperature;
 
void setup() {
//   Serial.begin(9600);
    
   lcd.begin(16, 2);
   lcd.clear();

   if (!tempsensor.begin()) {
    lcd.print("not find MCP9808!");
    while (1);
  }

   pinMode(RELAY_PIN, OUTPUT);
   pinMode (ENCODER_A, INPUT);
   pinMode (ENCODER_B, INPUT);
   pinMode (ENCODER_KEY, INPUT); 

   myPID.SetOutputLimits(0, WindowSize);
   myPID.SetMode(AUTOMATIC); 

      //// проверка ЕЕПРОМ для первого включения 
   if (EEPROM.read(0) == 255 && EEPROM.read(4) == 255){
        EEPROM.write(0, 10);
        EEPROM.write(1, 0);
        EEPROM.write(2, 240);
        EEPROM.write(3, 65);
   }
 
   EEPROM.get(0, Setpoint);

 
}

void loop() {
  temperature = tempsensor.readTempC();
  Input = temperature;
  
  myPID.Compute();  

   lcd.setCursor(0, 0);
   lcd.print(temperature);
   lcd.print("C  ");
   lcd.setCursor(8, 0);
   lcd.print(Setpoint, 1);
   lcd.print("C     ");
   lcd.setCursor(0, 1); 
   lcd.print(map(Output, 0, WindowSize, 0, 100)); 
   lcd.print("%  "); 
   lcd.setCursor(8, 1);  
   lcd.print(Output);
   lcd.print("mS "); 
     

///////////////////////


   if(!digitalRead(ENCODER_KEY)){                    
// если надавили на кнопку, входим в настройки
     lcd.setCursor(13, 0); 
     lcd.print("<<");  
                                                  // управление энкодером
   n = digitalRead(ENCODER_A);
   if ((encoderPinALast == LOW) && (n == HIGH)) {
     if (digitalRead(ENCODER_B) == LOW) {
        Setpoint -= .1; 
        if (Setpoint < TEMP_MIN) Setpoint = TEMP_MIN;       
 // проверяем приделы настроек
     } else {
        Setpoint += .1; 
        if (Setpoint > TEMP_MAX) Setpoint = TEMP_MAX;
     }  
   } 
   EEPROM.put(0, Setpoint);                    // пишим в еепром настройку 
   encoderPinALast = n;
  delay(5);
//  return;
   }


      /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if (millis() - windowStartTime >= WindowSize) { //time to shift the Relay Window
    windowStartTime += WindowSize;
    if (windowStartTime > millis()) windowStartTime = 0;  // защита от переполнения
  }
  if (Output < millis() - windowStartTime) digitalWrite(RELAY_PIN, LOW);
  else digitalWrite(RELAY_PIN, HIGH);
 

}

No comments: