salhar1
Published © GPL3+

Mini-Thermostat

Mini-thermostat with input for a 2-wire NTC thermistor and output for a resistive heating element. Plus code & schematics.

IntermediateShowcase (no instructions)17,865
Mini-Thermostat

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
USB-A to B Cable
USB-A to B Cable
×1
Resistor 10k ohm
Resistor 10k ohm
×1
Arduino prototype shield
×1
10 K NTC Thermistor
×1
Power N-MOSFET
×1
Arduino enclosure (optional)
×1

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

Circuit diagram (overview)

Code

Temperature controller

C/C++
Complete temperature controller code. Just copy and paste.

Includes:
- thermistor code for temperature readout
- code for controlling heater input
- basic PID controller
- basic serial interface
// variables and definitions

      //Important parameter, set to match environment
          const int dt = 500; // [ms] time constant in milliseconds (controller clock rate = 1/(dt/1000) [Hz])
          #define SetTemp 62.8 // [degC] set temperature in DegC
          #define MinTemp 20 // [degC] minimum expected temperature (needed for rescaling inputs)
          #define MaxTemp 65 // [degC] maximum allowed temperature, over which heater is turned off (needed for rescaling inputs)
          int SetTime = 1800; // [s] timer in seconds, if reached, running stops [Default: 1800]

      //I/O pins - don't edit unless replaced
          #define thermistorPin A0
          #define FETPin 3
          //#define LEDPin //number of LED pin (optional)

      //control parameters - editing not recommended     
          double K_P_ctrl = 15; //proportional gain
          double K_I_ctrl = 0; //integral gain (set to lower values i.e. 10^-3)
          double K_D_ctrl = 0; //derivative gain

// including headers and definitions
  #include <math.h>

//Inititalization
    //target temperature reached?
       bool bInRange = 0;

    //ticks per ms
       int TicksPerMS = floor(1000/dt);

    //Initialize PID variables:
       float previous_error = 0;
       float s_integral = 0;

//Thermistor code
    double Thermistor(int RawADC) {
      double Temp;
      Temp = log(10000.0*((1024.0/RawADC-1))); 
      Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
      Temp = Temp - 273.15;            // Convert Kelvin to Celcius
      return Temp;
    }

//PID controller code
    void Control_PID(double iTemp){
        
      //Overheat protection
          if(iTemp>MaxTemp){
            analogWrite(FETPin, 0);
            Serial.println("Error:overheat. Heater turned off");
            return;
          }
        
      //In range? If in range, maybe turn on LED?
          if((iTemp) >= SetTemp){
            if(bInRange==0){
              //digitalWrite(LEDPin, HIGH); 
              bInRange=1;
            }
          }else{
            if(bInRange==1){
              //digitalWrite(LEDPin, LOW); 
              bInRange=0;
            }
          }
          
        
        //PID subroutine
          float err = SetTemp - iTemp;
          //Serial.println(err);
          s_integral += err*dt;
          //Serial.println(s_integral);
          float s_derivative = (err - previous_error)/dt;
          //Serial.println(s_derivative);
          int U_in_ctrl = (K_P_ctrl*err + K_I_ctrl*s_integral + K_D_ctrl*s_derivative)/(MaxTemp-MinTemp)*255;
          previous_error = err;
                 
          
        // put voltage to output and write value to serial monitor
            Serial.print("Output PWM frequency: ");
            
            if (U_in_ctrl<=255){
               if (U_in_ctrl > 0){
                  analogWrite(FETPin, U_in_ctrl);
                  Serial.println(U_in_ctrl);                
               }           
               else
               {
                  analogWrite(FETPin, 1);
                  Serial.println("1 - cca. 0 V"); 
               }
            }
            else{
               analogWrite(FETPin,255);
               Serial.println("255 - cca. 5 V");             
            }                   
    }

void setup() {
    Serial.begin(9600);
    pinMode(FETPin, OUTPUT);
  //pinMode(LEDPin, OUTPUT);
  
    //rescale timer according to dt
    SetTime = SetTime * TicksPerMS;
}

void loop() {
  //Take a temperature reading and display it 
    double Temp = double(Thermistor(analogRead(thermistorPin)));
    Serial.print("Temperature:");
    Serial.println(Temp);  // display temperature
  
  //Timer serial out - displays time on serial monitor
    Serial.print(SetTime/60*dt/1000);
    Serial.print(" [mins] - SetTime: ");
    Serial.print(SetTime);
    Serial.println("");
        
  //Call controller algorithm 
    Control_PID(Temp); // call controller algorithm
  
  //End line in serial monitor...
    Serial.println("");
    Serial.println("");
   
  //Timer ticking (countdown)
    if (SetTime>0){
        SetTime--;
        // if zero reached
        if (SetTime==0){

          while(1) {
            //loop until disconnected
            Serial.println("Time ran out, controller stopped. Please disconnect or reset the controller.");
            digitalWrite(FETPin, LOW);
            delay(dt);
          } 
        }
    }
    
   //wait dt before next cycle
      delay(dt); 
}

Heater control library CPP

C/C++
Arduino library for heater control. You can include this in your own project.
/****************************************************************
 * Heater control library 
 *
 *  Return codes:
 *   1: in range
 *   0: not in range
 *   -1: error
*****************************************************************/

#include "Arduino.h"
#include "HeaterControl.h"

HeaterControl::HeaterControl(int FETPin)
{
  pinMode(FETPin, OUTPUT);
  _FETPin = FETPin;
}

int HeaterControl::Control_PID(double dCurrentTemperature, int dt, int ThresholdTemp, double MaxTemp, double MinTemp, double SetTemp, double K_P_ctrl, double K_I_ctrl, double K_D_ctrl)
{
  bool bInRange =0;
  
  //Overheat protection
  if (dCurrentTemperature > MaxTemp) {
    analogWrite(_FETPin, 0); //turn off heater
    return -1; //return with overheat code
  }

  //In range? If yes, return with in range code
  if (dCurrentTemperature >= ThresholdTemp && dCurrentTemperature < (ThresholdTemp + 2)) { bInRange = 1; }

  //PID subroutine
  float err = SetTemp - dCurrentTemperature;
  s_integral += err * dt;
  float s_derivative = (err - previous_error) / dt;
  int U_in_ctrl = (K_P_ctrl * err + K_I_ctrl * s_integral + K_D_ctrl * s_derivative) / (MaxTemp - MinTemp) * 255;
  previous_error = err;

  // put voltage to output and write value to serial monitor
  if (U_in_ctrl <= 255) 
  {
    if (U_in_ctrl > 0) {
      analogWrite(_FETPin, U_in_ctrl);
    }
    else
    {
      analogWrite(_FETPin, 1);
    }
  }
  else 
  {
    analogWrite(_FETPin, 255);
  }

  return bInRange;
}


void HeaterControl::TurnOff()
{
  analogWrite(_FETPin, 0); //turn off heater 
}

Heater control library header

C/C++
Header for heater control library
/****************************************************************
 * Heater control library header
 *
*****************************************************************/

#ifndef HeaterControl_h
#define HeaterControl_h

#include "Arduino.h"

class HeaterControl
{
  public:
    HeaterControl(int FETPin);
    int Control_PID(double dCurrentTemperature, int dt, int ThresholdTemp, double MaxTemp, double MinTemp, double SetTemp, double K_P_ctrl, double K_I_ctrl, double K_D_ctrl); //for ATMega328P
    void TurnOff();
   
  private:
    //received
    int _FETPin;
    
    //internal
    float previous_error = 0; //Initialize PID variables
    float s_integral = 0; //Initialize PID variables
};

#endif

Thermometer library CPP

C/C++
Arduino library for thermistor input. You can include this in your own project
#include "Arduino.h"
#include "Thermistor.h"

Thermistor::Thermistor(int ThermistorPin)
{
  pinMode(ThermistorPin, INPUT);
  thermistorPin = ThermistorPin;
}

double Thermistor::Thermistor_Read(int TemperatureOffset, double T0, double R0, double B)
{
  //Thermistor code with a generalized equation
  //Steinhart-Hart equation: T[K]=1/(a+b*log(R)+c*(log(R))^3)
  //where a=1/T_0-(1/B)*log(R_0), b=1/B and c = 0

  //take a reading:
  int RawADC = analogRead(thermistorPin);
  double Temp;

  double R;
  R = 10000.0 * (1024.0 / RawADC - 1);
  Temp = 1 / (1 / T0 + 1 / B * log(R / R0));
  Temp = Temp - 273.15;            // Convert Kelvin to Celsius
  return Temp;
}

Thermometer library header

C/C++
Header for thermometer library
/* Thermistor control library header
*/

#ifndef Thermistor_h
#define Thermistor_h

#include "Arduino.h"

class Thermistor
{
  public:
    Thermistor(int ThermistorPin); //constructor
    double Thermistor_Read(int TemperatureOffset);   
    double Thermistor_Read(int TemperatureOffset, double T0, double R0, double B);
    
  private:
    int thermistorPin;    
};

#endif

Credits

salhar1

salhar1

0 projects • 5 followers
Thanks to Adafruit.

Comments