ESP32 Bench
Boards: ESP32, S3, C3
Flash and monitor: Web Serial
← All projects

Touch piano

Turn four bare wires into touch keys. Each touch prints a note, and an optional buzzer plays it.

Starter10 min115200 baud
Board
Fig. 1. Pins this project uses on the ESP32-DevKitC V4, 38 pin. USB connector at the bottom.

Wiring

FromTo boardNote
Key 1GPIO 4Any conductive pad. Bare wire is enough
Key 2GPIO 13
Key 3GPIO 14
Key 4GPIO 27
Buzzer +GPIO 25Optional. A passive buzzer, not an active one
Buzzer -GND

Tested on this board

Not run on this board yet. Treat the wiring and code as a first draft.

Firmware, Arduino sketch for ESP32 Dev Module

// Four touch keys. Touch pins sense a finger through the wire, no parts needed.
const int KEYS[] = {4, 13, 14, 27};
const char* NOTES[] = {"C4", "E4", "G4", "C5"};
const int FREQ[] = {262, 330, 392, 523};
const int BUZZER = 25;  // optional passive buzzer

uint32_t baseline[4];
bool down[4];
int playing = -1;

bool touched(int i, uint32_t v) {
#if CONFIG_IDF_TARGET_ESP32
  return v < baseline[i] * 7 / 10;   // classic ESP32: the reading drops when touched
#else
  return v > baseline[i] * 13 / 10;  // ESP32-S3: the reading rises when touched
#endif
}

void setup() {
  Serial.begin(115200);
  delay(500);
  // Average a few readings with nobody touching the keys.
  for (int i = 0; i < 4; i++) {
    uint32_t sum = 0;
    for (int k = 0; k < 16; k++) {
      sum += touchRead(KEYS[i]);
      delay(5);
    }
    baseline[i] = sum / 16;
    Serial.printf("key %d on GPIO %d: baseline %lu\n", i + 1, KEYS[i], (unsigned long)baseline[i]);
  }
  Serial.println("Touch a key");
}

void loop() {
  int now = -1;
  for (int i = 0; i < 4; i++) {
    uint32_t v = touchRead(KEYS[i]);
    bool on = touched(i, v);
    if (on && !down[i]) Serial.printf("key %d down  %s  (reading %lu)\n", i + 1, NOTES[i], (unsigned long)v);
    if (!on && down[i]) Serial.printf("key %d up\n", i + 1);
    down[i] = on;
    if (on && now < 0) now = i;
  }
  if (now != playing) {
    if (now >= 0) tone(BUZZER, FREQ[now]);
    else noTone(BUZZER);
    playing = now;
  }
  delay(20);
}

Parts

QuantityPartWhere to buy
1×ESP32 or ESP32-S3 dev boardBuy at Amazon
4×Jumper wires, or foil, coins or fruit as keys
1×Optional passive buzzer

Amazon buy links may include an Associates tag, and this site may earn a commission from qualifying Amazon purchases at no extra cost to you. Adafruit links are direct.

Libraries

None beyond the ESP32 Arduino core.

Load it

  1. In the Arduino IDE, install the esp32 board package and pick the board named above the sketch.
  2. Paste the sketch, choose the board's port and upload. Hold BOOT if the upload stalls at Connecting.
  3. Close the IDE's serial monitor, then open the bench here to watch the output.

Field notes

  • The ESP32-C3 has no touch sensor, so this project is for the classic ESP32 and the S3 only.
  • Readings go the opposite way on the two chips: on the classic ESP32 they fall when touched, on the S3 they rise. The sketch handles both.
  • Keep your hands off the keys while the board starts. The first half second sets the untouched baseline.
  • Readings shift with humidity, wire length and whether the board is on USB or a battery. If keys trigger by themselves, press EN to take a new baseline.

Not tested yet

  • Not tested on hardware yet. Compiles for every board listed with Arduino-ESP32 core 3.3.12.