Overview

Reach out and touch somebody or some thing with capacitive touch sensing and the MPR121 capacitive touch breakout board.  Capacitive touch sensing means detecting when something conductive is touched by a large object or person.  For example detecting when a person touches a piece of foil, conductive ink, or even a piece of fruit or a vegetable.  It almost seems like magic but capacitive touch sensing is based on a very simple principle--by touching an object your body slightly changes the capacitance of it and that change can be detected with special circuitry.

The MPR121 board is a dedicated capacitive touch sensing chip that can check up to 12 inputs independently for touches.  Since the MPR121 uses a simple I2C interface you can use it with almost any development board like an Arduino, MicroPython or CircuitPython board.  This guide shows how to use the MPR121 capacitive touch sensing breakout with a CircuitPython board.

Before you follow this guide it will help to familiarize yourself with the following other guides:

Continue on to learn about the hardware needed to follow this guide.

Hardware

Parts

You'll need the following hardware to follow this guide:

Start by following the MPR121 breakout guide to assemble and test the board.  Then continue on below to learn how to wire it to a Feather for use with CircuitPython.

For the MPR121 Arduino shield just solder headers to the shield (don't forget to solder the 2x3 SPI header in the center of the board too) and connect it to a compatible Arduino (like the Arduino Zero flashed with CircuitPython firmware).

Wiring

Connect the MPR121 to your board using its I2C interface as follows:

  • MPR121 VIN to board 3V (or 5V) output - red wire.
  • MPR121 GND to board GND/ground - black wire.
  • MPR121 SCL to board SCL (I2C clock) - orange wire.
  • MPR121 SDA to board SDA (I2C data) - yellow wire.

Continue on to learn how to install a CircuitPython module to control the MPR121 board.

Software

Adafruit CircuitPython Module Install

To use the MPR121 with your Adafruit CircuitPython board you'll need to install the Adafruit_CircuitPython_MPR121 module on your board. Remember this module is for Adafruit CircuitPython firmware and not MicroPython.org firmware!

First make sure you are running the latest version of Adafruit CircuitPython for your board.

Next download the latest adafruit_mpr121.zip file from the releases page of the Adafruit_CircuitPython_MPR121 GitHub repository. You'll need to unzip this file and copy the entire adafruit_mpr121 directory to the board's root filesystem.

If your board supports USB mass storage, like the SAMD21 CircuitPython port, then simply drag the files to the board's file system. Note on boards without external SPI flash, like a Feather M0 or Trinket/Gemma M0, you might run into issues on Mac OSX with hidden files taking up too much space when drag and drop copying, see this page for a workaround.

If your board doesn't support USB mass storage, like the ESP8266, then use a tool like ampy to copy the file to the board. You can use the latest version of ampy and its new directory copy command to easily move module directories to the board.

In addition you'll need the Adafruit CircuitPython Bus Device module installed on your board. Just like installing the MPR121 module as mentioned above, download the latest release .zip file and copy the folder inside it to the board's root filesystem.

Before continuing make sure your board's root filesystem has the adafruit_mpr121, and adafruit_bus_device folders/modules copied over as shown below:

Example

To learn how to use the MPR121 module code you can look at the simpletest.py example included in the library.

To run the example open a terminal and navigate to the location where the file was downloaded. Using a tool like ampy you can run the example on your CircuitPython board with a command like:

ampy --port /path/to/board run -n simpletest.py

Change /path/to/board to the path or name of the serial port for your board.  

Notice the -n parameter to the run command, this will tell ampy to start the simpletest.py script but not wait for any output.  It's important to specify this -n option because simpletest.py has a main loop that will never return and instead runs forever printing a message when an input is touched.

Once simpletest.py is running open the serial REPL for your board.  With your finger try pressing any of the 0-11 input pins on the MPR121.  You should see a message printed every time an input is touched:

If you don't see any messages when you touch the inputs try running the simpletest.py script again but without the -n option.  This will help you see if the script is failing to run because an exception is being thrown (if the command just hangs then the script is running and didn't fail, press Ctrl-C to stop ampy from waiting for output).

In addition you might need to ground yourself to the board by touching the GND pin on the board with one finger and then touching the input pads with another finger.  

Also make sure nothing is touching the pins when you first run the script or else it might confuse the MPR121's touch detection (re-run the script with nothing touching to try again).

Usage

Examine the rest of the simpletest.py code to see how to use the MPR121 module.  First the module is imported with code like:

# Import MPR121 module.
import adafruit_mpr121

This code initializes the I2C bus:

# Create I2C bus.
import board
import busio
i2c = busio.I2C(board.SCL, board.SDA)

Once the I2C bus is intialized the MPR121 class can be created by passing it an instance of the I2C bus:

# Create MPR121 class.
mpr121 = adafruit_mpr121.MPR121(i2c)
# Note you can optionally change the address of the device:
#mpr121 = adafruit_mpr121.MPR121(i2c, address=0x91)

Notice the MPR121 class initializer takes an optional address parameter if you changed the board's I2C address.

Now you're ready to start checking if inputs are touched.  Notice the main loop for the example calls the MPR121 class is_touched function for every input:

# Loop forever testing each input and printing when they're touched.
while True:
    # Loop through all 12 inputs (0-11).
    for i in range(12):
        # Call is_touched and pass it then number of the input.  If it's touched
        # it will return True, otherwise it will return False.
        if mpr121.is_touched(i):
            print('Input {} touched!'.format(i))
    time.sleep(0.25)  # Small delay to keep from spamming output messages.

Just pass a value 0 to 11 to the is_touched function and it will return a boolean True or False value depending on if the input is currently being touched or not.  In the example it prints a small message when an input is touched.

The example doesn't show its usage but if you want to check all of the inputs at once you can call the touched function.  This function returns a 12-bit value where each bit represents the touch state of an input.  So bit 0 is input 0 and will be 1 if it's touched and 0 if it's not touched, bit 1 would be input 1, etc.  For example to test if input 0 and 11 are being touched with one call you could run code like:

# Call touched to get a 12-bit value with the state of each MPR121 input.
touch = mpr121.touched()
# Test if exactly bit 0 and 11 are set to 1, i.e. input 0 and 11 are touched.
if touch == 0b100000000001:
    print('Input 0 and 11 touched!')
# Or test if either bit 0 or 11 are set to 1, i.e. input 0 or 11 are touched:
if touch & 0b100000000000 > 0 or touch & 0b000000000001 > 0:
    print('Input 0 or 11 touched!')

That's all there is to using the MPR121 module with CircuitPython!