provides some challenges in geometry, since the touchscreen coordinates don't match the TFT coordinates. The scale is different and the rotation frame is 180 degrees off. It also includes a microSD (uSD) slot hidden underneath, wired to the SPI pins 11,12,13 with the card select wired to pin 5. The TFT seems to use pins 4, 5, 6, 7, 8, 9, 10, 11, 13, A0, A1, A2, and A3. The touchscreen uses pins 6, 7, A1, and A2. Getting them to play nice while sharing all those pins looks like a challenge, but the sample software works fine for me right out of the box on an UNO.
Reading the touch screen and writing to the TFT are both slow processes with the supplied software libraries.
It would be nice to have some way of scrolling a section of the screen, e.g. for a scrolling chart recorder, but for now I can make do drawing lines and boxes. I'm working on a library that defines a single TFT/TS class and does some other cool stuff to draw buttons, graphs and otherwise make using the combination a little more seamless. Now
, including an example program that follows the steps below to get all three features working together.
Adafruit provides an example for copying bitmap files to the screen from a uSD card, that doesn't use the touch screen. They also provide an example for a really simple paint program that uses the TFT and the touch screen, but not the uSD. I wanted to be able to use the TFT and the touch screen and record data from the program to the uSD for a log of what happened. I found that really hard to accomplish because I wasn't paying enough attention to the hardware conflicts. In addition to getting the pin directions right, the status of the SPI control register has to be preserved separately for TFT operations and uSD operations. The sketch below is a copy of the Adafruit paint example that does that to record a log file to the uSD. I hope the insight saves you some time.
Testing also shows that you can open multiple files for output simultaneously by following the obvious steps in parallel. (1 SD object, two separate File objects.) Watch out because these three libraries together take a lot of code space, putting you up against the 32K barrier on the UNO.
// Paint example specifically for the TFTLCD Arduino shield.
// If using the breakout board, use the tftpaint.pde sketch instead!
//************************************************************
// Modified by RWS to record data to a log file on the SD card
// Crucial stuff about saving the SPI control register state
// marked with asterisks like these ones....
//************************************************************
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
#include <TouchScreen.h>
#include <SD.h>
#define SD_CS 5 // Card select for shield use
// These are the pins for the shield!
#define YP A1 // must be an analog pin, use "An" notation!
#define XM A2 // must be an analog pin, use "An" notation!
#define YM 7 // can be a digital pin
#define XP 6 // can be a digital pin
#define TS_MINX 150
#define TS_MINY 120
#define TS_MAXX 920
#define TS_MAXY 940
// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
//#define LCD_CS A3 // these defines don't seem to be needed in the sketch
//#define LCD_CD A2 // although they are a hint that the TFTLCD may use those pins
//#define LCD_WR A1
//#define LCD_RD A0
// Assign human-readable names to some common 16-bit color values:
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
Adafruit_TFTLCD tft;
uint8_t spi_save_tft,spi_save_sd;
#define BOXSIZE 40
#define PENRADIUS 4
int oldcolor, currentcolor;
File logfile;
void setup(void) {
Serial.begin(9600);
progmemPrintln(PSTR("Paint!"));
tft.reset();
uint16_t identifier = tft.readID();
if(identifier == 0x9325) {
progmemPrintln(PSTR("Found ILI9325 LCD driver"));
} else if(identifier == 0x9328) {
progmemPrintln(PSTR("Found ILI9328 LCD driver"));
} else if(identifier == 0x7575) {
progmemPrintln(PSTR("Found HX8347G LCD driver"));
} else {
progmemPrint(PSTR("Unknown LCD driver chip: "));
Serial.println(identifier, HEX);
return;
}
tft.begin(identifier);
tft.fillScreen(BLACK);
tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED);
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW);
tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, GREEN);
tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, CYAN);
tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, BLUE);
tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, MAGENTA);
// tft.fillRect(BOXSIZE*6, 0, BOXSIZE, BOXSIZE, WHITE);
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);
currentcolor = RED;
//*******************************************************************
spi_save_tft = SPCR; // save the state of the SPI control register for TFT before SD stuff
//*******************************************************************
progmemPrint(PSTR("Initializing SD card...")); //*****************************************************
if (!SD.begin(SD_CS)) { // SD code from the Adafruit data logger shield example
progmemPrintln(PSTR("failed!")); //*****************************************************
return;
}
progmemPrintln(PSTR("OK!"));
// create a new file
char filename[] = "TSTLOG00.TXT";
for (uint8_t i = 0; i < 100; i++) {
filename[6] = i/10 + '0';
filename[7] = i%10 + '0';
if (! SD.exists(filename)) {
// only open a new file if it doesn't exist
logfile = SD.open(filename, FILE_WRITE);
break; // leave the loop!
}
}
if (! logfile) {
Serial.println("bad file");
}
else{
Serial.print("Log to: ");
Serial.println(filename);
}
//**********************************************************
spi_save_sd = SPCR; // save the state of the SPI control register after SD stuff
//**********************************************************
pinMode(13, OUTPUT); // maybe this pin 13 stuff has something to do with the SD card on SPI?
// or maybe it's just about blinking
}
#define MINPRESSURE 10
#define MAXPRESSURE 1000
void loop()
{
digitalWrite(13, HIGH);
Point p = ts.getPoint();
digitalWrite(13, LOW);
// if sharing pins, you'll need to fix the directions of the touchscreen pins
// the touchscreen swaps them back and forth between input and output multiple times
pinMode(XP, OUTPUT);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
pinMode(YM, OUTPUT);
// we have some minimum pressure we consider 'valid'
// pressure of 0 means no pressing!
if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
/*
Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);
Serial.print("\tPressure = "); Serial.println(p.z);
*/
//********************************************************
SPCR = spi_save_sd; // reset to the SD saved state of the SPI control register
//********************************************************
logfile.print("X = "); logfile.print(p.x);
logfile.print("\tY = "); logfile.print(p.y);
logfile.print("\tPressure = "); logfile.println(p.z);
logfile.flush();
//************************************************************
SPCR = spi_save_tft; // reset to the non-SD saved state of the SPI control register
//************************************************************
if (p.y < (TS_MINY-5)) {
Serial.println("erase");
// press the bottom of the screen to erase
tft.fillRect(0, BOXSIZE, tft.width(), tft.height()-BOXSIZE, BLACK);
}
// scale from 0->1023 to tft.width
p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(), 0);
p.y = map(p.y, TS_MINY, TS_MAXY, tft.height(), 0);
/*
Serial.print("("); Serial.print(p.x);
Serial.print(", "); Serial.print(p.y);
Serial.println(")");
*/
if (p.y < BOXSIZE) {
oldcolor = currentcolor;
if (p.x < BOXSIZE) {
currentcolor = RED;
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*2) {
currentcolor = YELLOW;
tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*3) {
currentcolor = GREEN;
tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*4) {
currentcolor = CYAN;
tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*5) {
currentcolor = BLUE;
tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*6) {
currentcolor = MAGENTA;
tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, WHITE);
}
if (oldcolor != currentcolor) {
if (oldcolor == RED) tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED);
if (oldcolor == YELLOW) tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW);
if (oldcolor == GREEN) tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, GREEN);
if (oldcolor == CYAN) tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, CYAN);
if (oldcolor == BLUE) tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, BLUE);
if (oldcolor == MAGENTA) tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, MAGENTA);
}
}
if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) {
tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor);
}
}
}
// Copy string from flash to serial port
// Source string MUST be inside a PSTR() declaration!
void progmemPrint(const char *str) {
char c;
while(c = pgm_read_byte(str++)) Serial.print(c);
}
// Same as above, with trailing newline
void progmemPrintln(const char *str) {
progmemPrint(str);
Serial.println();
}