Heating elements -- including nichrome wire, Peltier modules, heating pads, and cartridge heaters -- convert electrical energy into heat. They appear in projects like egg incubators, 3D printer heated beds, fermentation controllers, and reflow ovens. You cannot drive a heating element directly from an ESP32 GPIO pin. The GPIO can only supply about $12\,\text{mA}$ at $3.3\,\text{V}$, while heating elements typically need several amps at $12\,\text{V}$ or more. Instead, you use a MOSFET or relay as a switch that the ESP32 controls.
In this guide, you will learn how to safely switch a heating element on and off using an N-channel MOSFET, and how to regulate temperature using PWM and a temperature sensor for feedback.
This guide uses the ESP32-WROOM-32 DevKit. Pin labels and GPIO numbers may differ on your board -- always check your board's pinout diagram.
SAFETY WARNING: Heating elements can cause burns and fires. Always use a power supply rated for your element. Never leave a heating element running unattended during development. Implement a thermal cutoff (hardware fuse or thermal switch) as a failsafe in any real application. Test in a fire-safe environment.
MOSFET or relay? This guide focuses on MOSFET-based PWM control for DC heating elements. For a detailed comparison of when to use a MOSFET vs. a relay (including AC loads), see our relay vs. MOSFET guide.
🔗Key Concepts
| Topic | Description |
|---|---|
| Switching method | MOSFET (for DC loads with PWM) or relay (for on/off) |
| MOSFET choice | Logic-level N-channel (e.g., IRLZ44N, IRL540N) |
| Why "logic-level"? | Standard MOSFETs need $10\,\text{V}$ on the gate. Logic-level MOSFETs fully turn on at $3.3$ to $5\,\text{V}$, matching the ESP32's GPIO output. |
| Flyback diode | Required for inductive loads; protects the MOSFET from voltage spikes |
| Thermal cutoff | A hardware safety device that cuts power if temperature exceeds a safe limit |
🔗MOSFET Specs (IRLZ44N)
| Parameter | Value |
|---|---|
| Type | N-channel, logic level |
| Gate threshold voltage | $1.0$ to $2.0\,\text{V}$ |
| Drain-source voltage | $55\,\text{V}$ max |
| Continuous drain current | $47\,\text{A}$ max |
| On-resistance ($R_{DS(on)}$) | $0.022\,\Omega$ at $V_{GS} = 5\,\text{V}$ |
Note: The IRLZ44N works well with the ESP32's $3.3\,\text{V}$ GPIO. Some other "logic-level" MOSFETs have a gate threshold up to $2.5\,\text{V}$, which leaves very little margin at $3.3\,\text{V}$. Check the datasheet and ensure $R_{DS(on)}$ is specified at $V_{GS} = 2.5\,\text{V}$ or lower.
🔗What You'll Need
| Component | Qty | Notes | Buy |
|---|---|---|---|
| ESP32 dev board | 1 | AliExpress | Amazon.de .co.uk .com | |
| Heating element | 1 | AliExpress | Amazon.de .co.uk .com | |
| MOSFET (IRLZ44N or similar) | 1 | AliExpress | Amazon.de .co.uk .com | |
| 100 ohm resistor | 1 | Gate resistor | AliExpress | Amazon.de .co.uk .com |
| 10k ohm resistor | 1 | Pull-down resistor | AliExpress | Amazon.de .co.uk .com |
| 5V power supply | 1 | Or 12V, rated for your element | Amazon.de .co.uk .com |
| Breadboard | 1 | AliExpress | Amazon.de .co.uk .com | |
| Jumper wires | 6 | AliExpress | Amazon.de .co.uk .com |
Links marked Amazon/AliExpress are affiliate links. We may earn a small commission at no extra cost to you.
🔗Wiring (MOSFET Method)
This configuration uses a low-side switch -- the MOSFET sits between the heating element and ground.
| Connection | Details |
|---|---|
| MOSFET Gate (G) | GPIO 25 through $100\,\Omega$ resistor |
| MOSFET Source (S) | GND (shared with ESP32) |
| MOSFET Drain (D) | Heating element negative terminal |
| Heating element positive terminal | External power supply positive (+) |
| External power supply GND | ESP32 GND (shared ground) |
Additionally:
- Add a $10\,\text{k}\Omega$ pull-down resistor between the gate and source (GND). This ensures the MOSFET stays off when the ESP32 is booting or resetting (when GPIO pins may float).
- If your heating element is inductive (coiled nichrome wire, Peltier module), add a flyback diode (such as 1N5819 Schottky diode) across the element with the cathode toward the positive terminal.
Why a gate resistor? The $100\,\Omega$ resistor on the gate limits the inrush current when charging the MOSFET's gate capacitance. It also dampens high-frequency oscillations. It is not strictly required for a simple circuit, but it is good practice.
🔗Power Calculation
The power dissipated by a resistive heating element follows:
$$P = \frac{V^2}{R}$$
For example, a $10\,\Omega$ nichrome wire element on a $12\,\text{V}$ supply:
$$P = \frac{12^2}{10} = 14.4\,\text{W}$$
The current draw:
$$I = \frac{V}{R} = \frac{12}{10} = 1.2\,\text{A}$$
Make sure your power supply can handle this current, and that the MOSFET is rated well above it.
🔗Code Example: Simple On/Off Control
This sketch turns the heating element on and off at fixed intervals. Useful for testing.
#define HEATER_PIN 25
void setup() {
Serial.begin(115200);
pinMode(HEATER_PIN, OUTPUT);
digitalWrite(HEATER_PIN, LOW); // Start with heater off
Serial.println("Heater control ready.");
}
void loop() {
Serial.println("Heater ON");
digitalWrite(HEATER_PIN, HIGH);
delay(5000); // On for 5 seconds
Serial.println("Heater OFF");
digitalWrite(HEATER_PIN, LOW);
delay(5000); // Off for 5 seconds
}🔗Code Example: PWM Temperature Regulation
For finer control, use PWM to modulate the heating power. Combined with a temperature sensor, you can maintain a target temperature. This example implements a simple proportional control loop.
#include <OneWire.h>
#include <DallasTemperature.h>
#define HEATER_PIN 25
#define TEMP_SENSOR_PIN 4
#define TARGET_TEMP 37.0 // Target temperature in degrees C
#define TOLERANCE 0.5 // Acceptable range around target
OneWire oneWire(TEMP_SENSOR_PIN);
DallasTemperature sensors(&oneWire);
void setup() {
Serial.begin(115200);
// Set up heater PWM (low frequency is fine for heating elements)
ledcAttach(HEATER_PIN, 1000, 8); // 1 kHz, 8-bit resolution
sensors.begin();
Serial.println("Temperature control system ready.");
Serial.print("Target: ");
Serial.print(TARGET_TEMP);
Serial.println(" C");
}
void loop() {
sensors.requestTemperatures();
float currentTemp = sensors.getTempCByIndex(0);
if (currentTemp == DEVICE_DISCONNECTED_C) {
Serial.println("ERROR: Temperature sensor disconnected! Shutting off heater.");
ledcWrite(HEATER_PIN, 0);
delay(1000);
return;
}
// Simple proportional control
float error = TARGET_TEMP - currentTemp;
int pwmValue = 0;
if (error > TOLERANCE) {
// Below target: scale PWM proportionally
// Clamp to 0-255 range
pwmValue = constrain((int)(error * 50), 0, 255);
} else if (error < -TOLERANCE) {
// Above target: heater off
pwmValue = 0;
} else {
// Within tolerance: low maintenance power
pwmValue = 30;
}
ledcWrite(HEATER_PIN, pwmValue);
Serial.print("Temp: ");
Serial.print(currentTemp, 1);
Serial.print(" C | Target: ");
Serial.print(TARGET_TEMP, 1);
Serial.print(" C | PWM: ");
Serial.print(pwmValue);
Serial.print("/255 (");
Serial.print((pwmValue / 255.0) * 100, 0);
Serial.println("%)");
delay(1000);
}Important: This is a simplified proportional controller for learning purposes. A real temperature control system should implement PID control (Proportional-Integral-Derivative) for stable, accurate temperature regulation without overshooting. The Arduino PID library makes this straightforward.
🔗How It Works
🔗MOSFET as a Switch
A MOSFET (Metal-Oxide-Semiconductor Field-Effect Transistor) acts as a voltage-controlled switch. When you apply a voltage to the gate that exceeds the threshold voltage, the MOSFET creates a low-resistance path between drain and source, allowing current to flow through the heating element.
The beauty of a MOSFET is that the gate draws virtually no current -- the ESP32 only needs to provide a voltage, not a significant current. This is unlike a bipolar transistor (BJT), which requires continuous base current.
🔗PWM for Temperature Control
Instead of simply switching the heater fully on or fully off, PWM lets you control the average power delivered to the element:
$$P_{avg} = P_{max} \times \frac{\text{dutyCycle}}{255}$$
At a duty cycle of 128 (50%), the heater receives half its maximum power on average. Because heating elements have thermal mass (they heat and cool slowly), they smooth out the rapid switching naturally. A PWM frequency of $1\,\text{kHz}$ or even lower is perfectly adequate for thermal control.
🔗Why a Temperature Feedback Loop?
Without feedback, you cannot know the actual temperature. The heater might overshoot your target (risking damage or fire) or undershoot (not reaching the desired temperature). By reading a temperature sensor on every loop iteration and adjusting the PWM accordingly, the system self-corrects.
🔗Alternative: Relay Method
For simple on/off heating control (no PWM), you can use a relay module instead of a MOSFET. This is appropriate when:
- You do not need fine-grained temperature control (a few degrees of oscillation is acceptable)
- You are switching AC-powered heaters
- You want full electrical isolation
Use the relay to switch the heater on when temperature drops below the threshold and off when it rises above. This is called bang-bang control (or hysteresis control).
🔗Troubleshooting
| Problem | Possible Cause | Solution |
|---|---|---|
| Heater does not turn on | MOSFET not fully on at $3.3\,\text{V}$ | Verify you are using a logic-level MOSFET (IRLZ44N, not IRF540N) |
| Heater stays on even when GPIO is LOW | No pull-down resistor on MOSFET gate | Add a $10\,\text{k}\Omega$ resistor from gate to GND |
| MOSFET gets very hot | On-resistance too high or current too high | Use a MOSFET rated for your current; add a heatsink |
| Temperature overshoots badly | Control loop too aggressive | Reduce the proportional gain; implement PID control |
| Temperature sensor reads wrong | Sensor too far from heating element | Place the sensor close to (but not touching) the element |
| ESP32 resets when heater turns on | Power supply noise or shared power | Use separate supplies for ESP32 and heater; add decoupling capacitors |
| Heater runs at startup | GPIO floats during boot | Add the $10\,\text{k}\Omega$ gate pull-down resistor |
🔗Safety Checklist
Before running any heating project, verify the following:
- Power supply is rated for the heating element's current draw
- MOSFET (or relay) is rated above the element's current and voltage
- A hardware thermal cutoff or thermal fuse is installed as a failsafe
- The heating element is mounted on a heat-resistant, non-flammable surface
- The code includes a sensor-disconnected check that shuts off the heater immediately
- You have tested the shutdown behavior (what happens if the ESP32 crashes or resets?)
🔗Next Steps
- Implement a full PID controller for precise temperature regulation
- Log temperature data to an OLED display or send it over WiFi
- Build an egg incubator, fermentation chamber, or filament dryer
- Add over-temperature alerts using a buzzer