Here I am redesigning the closed loop temperature controller with Arduino that I had I designed and illustrated in Building an Automatic Temperature Controller Using Arduino and a PID Algorithm. While the circuit works, I wanted to make some improvements.
Circuit Diagram/Hardware
Following shows the circuit diagram of the improved version of the closed loop temperature controller with Arduino Uno.
The following shows the previous circuit that was working fine but needed improvements.

In my previous design shown above, I relied on a simple 9V battery to power the Arduino, which was a weak point for long-term use. To solve this, I integrated an LM2595 Buck Converter to pull power directly from the main 12V supply. By stepping this down to 5V, I eliminated the need for a second battery and improved the overall efficiency of the system.
I also upgraded the switching stage. While the IRF540N used previously is powerful, it isn't a "Logic Level" MOSFET and doesn't fully activate at the 5V provided by the Arduino. I swapped it for an IRLZ44N, which is designed specifically for 5V logic. This change ensures the MOSFET conducts fully and stays cool, allowing the bulb to receive maximum power.
To clean up the power delivery, I added a filtering network using 220µF and 120µF capacitors. These smooth out voltage spikes and ripples from the regulator. I also included a 1N5822 Schottky diode—a critical addition because its fast-switching speed and low forward voltage are essential for the high-frequency operation of the buck converter.
Finally, I stabilized the temperature sensing by powering the LM35 directly from the regulated 5V output. In the older version, the sensor shared a rail with a fluctuating battery; now, it has a rock-solid reference voltage for more accurate readings. I also added a gate resistor network (R1 and R2) to ensure the MOSFET gate discharges properly, preventing the load from staying partially active.
Code for the Temperature Controller
Below is the code for the PID-based temperature controller. This will measure the temperature from the LM35 sensor and adjust the power to the heating element to maintain a set temperature (25°C) using a relay.
// Pin Definitions
const int tempSensorPin = A0; // LM35 Temperature Sensor connected to A0
const int heaterPin = 9; // Heater connected to PWM pin 9
// Parameters for optimal control
float Kp = 2.5; // Proportional gain
float Ki = 0.5; // Integral gain
float Kd = 0.1; // Derivative gain
// Variables for control
float setPoint = 30.0; // Desired temperature in °C
float currentTemp = 0.0; // Current temperature reading
float error = 0.0; // Error value
float previousError = 0.0; // Previous error for derivative term
float integral = 0.0; // Integral accumulator
float output = 0.0; // Output PWM value
void setup() {
Serial.begin(9600);
pinMode(heaterPin, OUTPUT);
Serial.println("Automatic Temperature Controller");
}
void loop() {
// Read temperature from LM35 sensor
int sensorValue = analogRead(tempSensorPin);
currentTemp = (sensorValue * 5.0 / 1023.0) * 100.0; // Convert to Celsius
// Calculate error
error = setPoint - currentTemp;
// Calculate integral term
integral += error;
// Calculate derivative term
float derivative = error - previousError;
// Compute control output
output = Kp * error + Ki * integral + Kd * derivative;
// Limit output to PWM range (0-255)
output = constrain(output, 0, 255);
// Apply control to heater
analogWrite(heaterPin, output);
// Update previous error
previousError = error;
// Print for monitoring
Serial.print("Temperature: ");
Serial.print(currentTemp);
Serial.print(" °C, Output: ");
Serial.println(output);
// Delay for stability
delay(1000);
}