An MPR121 touch sensor on an Arduino: a touch piano
Beginner
Or see every lesson.
- 455parts on the bench
- 43boards running now
- 1.00xreal time, on every board
The MPR121 turns twelve pieces of metal into touch buttons. Wire each of its electrodes to a pad of foil, copper tape, a screw or even a piece of fruit, and it tells your Arduino which ones a finger is on. It talks I2C, so twelve keys take only two signal wires.
The circuit above is an Uno, an MPR121 and a piezo, as a twelve-key touch piano: one octave of notes from middle C. Hold a key and it plays; hold two and the lowest one wins; let go and it stops. Press Run, then hold the keys on the MPR121.
What you need
- An Arduino Uno
- An MPR121 breakout board
- A passive piezo
- Twelve touch pads: foil, copper tape or wire
- A breadboard and jumper wires
Wiring
| Part and pin | Goes to | Note |
|---|---|---|
| MPR121 VIN | 5 V | The breakout runs on 3 to 5 V |
| MPR121 GND | GND | |
| MPR121 SCL | SCL (A5) | |
| MPR121 SDA | SDA (A4) | Address 0x5A |
| MPR121 0 to 11 | The touch pads | One wire to each key |
| Piezo | Pin 8 | Other leg to GND |
How capacitive touch works
Every electrode, with the pad and wire on it, has a little capacitance: it holds a little charge, like a tiny capacitor. Your body is a big conductor, so a finger on the pad adds to it. The MPR121 measures each electrode many times a second and notices the change.
The chip keeps a baseline for each electrode, its reading with nobody touching. When a reading falls more than the touch threshold below the baseline, the key is touched; when it comes back within the release threshold, it is let go. The Adafruit library sets those thresholds to 12 and 6 counts for every key. All of that happens inside the chip, and the Arduino just reads two bytes: twelve bits, one per key.
The sketch
cap.begin(0x5A) finds the chip and starts it. Then every 10 ms the loop calls cap.touched(), which returns the twelve bits, electrode 0 in bit 0. The sketch looks for the lowest bit that is set, and if that key has changed, it plays its note with tone() or stops with noTone().
The notes are the twelve semitones from middle C, rounded to the hertz: 262 Hz for C4 up to 494 Hz for B4. Hold key 0 and the serial monitor says "key 0: C4, 262 Hz". Hold keys 4 and 9 together and you hear key 4, "E4, 330 Hz". Let go of everything and it says "quiet".
#include <Wire.h>
#include "Adafruit_MPR121.h"
const int PIEZO = 8;
const unsigned int NOTES[12] = {262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494};
const char *NAMES[12] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
Adafruit_MPR121 cap = Adafruit_MPR121();
int playing = -1;
void setup() {
Serial.begin(115200);
if (!cap.begin(0x5A)) {
Serial.println("no MPR121: check SDA, SCL and power");
while (1) delay(10);
}
Serial.println("ready: touch a key");
}
void loop() {
uint16_t touched = cap.touched();
int key = -1;
for (int i = 0; i < 12; i++) {
if (touched & (1 << i)) {
key = i;
break;
}
}
if (key != playing) {
playing = key;
if (key < 0) {
noTone(PIEZO);
Serial.println("quiet");
} else {
tone(PIEZO, NOTES[key]);
Serial.print("key ");
Serial.print(key);
Serial.print(": ");
Serial.print(NAMES[key]);
Serial.print("4, ");
Serial.print(NOTES[key]);
Serial.println(" Hz");
}
}
delay(10);
}Only play when something changes
The sketch remembers which key it is playing and only calls tone() when that changes. Calling tone() again every 10 ms with the same note would restart the sound wave each time, and you would hear a buzz on top of the note. Remembering the state and acting on the change is the same idea as button edge detection.
One piezo can play one note at a time, which is why the lowest key wins. For chords you would need several pins and a little more code, or a sound module.
Real pads, real problems
Keep the wires from the board to the pads short and apart, since a long wire is part of the electrode and can trigger the key when a hand comes near it. Pads about the size of a fingertip or bigger work well.
The chip learns its baselines when it starts. Touch a pad while it powers up and that touch becomes the "untouched" reading, so the key will not respond until it is reset. Keep hands off for the first second.
The simulation leaves out the capacitance itself: an untouched key reads 700 counts and a finger takes 40 off, and the baseline does not drift. On a real build you may need to adjust the thresholds with cap.setThresholds(touch, release) to suit your pads.
Common mistakes
The chip not found. With SDA pulled out, the sketch prints "no MPR121: check SDA, SCL and power" and stops. Check the two bus wires and power.
Another part at 0x5A. The MLX90614 IR thermometer lives there too. Move the MPR121 by wiring its ADDR pin: to 3.3 V for 0x5B, to SDA for 0x5C, to SCL for 0x5D, and pass the new address to begin().
Touching a pad at power-up, so it never reads as touched.
Restarting tone() every loop, giving a buzz instead of a clean note.
Pads too close together, so one finger touches two keys. Leave a gap.
Questions
How many touch inputs does the MPR121 have?
Twelve, numbered 0 to 11. Up to four MPR121 boards can share one I2C bus at addresses 0x5A to 0x5D, for 48 keys.
What library do I use for the MPR121?
The Adafruit MPR121 Library: cap.begin(0x5A), then cap.touched() for a twelve-bit number, one bit per electrode.
Can the MPR121 sense through plastic?
Yes, through a thin layer of plastic, glass or paper over the pad, though the change is smaller. You may need to lower the touch threshold.
Is the MPR121 better than the TTP223?
The TTP223 is one touch key with one digital output, simple and cheap. The MPR121 handles twelve keys on two wires and lets you set the thresholds. For more than a couple of keys, the MPR121 is less wiring.
Keep going
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.