Precise temperature control system with TEC

Hello,

I try to build temperature control system using TEC (thermo-electric cooler or Peltier element) as heating-cooling body, thermocouple as feedback and Arduino as brain. I'm new to arduino and microcontrollers in general. I watched some DIY videos where people build similar systems, but once I tried build it myself, it didn't work as expected. I created discussion here with hope, that you can point out on ideas that I might have missed.

Now I'll try to provide more details. Once again because of my lack of experience some details might be not relevant or I can miss something. Please do not hesitate asking me if you need something else.

General purpose of the system:
Change and maintain temperature of working body in temperature range of 25 - 35 C. Woking body is small plastic container with water (~1cm X 1cm X 0.3cm).

The Device allows to set temperature. Then it adjusts voltage supplied to TEC to reach this temperature. After that the device maintains temperature constant.

If the set temperature is higher than actual one, voltage is applied in one direction to heat the top surface of TEC. If the set temperature is lower, voltage should be applied in different direction to cool down top surface.

Here are some requirements (or good to have) for the system:

  1. Fast heating-cooling. In temperature range 25-35 C it must do its job within seconds.
  2. Linear change of temperature.
  3. Precise maintanence of temperature if desired temperature is reached. Fluctuation no more then 0.2 will be ok. Lower better =)

Now, I'll try to explain how I thought to reach this goal before. Maybe it helps you to guide me better.

I used the scheme proposed in the following video

I did some changes in the code though. Instead of using LED i used Arduino serial terminal to read current state. So, LED relating part of code I successfuly removed.

I used Elegoo UNO R3 (is it still arduino?).
For feedback system I used the same things as in the video: K-type thermocouple, ADC - MAX 6675 powered by 5V from controller.
I used simple rotary encoder to change set temperature. Power: 5V from controller.
For voltage control part I used NPN S8050 transistor, MOSFET IRFZ44, 10k resistor. Power: 12V from external power supply.
As heater-cooler I used TEC-12706.

I've managed to read actual temperature from thermocouple and change set temperature via rotary encoder. But I can't apply needed voltage with respect to changes of temperature. Here I attached some pictures of how I did connections.

Thank you for reading to the end. I highly appreciate any help with my problem. I understand that this might be quite simple task but once again I'm not experienced in this field, so will be happy to all reasonable advices and references.

Code is shown below

/*    Max6675 Module  ==>   Arduino
 *    CS              ==>     D10
 *    SO              ==>     D12
 *    SCK             ==>     D13
 *    Vcc             ==>     Vcc (5v)
 *    Gnd             ==>     Gnd      */
#include <SPI.h>

//LCD config
#include <Wire.h> 

//I/O
int PWM_pin = 3;  //Pin for PWM signal to the MOSFET driver (the BJT npn with pullup)
int clk = 8;      //Pin 1 from rotary encoder
int data = 9;     //Pin 2 from rotary encoder


//Variables
float set_temperature = 40;            //Default temperature setpoint. Leave it 0 and control it with rotary encoder

float temperature_read = 0.0;
float PID_error = 0;
float previous_error = 0;
float elapsedTime, Time, timePrev;
float PID_value = 0;
int button_pressed = 0;
int menu_activated=0;
float last_set_temperature = 0;

//Vraiables for rotary encoder state detection
int clk_State;
int Last_State;  
bool dt_State;  

//PID constants
//////////////////////////////////////////////////////////
int kp = 90;   int ki = 30;   int kd = 80;
//////////////////////////////////////////////////////////

int PID_p = 0;    int PID_i = 0;    int PID_d = 0;
float last_kp = 0;
float last_ki = 0;
float last_kd = 0;

int PID_values_fixed =0;

//Pins for the SPI with MAX6675
#define MAX6675_CS   10
#define MAX6675_SO   12
#define MAX6675_SCK  13

void setup() {
// Setup Serial Monitor
   Serial.begin (9600);
  
  pinMode(PWM_pin,OUTPUT);
  TCCR2B = TCCR2B & B11111000 | 0x03;    // pin 3 and 11 PWM frequency of 928.5 Hz
  Time = millis();
  
  Last_State = (PINB & B00000001);      //Detect first state of the encoder

  PCICR |= (1 << PCIE0);    //enable PCMSK0 scan                                                 
  PCMSK0 |= (1 << PCINT0);  //Set pin D8 trigger an interrupt on state change. 
  PCMSK0 |= (1 << PCINT1);  //Set pin D9 trigger an interrupt on state change. 
  PCMSK0 |= (1 << PCINT3);  //Set pin D11 trigger an interrupt on state change.   
                           
  pinMode(11,INPUT);
  pinMode(9,INPUT);
  pinMode(8,INPUT);
}

void loop() {
// First we read the real value of temperature
  temperature_read = readThermocouple();
  //Next we calculate the error between the setpoint and the real value
  PID_error = set_temperature - temperature_read + 3;
  //Calculate the P value
  PID_p = 0.01*kp * PID_error;
  //Calculate the I value in a range on +-3
  PID_i = 0.01*PID_i + (ki * PID_error);
  

  //For derivative we need real time to calculate speed change rate
  timePrev = Time;                            // the previous time is stored before the actual time read
  Time = millis();                            // actual time read
  elapsedTime = (Time - timePrev) / 1000; 
  //Now we can calculate the D calue
  PID_d = 0.01*kd*((PID_error - previous_error)/elapsedTime);
  //Final total PID value is the sum of P + I + D
  PID_value = PID_p + PID_i + PID_d;

  //We define PWM range between 0 and 255
  if(PID_value < 0)
  {    PID_value = 0;    }
  if(PID_value > 255)  
  {    PID_value = 255;  }
  //Now we can write the PWM signal to the mosfet on digital pin D3
  //Since we activate the MOSFET with a 0 to the base of the BJT, we write 255-PID value (inverted)
  analogWrite(PWM_pin,255-PID_value);
  previous_error = PID_error;     //Remember to store the previous error for next loop.

  Serial.print("Set temperature: ");
  Serial.println(set_temperature);
  
  Serial.print("Current temperature: ");
  Serial.println(temperature_read);

  Serial.print("Output signal: ");
  Serial.println(255-PID_value);

  delay(1000); //Refresh rate + delay of LCD print
}//Loop end

//The function that reads the SPI data from MAX6675
double readThermocouple() {

  uint16_t v;
  pinMode(MAX6675_CS, OUTPUT);
  pinMode(MAX6675_SO, INPUT);
  pinMode(MAX6675_SCK, OUTPUT);
  
  digitalWrite(MAX6675_CS, LOW);
  delay(1);

  // Read in 16 bits,
  //  15    = 0 always
  //  14..2 = 0.25 degree counts MSB First
  //  2     = 1 if thermocouple is open circuit  
  //  1..0  = uninteresting status
  
  v = shiftIn(MAX6675_SO, MAX6675_SCK, MSBFIRST);
  v <<= 8;
  v |= shiftIn(MAX6675_SO, MAX6675_SCK, MSBFIRST);
  
  digitalWrite(MAX6675_CS, HIGH);
  if (v & 0x4) 
  {    
    // Bit 2 indicates if the thermocouple is disconnected
    return NAN;     
  }

  // The lower three bits (0,1,2) are discarded status bits
  v >>= 3;

  // The remaining bits are the number of 0.25 degree (C) counts
  return v*0.25;
}


//The interruption vector for push button and rotary encoder
ISR(PCINT0_vect)
{
  clk_State =   (PINB & B00000001); //pin 8 state? It is HIGH? 
  dt_State  =   (PINB & B00000010); 
  if (clk_State != Last_State)
  {     
     // If the data state is different to the clock state, that means the encoder is rotating clockwise
     if (dt_State != clk_State) { 
       set_temperature = set_temperature+0.5 ;
     }
     else {
       set_temperature = set_temperature-0.5;
     } 
  }
  Last_State = clk_State; // Updates the previous state of the clock with the current state
}
1 Like

Your code. Your schematic.

And similar massive heat sink?
Paul

Schematic is the same as in the video above.
Code is the same with small differences (no LCD part). Unfortunately because of forum rules I cannot attach file, so take your time scrolling through the code here.
...
(Changed) Code is now in description section

... you should post your code in code tags!

Also is is ludicrous to expect someone to watch a video to see a schematic. Nobody has time to sit through those. Please post it here.

I didn't use heat sink yet. It is none of concern on this stage. Later If I could control voltage properly, I'd provide enough capacity heat sink.

Ok, no problem. Here it is. Not the exact schematics but that's only I have.

I hope you have enough spares on hand to get you through the testing phase.
Paul

What current is passing through those tiny Dupont wires and proto board? Also your photo is not helpful, as wires are covering everything you need to see.

Peltier modules are rather easily destroyed by operating them without a heat sink. The temperature typically should not exceed 80 degrees C anywhere on the device, or the connections melt.

Also, breadboard tracks tend to be destroyed by currents exceeding a few hundred mA.

I did not measure current, only voltage (without TEC module). It was around 12V as expected but no control, it remained the same no matter what signal is written to PIN3.

Right now, unfortunately, I can't do any measurements because my arduino is not working. I think I misdid something earlier and broke bootloader.

Thanks for warning. I'll take this into account. I did not overheat TEC so far, ran only couple of seconds just to ensure temperature is changing.

Please edit your post to add code tags ("</>" editor button).

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.