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
- Arduino Uno - original or a compatible clone
- TFT touchscreen - I used an Elegoo screen, meaning I needed Elegoo drivers.
- Micro SD reader board - used to store drawing data to SD card. My screen had a built in reader underneath the display.
- Stylus - my screen came with one. Fingernails work well, too.
- 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.
- Computer with Arduino IDE
- Programming cable - USB A to USB B. My Arduino came with one.
- 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
- Take the Micro SD card and attach it to your computer using your SD card reader
- Open File Explorer and find the SD card.
- Right-click it and select Format.
- Set the options based on the screenshot.
- Click Start.
- 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
- Press your screen shield down onto the Arduino, taking care to line up the pins.
- 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,
- Update the position variables with the parsed data from storage.txt
- 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!
Attachments
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:
- Plug the SD card with data into your computer.
- Open storage.txt in your favorite text/code editor.
- Copy all of the values in storage.txt.
- Follow this link to a point-plotting program.
- Delete the two example points on the left.
- 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!