In many applications, precise temperature control is essential—whether for industrial processes, 3D printing, or even home brewing. One of the best ways to achieve accurate temperature regulation is by using a PID (Proportional-Integral-Derivative) controller. In this guide, we’ll build a DIY PID temperature control system using an Arduino, a K-Type thermocouple with a MAX6675 amplifier, and an LCD 16×2 display to monitor the temperature.
🔹 Components Required
Before we dive into the project, here’s what you’ll need:
- Arduino Board (Uno, Mega, or any compatible board)
- K-Type Thermocouple with MAX6675 Amplifier (for temperature sensing)
- 16×2 LCD Display with I2C Module (for displaying temperature)
- Relay Module (to control the heating element)
- Heating Element (such as a resistor, nichrome wire, or heater)
- Cooling Fan (optional) (for active cooling in both heating/cooling applications)
- Push Buttons or Potentiometer (for manual tuning, if desired)
- Power Supply (as per the heating element requirements)
- Connecting Wires & Breadboard
🔹 Understanding PID Temperature Control
PID stands for:
- Proportional (P): Corrects errors proportionally.
- Integral (I): Reduces steady-state errors.
- Derivative (D): Reacts to rapid changes.
Using the PID library in Arduino, we can fine-tune these parameters to maintain a stable temperature around the setpoint.
🔹 Wiring Diagram
Connections
K-Type Thermocouple with MAX6675 to Arduino
MAX6675 Pin | Arduino Pin |
---|---|
VCC | 5V |
GND | GND |
SCK | D13 |
CS | D10 |
SO | D12 |
16×2 LCD with I2C Module to Arduino
LCD I2C Pin | Arduino Pin |
---|---|
VCC | 5V |
GND | GND |
SDA | A4 |
SCL | A5 |
Relay Module to Arduino
Relay Pin | Arduino Pin |
---|---|
VCC | 5V |
GND | GND |
IN | D9 |
🔹 The heating element is connected to Relay COM (Common) and NO (Normally Open) terminals, while the power source is linked accordingly.
🔹 Arduino Code
We’ll use the PID Library and MAX6675 Library to handle temperature control.
Install Libraries
Before uploading the code, install the following libraries in the Arduino IDE:
- PID Library (
PID_v1.h
) – for PID control. - MAX6675 Library (
max6675.h
) – to read the thermocouple. - LiquidCrystal_I2C – for LCD display control.
Complete Code
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <max6675.h>
#include <PID_v1.h>
// LCD setup
LiquidCrystal_I2C lcd(0x27, 16, 2);
// MAX6675 setup
#define SCK 13
#define CS 10
#define SO 12
MAX6675 thermocouple(SO, SCK, CS);
// PID Variables
double setpoint = 100.0; // Target Temperature
double input, output;
double Kp = 2.0, Ki = 5.0, Kd = 1.0; // Tune these values
// Relay control
int relayPin = 9;
PID myPID(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
lcd.backlight();
pinMode(relayPin, OUTPUT);
digitalWrite(relayPin, LOW);
myPID.SetMode(AUTOMATIC);
}
void loop() {
// Read temperature from the thermocouple
input = thermocouple.readCelsius();
// Compute PID output
myPID.Compute();
// Control relay based on PID output
if (output > 50) {
digitalWrite(relayPin, HIGH);
} else {
digitalWrite(relayPin, LOW);
}
// Display on LCD
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(input);
lcd.print("C ");
lcd.setCursor(0, 1);
lcd.print("Set: ");
lcd.print(setpoint);
lcd.print("C ");
Serial.print("Temperature: ");
Serial.print(input);
Serial.println(" °C");
delay(1000); // Update every second
}
Arduino Code for PID Temperature Control and Display
//LCD config (i2c LCD screen, you need to install the LiquidCrystal_I2C if you don't have it )
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,16,2); //sometimes the adress is not 0x3f. Change to 0x27 if it dosn't work.
/* i2c LCD Module ==> Arduino
* SCL ==> A5
* SDA ==> A4
* Vcc ==> Vcc (5v)
* Gnd ==> Gnd */
#include <SPI.h>
//We define the SPI pìns
#define MAX6675_CS 10
#define MAX6675_SO 12
#define MAX6675_SCK 13
//Pins
int PWM_pin = 3;
//Variables
float temperature_read = 0.0;
float set_temperature = 210;
float PID_error = 0;
float previous_error = 0;
float elapsedTime, Time, timePrev;
int PID_value = 0;
//PID constants
int kp = 9.1; int ki = 0.3; int kd = 1.8;
//int kp = 9.1; int ki = 0; int kd = 0;
int PID_p = 0; int PID_i = 0; int PID_d = 0;
void setup() {
pinMode(PWM_pin,OUTPUT);
TCCR2B = TCCR2B & B11111000 | 0x03; // pin 3 and 11 PWM frequency of 980.39 Hz
Time = millis();
lcd.init();
lcd.backlight();
}
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;
//Calculate the P value
PID_p = kp * PID_error;
//Calculate the I value in a range on +-3
if(-3 < PID_error <3)
{
PID_i = 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 = 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
analogWrite(PWM_pin,255-PID_value);
previous_error = PID_error; //Remember to store the previous error for next loop.
delay(300);
//lcd.clear();
lcd.setCursor(0,0);
lcd.print("PID TEMP control");
lcd.setCursor(0,1);
lcd.print("S:");
lcd.setCursor(2,1);
lcd.print(set_temperature,1);
lcd.setCursor(9,1);
lcd.print("R:");
lcd.setCursor(11,1);
lcd.print(temperature_read,1);
}
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;
}
🔹 How It Works
- The thermocouple measures the temperature.
- The MAX6675 module sends temperature data to the Arduino.
- The PID algorithm processes the data and adjusts the heating element accordingly.
- The relay module controls the heater based on the PID output.
- The LCD display shows the current temperature and the target setpoint.
🔹 Tuning the PID Controller
To achieve stable temperature control, you’ll need to tune the PID parameters (Kp
, Ki
, Kd
). Here’s how:
- Start with Kp (proportional gain). Increase it until the system reacts quickly but doesn’t overshoot too much.
- Gradually adjust Ki to minimize steady-state error.
- If temperature fluctuations occur, fine-tune Kd to reduce oscillations.
📌 Tip: If you are not using LCD for display, use the
Serial Monitor
to observe temperature changes and adjust PID values accordingly.
🔹 Applications of PID Temperature Control
- 3D Printing – Maintain consistent extrusion temperature.
- Reflow Ovens – For precise PCB soldering.
- Incubators – To control temperature for hatching eggs or lab experiments.
- Home Brewing – For fermenting or distilling at exact temperatures.
- Industrial Processing – Ensuring stable thermal conditions in manufacturing.
🔹 Conclusion
In this project, we implemented a PID-based temperature control system using an Arduino, a K-Type thermocouple with MAX6675, and an LCD 16×2 display. This method allows for precise and automated temperature regulation, making it useful for a wide range of applications.
Next Steps: Try integrating buttons or a rotary encoder to adjust the temperature setpoint dynamically!
Have questions or ideas for improvement? Drop them in the comments below! 🚀