Touch Shield Piano
- This project uses a 2.8" TFT Touch Screen for input and output (background display) and a standard simple speaker for audio output
- It must be used with Arduino IDE ver. 1.0.1 -- the TFT library it depends upon does NOT compile correctly under version 1.0.3; other versions are untested.
- This sketch requires the Adafruit TFT/Touchscreen libraries available from https://github.com/adafruit/Touch-Screen-Library
Hardware Required
1 x Arduino Uno or Arduino Mega
1 x Seeeduino Touch Shield, ver. 1.0 (2.8" TFT)
1 x 8-Ohm Speaker
The Sketch
// Adapted from the Adafruit Paint application included with the TFT/Touchscreen library package to demonstrate both TFT and Touch Screen
// Code modified to draw a piano style keyboard and assign proper pitches to those keys so that they play the correct note when touched
// It is recommended to use a PDA type stylus for added touch precision with this sketch, as the piano keys are pretty small
// *** BE SURE TO SET THE "speaker" PIN VALUE CORRECTLY FOR YOUR ARDUINO BOARD ***
// Ver. 1.0 - Clay Furman 20 DEC 2012
#include <stdint.h>
#include <TouchScreen.h>
#include <TFT.h>
const int speaker=19; //Pin to which the speaker is connected -- use 19 (this is the A5 pin, as a digital output) for Uno or 53 for Mega
//Define frequencies for each of the possible notes
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
//Measured ADC values for (0,0) and (210-1,320-1)
//TS_MINX corresponds to ADC value when X = 0
//TS_MINY corresponds to ADC value when Y = 0
//TS_MAXX corresponds to ADC value when X = 240 -1
//TS_MAXY corresponds to ADC value when Y = 320 -1
static unsigned int TS_MINX, TS_MAXX, TS_MINY, TS_MAXY;
//Touch Screen Co-ordinate mapping register
static unsigned int MapX1, MapX2, MapY1, MapY2;
/* Usage: TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
Where, XP = X plus, YP = Y plus, XM = X minus and YM = Y minus */
//init TouchScreen port pins. This would be reinitialized in setup() based on the hardware detected.
TouchScreen ts = TouchScreen(17, A2, A1, 14, 300);
int color = BLUE; //Default Paint brush color
int duration=250; //Default value for the tone duration
int wait=300; //Default time to wait between notes
void setup()
{
Tft.init(); //init TFT library
initTouchScreenParameters(); // initializes Touch Screen parameters based on the detected TFT Touch Shield hardware
// Serial.begin(9600); //debug
//Draw the white keys on the keyboard
for (int i=0; i<21; i++) {
Tft.fillRectangle(0,i*16,240,15,WHITE);
}
//Draw the black keys on the keyboard
Tft.fillRectangle(0,11,140,11,BLACK);
Tft.fillRectangle(0,43,140,11,BLACK);
Tft.fillRectangle(0,59,140,11,BLACK);
Tft.fillRectangle(0,75,140,11,BLACK);
Tft.fillRectangle(0,107,140,11,BLACK);
Tft.fillRectangle(0,123,140,11,BLACK);
Tft.fillRectangle(0,155,140,11,BLACK);
Tft.fillRectangle(0,171,140,11,BLACK);
Tft.fillRectangle(0,187,140,11,BLACK);
Tft.fillRectangle(0,219,140,11,BLACK);
Tft.fillRectangle(0,235,140,11,BLACK);
Tft.fillRectangle(0,267,140,11,BLACK);
Tft.fillRectangle(0,283,140,11,BLACK);
Tft.fillRectangle(0,299,140,11,BLACK);
}
void loop()
{
// Serial.println(Tft.IC_CODE,HEX); //debug
// a point object holds x y and z coordinates.
Point p = ts.getPoint();
// we have some minimum pressure we consider 'valid'
// pressure of 0 means no pressing!
if (p.z > ts.pressureThreshhold) {
//map the ADC value read to into pixel co-ordinates
p.x = map(p.x, TS_MINX, TS_MAXX, MapX1, MapX2);
p.y = map(p.y, TS_MINY, TS_MAXY, MapY1, MapY2);
// Determine if the key played is in the potential sharp side or not
if(p.x < 140)
{
Tft.fillCircle(p.x,p.y,2,color);
//Key might be a sharp -- split Y axis into black and white keys
if (p.y>=0 && p.y<=10) tone(speaker,NOTE_D6, duration);
if (p.y>=11 && p.y<=21) tone(speaker,NOTE_CS6, duration);
if (p.y>=22 && p.y<=31) tone(speaker,NOTE_C6, duration);
if (p.y>=33 && p.y<=42) tone(speaker,NOTE_B5, duration);
if (p.y>=43 && p.y<=53) tone(speaker,NOTE_AS5, duration);
if (p.y>=54 && p.y<=58) tone(speaker,NOTE_A5, duration);
if (p.y>=59 && p.y<=69) tone(speaker,NOTE_GS5, duration);
if (p.y>=70 && p.y<=74) tone(speaker,NOTE_G5, duration);
if (p.y>=75 && p.y<=85) tone(speaker,NOTE_FS5, duration);
if (p.y>=86 && p.y<=95) tone(speaker,NOTE_F5, duration);
if (p.y>=97 && p.y<=106) tone(speaker,NOTE_E5, duration);
if (p.y>=107 && p.y<=117) tone(speaker,NOTE_DS5, duration);
if (p.y>=118 && p.y<=122) tone(speaker,NOTE_D5, duration);
if (p.y>=123 && p.y<=133) tone(speaker,NOTE_CS5, duration);
if (p.y>=134 && p.y<=143) tone(speaker,NOTE_C5, duration);
if (p.y>=145 && p.y<=154) tone(speaker,NOTE_B4, duration);
if (p.y>=155 && p.y<=165) tone(speaker,NOTE_AS4, duration);
if (p.y>=166 && p.y<=170) tone(speaker,NOTE_A4, duration);
if (p.y>=171 && p.y<=181) tone(speaker,NOTE_GS4, duration);
if (p.y>=182 && p.y<=186) tone(speaker,NOTE_G4, duration);
if (p.y>=187 && p.y<=197) tone(speaker,NOTE_FS4, duration);
if (p.y>=198 && p.y<=207) tone(speaker,NOTE_F4, duration);
if (p.y>=209 && p.y<=218) tone(speaker,NOTE_E4, duration);
if (p.y>=219 && p.y<=229) tone(speaker,NOTE_DS4, duration);
if (p.y>=230 && p.y<=234) tone(speaker,NOTE_D4, duration);
if (p.y>=235 && p.y<=245) tone(speaker,NOTE_CS4, duration);
if (p.y>=246 && p.y<=255) tone(speaker,NOTE_C4, duration);
if (p.y>=257 && p.y<=266) tone(speaker,NOTE_B3, duration);
if (p.y>=267 && p.y<=277) tone(speaker,NOTE_AS3, duration);
if (p.y>=278 && p.y<=282) tone(speaker,NOTE_A3, duration);
if (p.y>=283 && p.y<=293) tone(speaker,NOTE_GS3, duration);
if (p.y>=294 && p.y<=298) tone(speaker,NOTE_G3, duration);
if (p.y>=299 && p.y<=309) tone(speaker,NOTE_FS3, duration);
if (p.y>=310 && p.y<=319) tone(speaker,NOTE_F3, duration);
}
else
{
//Key is too far along X axis to be sharp -- split Y axis into white keys only
Tft.fillCircle(p.x,p.y,2,color);
if (p.y>=0 && p.y<=15) tone(speaker,NOTE_D6, duration);
if (p.y>=17 && p.y<=31) tone(speaker,NOTE_C6, duration);
if (p.y>=33 && p.y<=47) tone(speaker,NOTE_B5, duration);
if (p.y>=49 && p.y<=63) tone(speaker,NOTE_A5, duration);
if (p.y>=65 && p.y<=79) tone(speaker,NOTE_G5, duration);
if (p.y>=81 && p.y<=95) tone(speaker,NOTE_F5, duration);
if (p.y>=97 && p.y<=111) tone(speaker,NOTE_E5, duration);
if (p.y>=113 && p.y<=127) tone(speaker,NOTE_D5, duration);
if (p.y>=129 && p.y<=143) tone(speaker,NOTE_C5, duration);
if (p.y>=145 && p.y<=159) tone(speaker,NOTE_B4, duration);
if (p.y>=161 && p.y<=175) tone(speaker,NOTE_A4, duration);
if (p.y>=177 && p.y<=191) tone(speaker,NOTE_G4, duration);
if (p.y>=193 && p.y<=207) tone(speaker,NOTE_F4, duration);
if (p.y>=209 && p.y<=223) tone(speaker,NOTE_E4, duration);
if (p.y>=225 && p.y<=239) tone(speaker,NOTE_D4, duration);
if (p.y>=241 && p.y<=255) tone(speaker,NOTE_C4, duration);
if (p.y>=257 && p.y<=271) tone(speaker,NOTE_B3, duration);
if (p.y>=273 && p.y<=287) tone(speaker,NOTE_A3, duration);
if (p.y>=289 && p.y<=303) tone(speaker,NOTE_G3, duration);
if (p.y>=305 && p.y<=319) tone(speaker,NOTE_F3, duration);
}
//Wait for the tone to play -- you can adjust the scalar to make the gap between tones more pronounced -- and then kill the tone output to prepare for the next cycle
wait=duration*1;
delay(wait);
noTone(speaker);
}
}
void initTouchScreenParameters()
{
//This function initializes Touch Screen parameters based on the detected TFT Touch Schield hardware
if(Tft.IC_CODE == 0x5408) //SPFD5408A TFT driver based Touchscreen hardware detected
{
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ts = TouchScreen(54, A1, A2, 57, 300); //init TouchScreen port pins
#else
ts = TouchScreen(14, A1, A2, 17, 300); //init TouchScreen port pins
#endif
//Touchscreen parameters for this hardware
TS_MINX = 120;
TS_MAXX = 910;
TS_MINY = 120;
TS_MAXY = 950;
MapX1 = 239;
MapX2 = 0;
MapY1 = 0;
MapY2 = 319;
}
else //ST7781R TFT driver based Touchscreen hardware detected
{
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ts = TouchScreen(57, A2, A1, 54, 300); //init TouchScreen port pins
#else
ts = TouchScreen(17, A2, A1, 14, 300); //init TouchScreen port pins
#endif
//Touchscreen parameters for this hardware
TS_MINX = 140;
TS_MAXX = 900;
TS_MINY = 120;
TS_MAXY = 940;
MapX1 = 239;
MapX2 = 0;
MapY1 = 319;
MapY2 = 0;
}
}
Use
- To play the piano, simply touch the "keys" displayed on the screen -- a PDA stylus is recommended because the keys are pretty small.
Enjoy!
cfurman?