Sparkfun Touch Shield
Last updated: 3 October 2012
Prepared by Samson Young [skfyoung@cityu.edu.hk]
URL: https://www.sparkfun.com/products/10508
Cost per unit: $14.95 USD (approx. 116 HKD)

TouchShield.jpg





















General Information

About Touch Shield
The touch shield has 9 capacitive touch pads, with headers for the remaining 3 electrode connections. With this shield you can have a total of 12 touch sensitive buttons. An on-board logic level converter allows it to work with 5V and 3.3V Arduino boards (excerpted from sparkfun.com, accessed October 3, 2012).

Features & Specifications
- No special specs to note.

Things to Note
I *think* this shield is able to detect multi-touch, but somehow in my own example whenever I try to get it do multi-touch stuff it freezes up. This might have something to do with serial communication management – if one of you manages to solve this problem please let me know your solution and I will post an update. The example code checks to see if key press == 1, and only proceed if state returned is true.

Getting it to work!
Assembly
The shield needs a way to connect to the arduino main board – the easiest thing to do is just solder some stackable header pins onto the shield.
In the example code I stacked the touch shield, the music instrument shield and the arduino together to create a touchpad instrument. When you put everything together they look like this:

touchassem.jpg




Connection
No special connection from the board is required in the example code. Simply put the shield on top of your arduino board (see above). See Music Shield SUM for details on the use of the music shield.

Library
My example code is a modification of Jum Lindblom’s example on sparkfun’s website. It uses a default atmel I2c library. Be sure to keep all the .h files inside of the example code zipped folder.

Example Code

/*
TouchPad + MusicShield Instrument
Modified based on Jim Lindblom's touchshield example
by Samson Young [skfyoung@cityu.edu.hk]
*/

TOUCHPAD STUFF
#include "mpr121.h"
#include "i2c.h"
#define DIGITS 11
#define ONE 8
#define TWO 5
#define THREE 2
#define FOUR 7
#define FIVE 4
#define SIX 1
#define SEVEN 6
#define EIGHT 3
#define NINE 0
Variables for the getNumber() function.
int i = 0;
int touchNumber = 0;
uint16_t touchstatus;
char digits[DIGITS];
interupt pin
int irqpin = 2; D2
END OF TOUCHPAD STUFF

MUSIC SHIELD STUFF
#include <NewSoftSerial.h>
NewSoftSerial mySerial(2, 3);
byte note = 0;
byte resetMIDI = 4;
byte ledPin = 13; MIDI traffic inidicator
END OF MUSIC SHIELD STUFF

void setup()
{
TOUCHPAD STUFF
make sure the interrupt pin is an input and pulled high
pinMode(irqpin, INPUT);
digitalWrite(irqpin, HIGH);
output on ADC4 (PC4, SDA)
DDRC |= 0b00010011;
Pull-ups on I2C Bus
PORTC = 0b00110000;
initalize I2C bus. Wiring lib not used.
i2cInit();
delay(100);
initialize mpr121
mpr121QuickConfig();
Create and interrupt to trigger when a button
is hit, the IRQ pin goes low, and the function getNumber is run.
attachInterrupt(0,getNumber,LOW);
END OF TOUCHPAD STUFF

MUSIC SHIELD STUFF
Reset the VS1053 chip and setup softserial for MIDI control
mySerial.begin(31250);
pinMode(resetMIDI, OUTPUT);
digitalWrite(resetMIDI, LOW);
delay(100);
digitalWrite(resetMIDI, HIGH);
delay(100);

}

void loop()
{
This is where you program all the music stuff
GetNumber function called. See below.
getNumber();
0xB0 is channel message, set channel volume to near max (127)
talkMIDI(0xB0, 0x07, 120);
Choose GM1 Bank
talkMIDI(0xB0, 0, 0x00);

if (touchstatus & (1<<SEVEN))
{
talkMIDI(0xC0, 10, 0); select instrument (middle number)
noteOn(0, 60, 127); select pitch (middle number)
delay(100);
noteOff(0, 60, 60);
delay(100);
}

else if (touchstatus & (1<<FOUR))
{
talkMIDI(0xC0, 11, 0); select instrument (middle number)
noteOn(0, 60, 127); select pitch (middle number)
delay(100);
noteOff(0, 60, 60);
delay(100);
}

else if (touchstatus & (1<<ONE))
{
talkMIDI(0xC0, 12, 0); select instrument (middle number)
noteOn(0, 60, 127); select pitch (middle number)
delay(100);
noteOff(0, 60, 60);
delay(100);
}


else if (touchstatus & (1<<EIGHT))
{
talkMIDI(0xC0, 13, 0); select instrument (middle number)
noteOn(0, 60, 127); select pitch (middle number)
delay(100);
noteOff(0, 60, 60);
delay(100);
}

else if (touchstatus & (1<<FIVE))
{
talkMIDI(0xC0, 14, 0); select instrument (middle number)
noteOn(0, 60, 127); select pitch (middle number)
delay(100);
noteOff(0, 60, 60);
delay(100);
}


else if (touchstatus & (1<<TWO))
{
talkMIDI(0xC0, 15, 0); select instrument (middle number)
noteOn(0, 60, 127); select pitch (middle number)
delay(100);
noteOff(0, 60, 60);
delay(100);
}

else if (touchstatus & (1<<NINE))
{
talkMIDI(0xC0, 74, 0); select instrument (middle number)
noteOn(0, 60, 127); select pitch (middle number)
delay(100);
noteOff(0, 60, 60);
delay(100);
}

else if (touchstatus & (1<<SIX))
{
talkMIDI(0xC0, 75, 0); select instrument (middle number)
noteOn(0, 60, 127); select pitch (middle number)
delay(100);
noteOff(0, 60, 60);
delay(100);
}

else if (touchstatus & (1<<THREE))
{
talkMIDI(0xC0, 76, 0); select instrument (middle number)
noteOn(0, 60, 127); select pitch (middle number)
delay(100);
noteOff(0, 60, 60);
delay(100);
}

}

getNumber Management
void getNumber()
{
touchstatus = mpr121Read(0x01) << 8;
touchstatus |= mpr121Read(0x00);
Check how many electrodes were pressed
for (int j=0; j<12; j++)
{
if ((touchstatus & (1<<j)))
touchNumber++;
}
}


declare the noteOn(), noteOff(), and talkMIDI() functions for MIDI.
do not modify.

Send a MIDI note-on message. Like pressing a piano key
channel ranges from 0-15
void noteOn(byte channel, byte note, byte attack_velocity) {
talkMIDI( (0x90 | channel), note, attack_velocity);
}

Send a MIDI note-off message. Like releasing a piano key
void noteOff(byte channel, byte note, byte release_velocity) {
talkMIDI( (0x80 | channel), note, release_velocity);
}

Plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that data values are less than 127
void talkMIDI(byte cmd, byte data1, byte data2) {
digitalWrite(ledPin, HIGH);
mySerial.print(cmd, BYTE);
mySerial.print(data1, BYTE);

Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes
//(sort of: http://253.ccarh.org/handout/midiprotocol/)
if( (cmd & 0xF0) <= 0xB0)
mySerial.print(data2, BYTE);

digitalWrite(ledPin, LOW);
}