▲ Live Dashboard click to collapse
● Live Cap Touch Monitor v2 Chrome / Edge only — reads your board over USB Open Dashboard →
▶ Week 3 · Capacitive Touch

Feel the Touch
No buttons needed.

Your finger is the sensor. Learn to use the ESP32-S3 capacitive touch pins — then build a Touch-Pad controller.

author  Yury Gitman | course  PSAM 5320 | date  March 14, 2026 | version  1.0

What is Capacitive Touch?

๐Ÿ‘†

Your body is a conductor

Your skin carries a tiny electrical charge. When you touch a wire connected to a GPIO pin, you change the electrical field around it.

๐Ÿ“

The chip measures change

The ESP32-S3 reads a number. When nothing touches the wire: low number (~22,000). When you touch: high number (~100,000+).

๐ŸŽš๏ธ

You set the threshold

You decide: "above 50,000 = touched." Every setup is different. Use the live dashboard below to find YOUR numbers.

๐Ÿ’ก Key difference from regular ESP32

On ESP32-S3 (our board): higher number = touched. On older ESP32: lower number = touched. Old tutorials may have it backwards!

What the numbers look like

~22,000
Not touching
Baseline ยท varies by board
~100,000+
Finger touching
Spikes up when touched
โ†‘ idle  ยท  set threshold somewhere in between  ยท  touched โ†‘
โš ๏ธ Your numbers will be different

Baseline values depend on your specific board, wire length, humidity, desk surface, and nearby electronics. Always measure YOUR values first using the dashboard. Do not hardcode 80,000 without checking.

Pin Map & Wiring

The XIAO ESP32-S3 has 13 touch-capable pins (pink labels in the diagram). We use 2 for this test, and 4 for the Touch-Pad project.

XIAO ESP32-S3 Pinout Diagram
TOUCH โ€” pink = touch pin GPIO โ€” blue = digital ANALOG โ€” orange = analog POWER โ€” red = 3.3V / 5V GND โ€” black = ground

2-Key Test Wiring (this experiment)

A1 / GPIO2
โ†’
KEY 1 โ€” connect a jumper wire. Touch the wire end or insulation.
Also labeled TOUCH2 on the pinout diagram
A3 / GPIO4
โ†’
KEY 2 โ€” connect a jumper wire. Touch the wire end or insulation.
Also labeled TOUCH4 on the pinout diagram
A0 / A2
โ†’
GND GUARDS โ€” optional. Connect to GND. These reduce interference between keys.
No code needed for these โ€” just wire them to GND physically
USB-C
โ†’
Connect to your computer. Powers the board and sends serial data.
โ„น๏ธ The wire IS the sensor

You do not need any extra components. Just a jumper wire plugged into the pin. The wire itself acts as the touch electrode. Longer wire = more sensitive. Larger surface area at the end = more sensitive.

Touch pin reference table

XIAO Label GPIO Number Arduino name Touch-Pad use Available?
D0 / A0GPIO1touchRead(1)LEFTโœ“ touch
D1 / A1GPIO2touchRead(2)UP / KEY 1โœ“ touch
D2 / A2GPIO3touchRead(3)DOWNโœ“ touch
D3 / A3GPIO4touchRead(4)RIGHT / KEY 2โœ“ touch
D4 / A4GPIO5โ€”โ€”SDA (I2C)
D5 / A5GPIO6โ€”โ€”SCL (I2C)

Electrode types โ€” what works best?

๐Ÿ“Œ

Bare pin tip

Very small area. Works only when directly touched.

sensitivity: low
๐Ÿ”Œ

Insulated wire

Plastic sleeve increases area + adds dielectric. Better signal.

sensitivity: medium
๐Ÿฅข

Foil / copper tape pad

Large flat surface. Works even with hovering nearby.

sensitivity: high
๐Ÿงต

Conductive fabric

Soft, wearable. Good for toy skins and soft buttons.

sensitivity: high

Arduino Sketch โ€” 2-Key Test

This sketch reads two touch pins and sends the values over USB to your computer. You will use the Live Dashboard (next section) to see the values in real time.

  1. 1

    Open Arduino IDE

    Make sure you have the esp32 by Espressif board package installed. Board: XIAO_ESP32S3. Port: the USB port your board is on.

  2. 2

    Copy the code below

    Click the copy button on the code block. Paste into a new Arduino sketch.

  3. 3

    Upload to your board

    Click the Upload arrow (โ†’). Wait for "Done uploading." The board resets automatically.

  4. 4

    Open the Live Dashboard below

    Do NOT open Arduino Serial Monitor โ€” that will block the dashboard. Go directly to the Dashboard section on this page.

cap_touch_2key_test.ino
// XIAO ESP32-S3 โ€” Cap Touch 2-Key Test
// KEY 1: A1 pin (GPIO2 / TOUCH2)
// KEY 2: A3 pin (GPIO4 / TOUCH4)
// Optional GND guards: A0, A2 wired to GND (no code needed)

void setup() {
  Serial.begin(115200);
  Serial.println("KEY1,KEY2");  // CSV header for dashboard
}

void loop() {
  int key1 = touchRead(A1);  // GPIO2 / TOUCH2
  int key2 = touchRead(A3);  // GPIO4 / TOUCH4

  // Send as CSV โ€” dashboard reads this format
  Serial.print(key1);
  Serial.print(",");
  Serial.println(key2);

  delay(50);  // 20 readings per second
}
โœ… What the serial output looks like

You will see lines like: 22813,23377 โ€” two numbers separated by a comma. First is KEY 1, second is KEY 2. Numbers jump up when you touch.

Read Your Touch Values

This tool runs directly in Chrome. It reads the serial data from your board and shows live graphs, values, and helps you find the right threshold for your setup.

  1. 1

    Make sure your board is plugged in

    USB-C cable connected. Sketch already uploaded (see Code section above).

  2. 2

    Click "Connect Serial" below

    A popup will appear. Select the port that says usbmodem (Mac) or COM (Windows). Click Connect.

  3. 3

    Click "Auto-calibrate baseline (3s)"

    Keep your hands away from the wires for 3 seconds. This sets the resting value for your specific board.

  4. 4

    Touch KEY 1 and KEY 2 a few times

    Watch the values spike. The "suggested thresh" in the Stats section will calculate the best threshold for you automatically.

  5. 5

    Use Macro + Micro sliders to set threshold

    Macro = big moves (step 5,000). Micro = fine tuning (step 100). Each key can have its own threshold โ€” use the Per-Key section if KEY 1 and KEY 2 behave differently.

โš ๏ธ Chrome / Edge only

WebSerial does not work in Safari or Firefox. Use Google Chrome or Microsoft Edge for the dashboard to work.

Live Dashboard
Cap Touch Monitor v2
Opens in a new tab — use Chrome or Edge. Reads your board over USB via WebSerial.
Open Dashboard →

When Things Don't Work

Problem Fix Why
Dashboard shows no data Close Arduino Serial Monitor. It blocks the port. Reconnect in dashboard. Only one program can use the serial port at a time.
Connect Serial button does nothing Switch to Chrome or Edge browser. Safari does not support WebSerial. WebSerial API is only in Chromium-based browsers.
Touch does not register (stays idle) Lower the threshold with the Macro slider. Try 30,000 first. Or use a larger electrode (foil pad, more wire). Your baseline may be lower than expected, or your electrode has low sensitivity.
Triggers without touching (false touch) Raise the threshold. Also check if any wire is touching a metal surface or another wire. Noise or cross-talk between pins causes false readings.
KEY 1 and KEY 2 have very different sensitivities Use the Per-Key Threshold section. Set different thresholds for each key. Different wire lengths, bends, or electrode sizes change each pin's baseline independently.
Values jump around a lot (noisy) Move away from power supplies, phone chargers, and fluorescent lights. Try on a wooden surface instead of metal desk. Electromagnetic interference couples into the unshielded wires.
Insulated wire more sensitive than bare pin tip This is normal! The plastic sleeve increases contact area and acts as a dielectric layer. This is good โ€” it means more of your finger touches the sensor area. Capacitance = area ร— material factor รท distance. More area + dielectric = more signal.
Works on desk but not in finished project Re-run auto-calibrate in the final assembly. The enclosure material, metal parts, and power supply all affect the baseline. Always calibrate in the final context. Capacitive touch is affected by everything nearby. Lab results โ‰  field results.
๐Ÿ“Š Data collection tip

Before drawing conclusions about your setup, test with at least 3 different electrode types (bare pin, insulated wire, foil pad) in the same conditions. One observation on a desk with loose wires is not enough data to know what is happening.

Common questions

Why does it work through plastic and tape? +
Capacitance works through insulators. Your phone screen has glass on top of the sensors. You can put tape or thin plastic over your touch wire โ€” it often works better because the plastic adds surface area for your finger to contact.
Does humidity affect the readings? +
Yes. Humid air conducts slightly. Your threshold values may need adjustment on rainy days vs dry winter days. This is also why you should always auto-calibrate at the start of a session, not rely on yesterday's numbers.
Can I use the I2C pins (GPIO5, GPIO6) for touch? +
Technically yes โ€” they are touch-capable. But we use GPIO5 and GPIO6 for the OLED display (SDA and SCL). If you try to use them for touch at the same time as the OLED, things will break. Stick to GPIO1โ€“4 for touch when using the OLED.
Why does removing the GND guard wires seem to change nothing? +
This is an open question that needs more testing. Early observations suggest the guards may not have a big effect in this particular configuration on a desk. But we need more data โ€” different setups, different environments, and tests inside an actual enclosure โ€” before we can say anything definitive. Keep testing and note your conditions carefully.
How do I make a bigger touch area? +
Connect the pin to a larger conductor: copper tape, aluminum foil, or conductive fabric. Larger area means more capacitance change when your finger approaches, which means higher signal delta and easier detection. This is how commercial capacitive buttons work โ€” the visible copper pad on a PCB is the electrode, not just the pin.

Touch-Pad Controller with OLED

Once you understand the 2-key test, you are ready to build the full Touch-Pad. This uses 4 touch pins to make a directional controller that shows arrows on the OLED display.

๐Ÿ“š Required library

Go to: Sketch โ†’ Include Library โ†’ Manage Libraries โ†’ Search Adafruit SH110X โ†’ Install. Also install Adafruit GFX Library when prompted.

Touch-Pad pin mapping

XIAO LabelGPIODirectionWire Color (suggestion)
D0GPIO1LEFT โ†Red
D1GPIO2UP โ†‘Green
D2GPIO3DOWN โ†“Blue
D3GPIO4RIGHT โ†’Yellow
CapTouchDPad_V2.ino
/*
 * CapTouchDPad_V2.ino โ€” Touch-Pad Visualizer
 * XIAO ESP32-S3 + SH1106G OLED
 *
 * Wiring:
 *   D0 (GPIO 1) โ†’ LEFT wire
 *   D1 (GPIO 2) โ†’ UP wire
 *   D2 (GPIO 3) โ†’ DOWN wire
 *   D3 (GPIO 4) โ†’ RIGHT wire
 *   OLED: SDA=GPIO5, SCL=GPIO6 (I2C default)
 */
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#include <Wire.h>

Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire, -1);

// Touch Pins
const int PIN_LEFT  = 1;  // D0
const int PIN_UP    = 2;  // D1
const int PIN_DOWN  = 3;  // D2
const int PIN_RIGHT = 4;  // D3

// Threshold โ€” adjust after calibration!
const int THRESHOLD = 80000;

int vL, vU, vD, vR;

void setup() {
  Serial.begin(115200);
  Wire.begin(5, 6);
  Wire.setClock(400000);
  display.begin(0x3C, true);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SH110X_WHITE);
  display.setCursor(0, 0);
  display.println("Touch-Pad Ready!");
  display.display();
  delay(500);
}

void drawArrow(int x, int y, int dir, bool active) {
  if (active) display.fillCircle(x, y, 10, SH110X_WHITE);
  else        display.drawCircle(x, y, 10, SH110X_WHITE);
  int c = active ? SH110X_BLACK : SH110X_WHITE;
  if (dir == 0) { // Left
    display.drawLine(x+4,y, x-4,y, c);
    display.drawLine(x-4,y, x,y-4, c);
    display.drawLine(x-4,y, x,y+4, c);
  } else if (dir == 1) { // Up
    display.drawLine(x,y+4, x,y-4, c);
    display.drawLine(x,y-4, x-4,y, c);
    display.drawLine(x,y-4, x+4,y, c);
  } else if (dir == 2) { // Down
    display.drawLine(x,y-4, x,y+4, c);
    display.drawLine(x,y+4, x-4,y, c);
    display.drawLine(x,y+4, x+4,y, c);
  } else { // Right
    display.drawLine(x-4,y, x+4,y, c);
    display.drawLine(x+4,y, x,y-4, c);
    display.drawLine(x+4,y, x,y+4, c);
  }
}

void loop() {
  vL = touchRead(PIN_LEFT);
  vU = touchRead(PIN_UP);
  vD = touchRead(PIN_DOWN);
  vR = touchRead(PIN_RIGHT);

  bool tL = vL > THRESHOLD;
  bool tU = vU > THRESHOLD;
  bool tD = vD > THRESHOLD;
  bool tR = vR > THRESHOLD;

  display.clearDisplay();
  int cx=64, cy=32, sp=22;
  drawArrow(cx-sp, cy,    0, tL);
  drawArrow(cx,    cy-sp, 1, tU);
  drawArrow(cx,    cy+sp, 2, tD);
  drawArrow(cx+sp, cy,    3, tR);

  // Raw values in corners for calibration
  display.setCursor(0,0);   display.print(vL);
  display.setCursor(50,0); display.print(vU);
  display.setCursor(0,56); display.print(vD);
  display.setCursor(50,56);display.print(vR);
  display.display();

  delay(16);  // ~60fps
}
โš ๏ธ Change THRESHOLD after calibration

The code uses THRESHOLD = 80000 as a starting point. Use the 2-key test + dashboard first to find YOUR board's actual values, then update this number in the Touch-Pad code.

๐Ÿ”— Full project page

The original Touch-Pad project page with additional exercises and build prompts is at: b.parsons.edu/~gitmany/courses/week3/project1-captouch-dpad.html

PSAM 5320 Making Wireless Toys  ยท  Yury Gitman  ยท  Parsons School of Design  ยท  Spring 2026  ยท  March 14, 2026