Introduction: Arduino TFT Drawing Program

This instructable details the code that goes into making a drawing program for an Arduino TFT screen. This program is unique, however, because it allows for the saving of a drawing to the SD card and loading it later to make more edits!

Supplies

  1. Arduino Uno - original or a compatible clone
  2. TFT touchscreen - I used an Elegoo screen, meaning I needed Elegoo drivers.
  3. Micro SD reader board - used to store drawing data to SD card. My screen had a built in reader underneath the display.
  4. Stylus - my screen came with one. Fingernails work well, too.
  5. Micro SD card - no more than 32GB, due to exFAT formatting limitations (The Arduino can read FAT32 formatted cards but NOT exFAT. Most larger cards are formatted with exFAT.). This is the kind that you would put into a phone with expandable storage.
  6. Computer with Arduino IDE
  7. Programming cable - USB A to USB B. My Arduino came with one.
  8. SD card adapter - used to convert the Micro SD card into a normal SD to put into SD slot OR one that connects an SD card to a USB slot.

Step 1: Format the SD Card

  1. Take the Micro SD card and attach it to your computer using your SD card reader
  2. Open File Explorer and find the SD card.
  3. Right-click it and select Format.
  4. Set the options based on the screenshot.
  5. Click Start.
  6. Eject the card when the process is complete.

If you aren't running Windows, try using SD Formatter from the SD association.

Step 2: Prepare the Arduino

  1. Press your screen shield down onto the Arduino, taking care to line up the pins.
  2. Insert the SD card into the reader below the screen.

Step 3: Arduino Sketch

Although the parts list was pretty simple, there is a ton of code. I'll go through it step-by-step here.

#include <Elegoo_GFX.h>
#include <Elegoo_TFTLCD.h>
#include <TouchScreen.h>
#include <SPI.h>
#include <SD.h>

Elegoo_GFX, _TFTLCD, and TouchScreen are all hardware-specific. If you use a different screen, use the manufacturer-provided libraries.

SPI and SD are used to communicate with the SD card. SPI is the protocol used by the SD card controller.

#if defined(__SAM3X8E__)<br>#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif

This is also hardware-specific.

#define YP A3  // must be an analog pin<br>#define XM A2  // must be an analog pin
#define YM 9
#define XP 8
//Touch For New ILI9341 TP
#define TS_MINX 120
#define TS_MAXX 900
#define TS_MINY 70
#define TS_MAXY 920
#define CSPIN 10
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

Each of these #define statements make the IDE replace the name with the value. Here, they set the LCD and SD I/O pins.

// Assign names to some 16-bit color values:<br>#define	BLACK   0x0000
#define WHITE   0xFFFF
#define RED   0xF800
#define BLUE    0x001F
#define GREEN   0x07E0

These are a few of the colors used in the code. #define-ing them makes reading the code easier.

#define PENRADIUS 3

This defines the size of the drawing pen.

#define MINPRESSURE 10<br>#define MAXPRESSURE 1000
// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one I'm using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

These statements define the pressure needed to register a touch, initialize the touch function, and start the screen.

File storage;<br>int storageSize;
int stoX = 1;
int stoY = 1;

These are variables for the storage portion of the program.

void setup(void) {<br>  Serial.begin(9600);
  Serial.println("Paint program");
  tft.reset();
  uint16_t identifier = tft.readID();
  if (identifier == 0x0101) {
    identifier = 0x9341;
    Serial.println(F("Found 0x9341 LCD driver"));
  }
  //Start the screen
  tft.begin(identifier);
  tft.setRotation(2);
  pinMode(13, OUTPUT);
  //Start SD card
  if (!SD.begin(CSPIN)) {
    Serial.println("SD initialization failed");
    return;
  }
  Serial.println("SD initialized");
  //Draw the background
  drawBackground();
}

The setup function starts Serial if it is available, resets the screen, detects the TFT driver, starts the screen, starts the card, and calls a function to draw the background.

I will skip to the major part of the loop function. Everything else is just used to drive the touchscreen.

//Detect screen press and store it to variables<br>  if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
    //Scale
    p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(), 0);
    p.y = (tft.height() - map(p.y, TS_MINY, TS_MAXY, tft.height(), 0));
    //Draw
    if (p.y > 21) {
      //Save data to SD card
      storage = SD.open("storage.txt", FILE_WRITE);
      storage.print(p.x);
      storage.print(",");
      storage.println(p.y);
      storage.close();
      //Dot at the touch position
      tft.fillCircle(p.x, p.y, PENRADIUS, WHITE);
    }
    //Delete button
    if ((p.y < 21) && (p.x > 198) && (p.x < 219)) {
      deleteStorage();
    }
    //Load button action
    if ((p.y < 21) && (p.x > 219)) {
      loadStorage();
    }
  }

If a press is detected, set variables for the location of the press.

Then, if the press is within the drawing area, save the point to the SD card in storage.txt and draw a circle at the point pressed, with a defined size and color.

Then, if the press is at the location of the delete button, run a function that deletes the stored drawing. If you are using a different-sized screen, try playing with the button location values.

Then, if the press is at the location of the load button, run a function that loads the stored drawing. If you are using a different-sized screen, try playing with the button location values.

Now, I will explain the functions.

The first function is called in setup to draw the background and buttons.

void drawBackground() {<br>  //Set the background
  tft.fillScreen(BLACK);
  //Paint text
  tft.setTextColor(WHITE);
  tft.setTextSize(3);
  tft.setCursor(0, 0);
  tft.println("Paint");
  //Load button
  tft.fillRect(219, 0, 21, 21, GREEN);
  //Clear button
  tft.fillRect(198, 0, 21, 21, RED);
}

It fills the screen black, writes the word Paint, and draws colored squares for the buttons. If you are using a different-sized screen, try playing with the button location values.

void deleteStorage() {<br>  //Delete the file
  SD.remove("storage.txt");
  //Set the background
  tft.fillScreen(BLACK);
  //Delete Success text
  tft.setTextColor(WHITE);
  tft.setTextSize(2);
  tft.setCursor(0, 0);
  tft.println("storage.txt deleted");
  //Let the user read it
  delay(2000);
  //Continue drawing
  drawBackground();
}

The deleteStorage function removes storage.txt, fills the screen black, and gives a success message for deletion. It then calls the drawBackground function to allow you to start painting something else.

void loadStorage() {<br>  //Avoid repeats from slow fingers
  delay(250);
  //Check for storage file
  if (!SD.exists("storage.txt")) {
    Serial.println("No storage.txt file");
    return;
  }
  //Open file in read-only mode
  storage = SD.open("storage.txt", FILE_READ);
  //While there is data,
  while (stoY > 0) {
    //Update position variables
    stoX = storage.parseInt();
    stoY = storage.parseInt();
    //Draw from storage
    tft.fillCircle(stoX, stoY, PENRADIUS, WHITE);
  }
  //Close the file
  storage.close();
}

Finally, the loadStorage function checks for a storage file, opens it in read-only mode, then repeats this loop:

As long as there is more data,

  1. Update the position variables with the parsed data from storage.txt
  2. Draw a circle at the loaded point

When the loop completes and there is no more data, it closes the storage file.

The code for this sketch can be found below. Just download it, open it in Arduino, and upload it to your board!

Step 4: Using This Program

Just plug in your Arduino to a power source - computer, battery, wall wart, etc. and start drawing. To erase your drawing and its stored data, press the red button. To load a drawing from storage and continue working on it, click the green button. In this way, you can iterate many times on a drawing!

As an extension, try plotting the drawing on your computer:

  1. Plug the SD card with data into your computer.
  2. Open storage.txt in your favorite text/code editor.
  3. Copy all of the values in storage.txt.
  4. Follow this link to a point-plotting program.
  5. Delete the two example points on the left.
  6. Paste your data where the example points were.

This is a neat way to show off your drawings - maybe even try changing the point color on the Arduino or in the point-plotter!

Modifications are welcomed, and I'd love to see some suggestions in the comments. Thanks for taking a look at this and I hope that you'll find neat uses for it in your own projects!