Display Custom Bitmap graphics on an Arduino Touch Screen and other Arduino compatible Displays
- Nick Koumaris
- http://educ8s.tv
- info@educ8s.tv
- 23.823 Views
- moderate
- Tested
Displaying a custom image or graphic on a LCD display is a very useful task as displays are now a premium way of providing feedback to users on any project. With this functionality, we can build projects that display our own logo, or display images that help users better understand a particular task the project is performing, providing an all-round improved User Experience (UX) for your Arduino or ESP8266 based project. Today’s tutorial will focus on how you can display graphics on most Arduino compatible displays.
The procedure described in this tutorial works with all color displays supported by Adafruit’s GFX library and also works for displays supported by the TFTLCD library from Adafruit with little modification. Some of the displays on which this procedure works include:
- 0.95″ Color SSD1331 OLED display
- 1.44″ ILI9163C TFT Display
- 1.8” ST7735 color TFT display
- 2.8” ILI9325 Color Touch Screen
- 3.5” ILI9481 Color TFT display
While these are the displays we have, and on which this tutorial was tested, we are confident it will work perfectly fine with most of the other Arduino compatible displays.
For each of the displays mentioned above, we have covered in past how to program and connect them to Arduino. You should check those tutorials, as they will give you the necessary background knowledge on how each of these displays works.
For this tutorial, we will use the 2.8″ ILI9325 TFT Display which offers a resolution of 320 x 340 pixels and we will display a bitmap image of a car.
Required Components
To demonstrate how this works with different displays, you can use some of the most popular displays:
As usual, each of the components listed above can be bought from the links attached to them. While having all of the displays listed above may be useful, you can use just one of them for this tutorial.
Schematics
To demonstrate how things work, we will use the 2.8″ TFT Display. The 2.8″ TFT display comes as a shield which plugs directly into the Arduino UNO as shown in the image below.
Not all Arduino displays are available as shields, so when working with any of them, connect the display as you would when displaying text (we recommend following the detailed tutorial for the display type you use of the above list). This means no special connection is required to display graphics.
With the screen connected, we then proceed to prepare the graphics images to be displayed.
Preparing the Graphics
Before an image is displayed on any of the Arduino screens, it needs to be converted to a C compatible hex file and that can only happen when the image is in bitmap form. Thus, our first task is to create a bitmap version of the graphics to be displayed or convert the existing image to a bitmap file. There are several tools that can be used for creation/conversion of bitmap images including, Corel Draw and Paint.net, but for this tutorial, we will use the Paint.net.
Our demo graphics today will be a car. We will create the car on a black background and use a white fill so it’s easy for us to change the color later on.
The resolution of the graphics created should be smaller than the resolution of your display to ensure the graphics fit properly on the display. For this example, the resolution of the display is 320 x 340, thus the resolution of the graphics was set to 195 x 146 pixels.
Your graphics could also include some text. Just ensure the background is black and the fill color is white if you plan to change the color within your Arduino code.
With the graphics done, save both files as .bmp with 24bits color. It is important to keep in mind that large bitmaps use up a lot of memory and may prevent your code from running properly so always keep the bitmaps as small as possible.
The next task is to convert the graphics into byte arrays so they can be used in the code.
To do this, we will use the “Image2Code” Java utility developed by Adafruit.
Image2Code is an easy-to-use, small Java utility to convert images into a byte array that can be used as a bitmap on displays that are compatible with the Adafruit-GFX or Adafruit TFTLCD (with little modification) library.
All we have to do is to load the graphics into the software by clicking the “Choose file” button and it will automatically generate a byte array equivalent to the selected bitmap file.
Copy the generated bit array, and create a graphics.c file in the same Arduino project folder where the code will reside.
Paste the bit array in the graphics.c file and save. Since we have two graphics (the car and the text), You can paste their data array in the same file. check the graphics.c file attached to the zip file, under the download section to understand how to do this. Don’t forget to declare the data type as “const unsigned char“, add PROGEM in front of it and include the avr/pgmspace.h header file as shown in the image below. This instructs the code to store the graphics data in the program memory of the Arduino.
With this done, we are now ready to write the code. Do note that this procedure is the same for all kind of displays and all kind of graphics. Convert the graphics to a bitmap file and use the Img2code utility to convert it into a hex file which can then be used in your Arduino code.
Code
To reduce the amount of code, and stress involved in displaying the graphics, we will use two wonderful libraries; The GFX library and the TFTLCD library from Adafruit.
The GFX library, among several other useful functions, has a function called drawBitmap(), which enables the display of a monochrome bitmap image on the display. This function allows the upload of monochrome only (single color) graphics, but this can be overcome by changing the color of the bitmap using some code.
The Adafruit libraries do not support all of the displays but there are several modifications of the libraries on the internet for more displays. If you are unable to find a modified version of the library suitable for your the display, all you need do is copy the code of the drawBitmap() function from the GFX library and paste it in the Arduino sketch for your project such that it becomes a user-defined function.
The drawBitmap function takes 6 arguments as shown in the code snippet below;
void drawBitmap(int16_t x, int16_t y,const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
The first two are the x and y coordinates of a point on the screen where we want the image to be displayed. The next argument is the array in which the bitmap is loaded in our code, in this case, it will be the name of the car and the text array located in the graphics.c file. The next two arguments are the width and height of the bitmap in pixels, in other words, the resolution of the image. The last argument is the color of the bitmap, we can use any color we like. The bitmap data must be located in program memory since Arduino has a limited amount of RAM memory available.
Since using a display without the GFX library is more complex, it’s probably better to do an explanation of how to write the code for this procedure.
As usual, we start writing the sketch by including the libraries required. For this procedure, we will use the TFTLCD library alone, since we are assuming you are using a display that is not supported by the GFX library.
/////////////////////////// // 2.8" CAR DISPLAY DEMO // // http://www.educ8s.tv // ////////////////////////// #include <Adafruit_TFTLCD.h>
Next, we declare the pins of the Arduino to which the LCD is connected.
#define LCD_CS A3 #define LCD_CD A2 #define LCD_WR A1 #define LCD_RD A0 #define LCD_RESET A4
Next, we create the colors to be used, specifying the matching hex values and then create an instance of the TFTLCD library.
#define BLACK 0x0000 #define BLUE 0x001F #define RED 0xF800 #define GREEN 0x07E0 #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define WHITE 0xFFFF #define GREY 0xD6BA Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
Next, we specify the name of the graphics to be displayed; car and title. At this stage, you should have added the bit array for these two bitmaps in the graphics.c file and the file should be placed in the same folder as the Arduino sketch.
extern uint8_t car[]; extern uint8_t title[];
Next, we write the void setup function. All we do here is to initialize the screen and rotate it to a preferred orientation.
void setup() { Serial.begin(9600); Serial.print("Starting..."); tft.reset(); tft.begin(0x9325); tft.setRotation(1); }
With that done, we proceed to the void loop function, under the loop function, we call the drawbitmap() function to display the car and the text bitmap using different colors.
void loop() { tft.fillScreen(BLACK); tft.drawRect(0,0,319,240,WHITE); //Draw white frame drawBitmap(30, 10, title, 275, 31,WHITE); drawBitmap(65, 70, car, 195, 146,GREEN); delay(2000); drawBitmap(30, 10, title, 275, 31,BLUE); drawBitmap(65, 70, car, 195, 146,RED); delay(2000); drawBitmap(30, 10, title, 275, 31,RED); drawBitmap(65, 70, car, 195, 146,BLUE); delay(2000); tft.fillScreen(WHITE); //Make screen white drawBitmap(30, 10, title, 275, 31,BLACK); drawBitmap(65, 70, car, 195, 146,BLACK); delay(2000); }
The last section of the code is the drawBitmap function itself, as earlier mentioned, to use the drawbitmap() function with the Adafruit TFTLCD library, we need to copy the function’s code and paste into the Arduino sketch.
void drawBitmap(int16_t x, int16_t y,const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) { int16_t i, j, byteWidth = (w + 7) / 8; uint8_t byte; for(j=0; j<h; j++) { for(i=0; i<w; i++) { if(i & 7) byte <<= 1; else byte = pgm_read_byte(bitmap + j * byteWidth + i / 8); if(byte & 0x80) tft.drawPixel(x+i, y+j, color); } } }
The complete code for the project is available below and also attached under the download section at the end of the tutorial.
////////////////////////////////////////////// // 2.8" CAR DISPLAY DEMO // // // // http://www.educ8s.tv // ///////////////////////////////////////////// #include <Adafruit_TFTLCD.h> #define LCD_CS A3 #define LCD_CD A2 #define LCD_WR A1 #define LCD_RD A0 #define LCD_RESET A4 #define BLACK 0x0000 #define BLUE 0x001F #define RED 0xF800 #define GREEN 0x07E0 #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define WHITE 0xFFFF #define GREY 0xD6BA Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET); extern uint8_t car[]; extern uint8_t title[]; void setup() { Serial.begin(9600); Serial.print("Starting..."); tft.reset(); tft.begin(0x9325); tft.setRotation(1); } void loop() { tft.fillScreen(BLACK); tft.drawRect(0,0,319,240,WHITE); //Draw white frame drawBitmap(30, 10, title, 275, 31,WHITE); drawBitmap(65, 70, car, 195, 146,GREEN); delay(2000); drawBitmap(30, 10, title, 275, 31,BLUE); drawBitmap(65, 70, car, 195, 146,RED); delay(2000); drawBitmap(30, 10, title, 275, 31,RED); drawBitmap(65, 70, car, 195, 146,BLUE); delay(2000); tft.fillScreen(WHITE); //Make screen white drawBitmap(30, 10, title, 275, 31,BLACK); drawBitmap(65, 70, car, 195, 146,BLACK); delay(2000); } void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) { int16_t i, j, byteWidth = (w + 7) / 8; uint8_t byte; for(j=0; j<h; j++) { for(i=0; i<w; i++) { if(i & 7) byte <<= 1; else byte = pgm_read_byte(bitmap + j * byteWidth + i / 8); if(byte & 0x80) tft.drawPixel(x+i, y+j, color); } } }
Demo
Plug in your screen as shown above. If you are using any other display, connect it as shown in the corresponding linked tutorial. With the schematics in place, connect the Arduino board to your PC and upload the code. Don’t forget the graphics file needs to be in the same folder as the Arduino sketch.
With that done, you should see your screen come up as shown in the image below.
That’s it for this tutorial guys. The procedure is the same for all kinds of Arduino compatible displays. If you get stuck while trying to replicate this using any other display, feel free to reach out to me via the comment sections below.
Till Next time.
The video version of this tutorial is available on Youtube.
Hey Nick, great post. I just stumbled across it and it definitely helped me get an image to my 1.44″ screen (a knock-off of Adafruit’s). Question- Have you tried animating it? i.e. moving the image around the screen? I’m trying to make a simple pair of “eyes” for a robot, that look around based on input from various sensors. But the refresh rate is so unbelievably slow. The image slowly wipes to black and then the new image slowly wipes onto the screen. I’m looking for a tutorial on how to get this to function in a similar manner to Adafruits animated electronic eyes (https://learn.adafruit.com/animated-electronic-eyes). Any tips?
This is old but the best way(that I know of) is to use the TFT_eSPI library and make sprites. This lets you draw the images into the sprites and paste them to the TFT without the flicker. You could have one Sprite for the eye whites and one for the pupils and composite them together. Then just push the pupil sprites onto the eye sprites. in the TFT_eSPI library there is an example for rotated sprites.