Raspberry Pi Pico
MPR121 Touch Sensor

The MPR121 is an integrated circuit that does capacitive touch sensing. The one I am using is an Adafruit board. It costs just over £7 now to buy the latest version and there is a cheaper version that you can use with crocodile clips. You connect to it using I2C.

I used some Play Doh to make my buttons.

Pico Circuit

Here is a Fritzing diagram using the latest Adafruit board. The unconnected wires on the right of the diagram are what you connect to your electrodes (buttons). You can use anything conductive and experiment with different objects to see how well they work. Play Doh works a treat for touch sensing.

Pico Circuit

Here is the library I wrote to interact with the MPR121 board. Save it to the Pico as mpr121.py.

from micropython import const
from time import sleep_ms

ADDRESS = const(0x5a)

class MPR121:    
    def __init__(self, i2c):
        self.i2c = i2c
        self.reset()
    
    def cmd(self, reg, value):
        self.i2c.writeto_mem(ADDRESS,reg,bytes([value]))
        
    def reset(self):
        self.cmd(0x80, 0x63)
        sleep_ms(1)
        self.cmd(0x5e, 0)
        self.set_thresholds(12,6)
        rst = [0x01,0x01,0x0e,0,0x01,0x05,0x01,0,0,0,0]
        for i in range(43, 54):
            self.cmd(i, rst[i-43])
        self.cmd(0x5b, 0)
        self.cmd(0x5c, 0x10)
        self.cmd(0x5d, 0x20)
        self.cmd(0x5e, 0x8f)
    
    def touched(self):
        self.cmd(0,0)
        lower = self.i2c.readfrom(ADDRESS, 2)
        return lower[0] + (lower[1]<<8)
                
    def set_thresholds(self, touch, release):
        for i in range(12):
            self.cmd(0x41 + 2*i, touch)
            self.cmd(0x42 + 2*i, release)

I tested my connections and code with a simple program, reading values in the shell.

from machine import Pin, I2C
from time import sleep
from mpr121 import MPR121


i2c=I2C(0,sda=Pin(16), scl=Pin(17))
cap = MPR121(i2c)

while True:
    a =cap.touched()
    print('{:012b}'.format(a))
    sleep(0.02) 

Finally, I connected a buzzer to GP15 and made a piano (of sorts).

from machine import Pin, I2C, PWM
from time import sleep
from mpr121 import MPR121

# define the pin to use for buzzing
buzzer = PWM(Pin(15))
# the duty cycle to use when the note is on
volume = 2512

# frequency - plays until stopped
def note_on(frequency):
    buzzer.duty_u16(volume)
    buzzer.freq(frequency)

# stop the noise
def note_off():
    buzzer.duty_u16(0)

def bit_length(n):
    bits = 0
    while n >> bits: bits += 1
    return bits

i2c=I2C(0,sda=Pin(16), scl=Pin(17))
cap = MPR121(i2c)

notes = [262,294,330,349,392,440,494,523,587,659,698,784]

last = -2
while True:
    x = cap.touched()
    # play note from leftmost press only
    leftmost = bit_length(x&-x) - 1
    if leftmost != last:
        if leftmost==-1:
            note_off()            
        else:
            note_on(notes[leftmost])
    last = leftmost