ESP32: use the onboard touch pins as buttons
The ESP32 has 10 capacitive touch pins that work without any extra hardware. Wire a piece of foil and you have a button.
The ESP32 has 10 capacitive touch pins (T0 through T9) that work without
any extra hardware. Touch one with your finger (or a piece of foil connected
to it), and the chip detects the capacitance change. No pull-up resistor,
no debouncing, no button to buy.
This is the tutorial I send people when they want a button without a button.
What you need
- ESP32 dev board
- A piece of aluminum foil and a wire, OR a wire that you can touch with your finger
That is it. No resistors. No buttons.
The touch pins
On a 30-pin ESP32 dev board, the touch pins are:
- GPIO 4 (T0)
- GPIO 0 (T2): careful, this is a boot pin
- GPIO 2 (T2): careful, this is a boot pin
- GPIO 15 (T3): careful, this is a boot pin
- GPIO 13 (T4)
- GPIO 12 (T5)
- GPIO 14 (T6)
- GPIO 27 (T7)
- GPIO 33 (T8)
- GPIO 32 (T9)
GPIO 4 and GPIO 13-33 are the safe picks. GPIO 0, 2, and 15 do weird things during reset and will cause confusing boot failures if you tie them to a big piece of metal.
The code
#define TOUCH_PIN T0 // GPIO 4
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Touch the pin!");
}
void loop() {
int value = touchRead(TOUCH_PIN);
Serial.println(value);
delay(100);
}
Upload it. Open Serial Monitor. You should see a baseline value (the “untouched” reading, usually around 60-80). Touch the pin and the number drops (toward 10-20). Move your hand away and it goes back.
Every board is slightly different. The baseline for your board might be 70 or 80. The “touched” threshold depends on the value you see.
A more useful version: print “touched” vs “not touched”
#define TOUCH_PIN T0
int threshold = 30; // adjust based on your baseline
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Touch the pin!");
}
void loop() {
int value = touchRead(TOUCH_PIN);
if (value < threshold) {
Serial.println("Touched!");
while (touchRead(TOUCH_PIN) < threshold) delay(50);
} else {
Serial.println("...");
}
delay(50);
}
The while loop waits for you to remove your finger, so you only get one
“Touched!” per touch.
How to set the threshold
Run the first sketch (the one that just prints the value). Watch the Serial Monitor. Note the highest value when not touched, and the lowest value when touched. Set the threshold in between.
For example:
- Untouched: 70-80
- Touched: 10-25
Threshold of 40-50 works.
If the threshold is too high, you get false positives from noise. If too low, you have to touch really hard to trigger it.
Adding a debounce
Capacitive touch can flicker when your finger is on the edge of detection. Add a debounce:
bool touchState = false;
unsigned long lastChange = 0;
const unsigned long DEBOUNCE_MS = 150;
void loop() {
int value = touchRead(TOUCH_PIN);
bool touched = value < threshold;
if (touched != touchState && millis() - lastChange > DEBOUNCE_MS) {
touchState = touched;
lastChange = millis();
if (touchState) Serial.println("Touched!");
}
}
Putting foil on the touch pin
To make a “hidden” touch button, connect a wire from T0 to a piece of
aluminum foil taped under a non-conductive surface (e.g. under a piece of
tape, under a 3D-printed panel). Touching the surface touches the button.
This is how you make:
- Lamp controls hidden in a wood panel
- Touch interfaces that look like they are doing magic
- Buttons behind glass or plastic
The capacitance of the wire matters. Keep the wire under about 30 cm, and keep it away from other wires or PCB traces, which add parasitic capacitance and can make the touch sensor less sensitive.
What to build next
- A touch-controlled lamp (touch the nightstand, lamp turns on).
- A multi-touch piano with one touch pin per key.
- A touch-controlled volume slider (linear foil strip with multiple touch pins).
The lamp version is a separate tutorial on this site. The multi-touch version is in the book ESP32 Fun Projects.