“Build a 6x6 grid with an MPR121, expanding possible inputs from a mere 12 to 36!
A capacitor is simply two conductors with an insulator in between. This allows for a charge to be stored and then discharged. This also lets changes in its capacitance be sensed, such as a finger coming into contact with a copper pad. To read more about how capacitive touch sensing works, you can view this article.
The most important part of any capacitive-sensing circuit is the capacitive sensor. I went with the MPR121, mainly due to how easy it is to interface with it. It’s also nice because the board itself is cheap and has plenty of input pins to connect (12 total).
The brain of the whole circuit is an Arduino Nano, just because it’s what I had on hand and this project doesn’t need powerful hardware to run. The last piece is a long strip of copper tape, which is simply a thin piece of copper with an adhesive layer underneath. Anything conductive can be used in its place, such as bananas, screws, or aluminum strips.
Assembling the Grid
To begin, I got a piece of card stock and cut it into a square-ish shape. Next, I cut the copper strip into 12 smaller strips and attached them to the card stock, ensuring that there was even spacing between cells. Finally, I soldered a jumper wire to the edge of each copper strip and plugged it into the breadboard, along with the MPR121 and Arduino Nano. The MPR121 communicates with the Nano via I2C, so the SDA, SCL, VCC, GND, and IRQ lines were all attached.
The Capacitive Sensing Program
The program is fairly simple in operation. Every time the MPR121 senses a change, it generates an interrupt via its IRQ pin. Because this pin is active LOW, it means that the interrupt is active whenever it goes from HIGH to LOW, otherwise known as FALLING. The IRQ pin is attached to pin 2 on the Arduino Nano, which is the ATmega328p’s INT0 pin. It can also be attached to pin 3, which acts as INT1. The attachInterrupt() function is called that passes in a pointer to the callback function, which will cause the function to run whenever the interrupt is triggered.
The callback function simply updates a two-dimensional array of values, in which each cell is a product of the row and column at that location. For example, if row 4 has a value of 3000, and column 2 has a value of 1200, then the cell at (4, 2) = 3000 * 1200.
In the loop function, the two-dimensional is printed out every second by calling printTable().
Pygame is a great framework for creating interactive GUIs with Python, so I used it to display the grid of values. The table of values is printed out via Serial, which has TABLE to signify the start of each table. Then, there are 6 lines of data, with each element being separated by the
| symbol. The values are parsed by first stripping away the whitespace, then using the built-in split() method to convert the string into a list. The value is then mapped to a number between 0 and 255, which is used to color each square in the window, ranging from blue (no touch) to red (touched).
In the future, I would like to connect this circuit up as a way to have many virtual buttons, thus saving space and hardware. It could be used to control an LED matrix, interact with an exhibit, and much more.”