Displaying RGB bitmap on tft from .c file

#define TFT_CS     10
#define TFT_RST    8
#define TFT_DC     9
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#include "hi.c"

int tank_y = 97;
int tank_x = 40; 
int y;
int x;

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
extern uint8_t tank;
void setup(){
  

void loop(){}

hi.c (19.0 KB)

I am using a 1.8 tft by the way

  1. Are you able to read that array?
  2. Will you be using this format for other images?
  3. Where did you generate that file?

Did you try the drawBitmap function that comes with the Adafruit_GFX library? There might be an example sketch that demonstrates the bitmap function.

I guess the TO has been using this webpage

https://www.pixilart.com/

At the end of the appended hi.c one can find this

const lv_img_dsc_t pixil-frame-0 = {
  .header.cf = LV_IMG_CF_RGB565A8,
  .header.always_zero = 0,
  .header.reserved = 0,
  .header.w = 32,
  .header.h = 32,
  .data_size = 3072,
  .data = pixil-frame-0_map,
};

The picture specification:

  • Width 32 pixels
  • Height 32 pixels
  • colors in RGB 565 (2 bytes per pixel)
  • Alpha channel 8 bit (1 byte per pixel)
  • datasize = 3072 = 32 x 32 x 3 bytes

@beesarecute: Do you agree?

And this seems to be the library to handle those graphics

https://github.com/lvgl/lvgl

If you just want to see the content: https://wokwi.com/projects/381952766027751425

Sketch:

/*
  Forum: https://forum.arduino.cc/t/displaying-rgb-bitmap-on-tft-from-c-file/1191496
  Wokwi: https://wokwi.com/projects/381952766027751425
*/
#include "hi.h"

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#define TFT_DC 9
#define TFT_CS 10

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

constexpr int offX = 100;
constexpr int offY = 120;

void setup() {
  Serial.begin(115200);
  Serial.println(image.width);
  Serial.println(image.height);
  tft.begin();
  tft.fillScreen(ILI9341_RED);
  decodeImage();
}

void loop() {
}



void decodeImage(){
  uint16_t a;
  uint16_t b;
  uint16_t color;
  for (int row=0; row < image.height; row++){
    for (int col=0;col < image.width;col++){
       a = pixil_frame[row*image.width*2+col*2];
       b = pixil_frame[row*image.width*2+col*2+1];
       color = a << 8 + b;
       if (color == 0) {color = ILI9341_WHITE;};
       tft.drawPixel(col+offX,row+offY,color);
    }

  }
}

The image data are too large to hold in memory for an UNO so I used a MEGA and I removed the alpha channel data which are used for transparency. That could be replaced by declaring the color R=G=B=Zero as transparent and replacing it by the background, like here

    if (color == 0) {color = ILI9341_WHITE;}

where white is used instead of black. I also added a struct to provide data like width and height.

See here for the manually modified image file
constexpr byte pixil_frame[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0xa7, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 };

/*
const lv_img_dsc_t pixil-frame-0 = {
  .header.cf = LV_IMG_CF_RGB565A8,
  .header.always_zero = 0,
  .header.reserved = 0,
  .header.w = 32,
  .header.h = 32,
  .data_size = 3072,
  .data = pixil-frame-0_map,
};
*/

struct imageType {
  int width = 32;
  int height = 32;
  long data_size = 3072;
} image;

The result looks like this
image

Might not be exactly what you want but it is a start ... :wink:

Edit: If the color is not correct change the line

color = a << 8 + b;

to

color = b << 8 + a;

thanks
I will give this a try

Just make the change of the line as mentioned above.

The sketch shows how to handle the data after the changes which I applied. If you want to use it with other image data you will have to change them accordingly.

Good luck!

Here is a version with moving images :wink:

It's just a demo. The routines can and have to be optimized for use in an application (e.g. clearing of images at the boundaries or if the images are moved upwards or downwards). But they show some principles:

On Wokwi: https://wokwi.com/projects/382087959061470209

Sketch:

/*
  Forum: https://forum.arduino.cc/t/displaying-rgb-bitmap-on-tft-from-c-file/1191496
  Wokwi: https://wokwi.com/projects/382087959061470209
*/
#include "hi.h"

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#define TFT_DC 9
#define TFT_CS 10

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

constexpr int maxNoOfImgs {10};

int yTop = 0;
int xPos = 0;
int yPos = 0;
int step  = 4;
int noOfImgs = 1;

void setup() {
  Serial.begin(115200);
  Serial.println(image.width);
  Serial.println(image.height);
  tft.begin();
}

void loop() {
  move();
}

void move() {
  for (int n = 0; n < noOfImgs; n++) {
    decodeImageAt(xPos, yPos + n * 32, ILI9341_BLACK);
  }
  xPos += step;
  if (xPos >= tft.width() - image.width || xPos < 0) {
    step = -step;
    noOfImgs++;
    if (noOfImgs > maxNoOfImgs) {
      tft.fillScreen(ILI9341_BLACK);
      noOfImgs = 1;  
    }
  }
}



void decodeImageAt(int x, int y, uint16_t bkColor) {
  uint16_t a;
  uint16_t b;
  uint16_t color;
  int myX;
  deleteTail(x, y, bkColor);
  for (int row = yTop; row < image.height; row++) {
    for (int col = 0; col < image.width; col++) {
      a = pixil_frame[row * image.width * 2 + col * 2];
      b = pixil_frame[row * image.width * 2 + col * 2 + 1];
      color = b << 8 + a;
      if (color == 0) {
        color = bkColor;
      }
      else
      {
        if (yTop == 0) {
          yTop = row;
        };  // Forget the rows on top of yTop which are completely "zero"
      }
      if (step > 0) {
        myX = col + x;
      } else {
        myX = (image.width - col) + x;
      }
      tft.drawPixel(myX, row + y, color);
    }
  }
}

void deleteTail(int x, int y, uint16_t bkColor) {
  // This routine could be replaced by tft.drawRect() ...
  if (x == 0 || x == tft.width() - image.width) {
    return;
  };
  int myX;
  for (int row = yTop; row < image.height; row++) {
    for (int col = 0; col < abs(step); col++) {
      if (step < 0) 
      {
        myX = (image.width + col) + x +1;
      } 
      else 
      {
        myX = col + x -step;
      }
      tft.drawPixel(myX, row + y, bkColor);
    }
  }
}

The file hi.h is the same as in post #5 (see "manually modified image file").

Enjoy ... :wink:

Just curious if you really need the RGB coded files ...

If ASCII coded images are ok for you it would make it much easier. I prepared a sketch that demos how you can use a simple format to create "sprites", draw and move them and modify colors:

Sketch "ASCII Simple
Main File:

/*
  Forum: https://forum.arduino.cc/t/displaying-rgb-bitmap-on-tft-from-c-file/1191496
  Wokwi: https://wokwi.com/projects/382118901174917121
*/

#include "asciiGraphs.h"

// Single sprites created from ASCII arrays
asciiImageStruct img1 {asciiImage1};
asciiImageStruct img2 {asciiImage2};


void setup() {
  Serial.begin(115200);
  tft.begin();
  tft.setRotation(1);
  img1.init();
  img2.init();

  int xCenter = (tft.width() - noOfCols) / 2;

// A single sprite is prepared for static drawing
// at different places with a different color

  img2.setXYandStepAndDelay(xCenter, 200, 0, 0);
  img2.draw();

  img2.setXY(xCenter + noOfCols, 200);
  img2.xColor = ILI9341_RED;
  img2.draw();

  img2.setXY(xCenter - noOfCols, 200);
  img2.xColor = ILI9341_GREEN;
  img2.draw();

// From here a single sprite is prepared for moving
  img1.setXYandStepAndDelay(0, 120, 4, 50);
}

void loop() {
  // move img1 every loop a step forward
  img1.move();
  // if it turns at the borders this will return TRUE
  if (img1.isTurning) {
    Serial.println("img1 has turned");
    // and than the colors of the graphics shall change
    changeColor();
  }
}

void changeColor() {
  if (img1.xColor == ILI9341_BLUE) {
    img1.xColor = ILI9341_RED;
    img1.oColor = ILI9341_BLUE;
  } else {
    img1.xColor = ILI9341_BLUE;
    img1.oColor = ILI9341_RED;
  }
}

include file for sprite handling: asciiGraphs.h

#pragma once

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#define TFT_DC 9
#define TFT_CS 10

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

constexpr int noOfRows {11};
constexpr int noOfCols {32};

typedef char asciiImgType[noOfRows][noOfCols];

#include "asciiData.h"

struct asciiImageStruct {
  asciiImgType & pixelChars;
  int xPos;
  int yPos;
  int step;
  boolean isTurning;
  uint16_t dotColor ;
  uint16_t xColor;
  uint16_t oColor;
  unsigned long lastMove;
  unsigned long moveDelay;
  void init();
  void setXY(int x, int y);
  void setStepAndDelay(int aStep, unsigned long moveDely);
  void setXYandStepAndDelay(int x, int y, int aStep,unsigned long moveDely);
  void draw();
  void move();
  void removeTail();
  void setColorsDotXO(uint16_t dotColorIn, uint16_t xColorIn, uint16_t oColorIn);
};

void asciiImageStruct::init() {
  xPos = 0;
  yPos = 0;
  dotColor = ILI9341_BLACK;
  xColor   = ILI9341_BLUE;
  oColor  = ILI9341_RED;
  isTurning = false;
  lastMove = 0;
  moveDelay = 0;
}

void asciiImageStruct::setXY(int x, int y) {
  xPos = x;
  yPos = y;
}

void asciiImageStruct::setStepAndDelay(int aStep, unsigned long moveDely) {
  step = aStep;
  moveDelay = moveDely;
}

void asciiImageStruct::setXYandStepAndDelay(int x, int y, int aStep, unsigned long moveDely) {
  setXY(x, y);
  setStepAndDelay(aStep, moveDely);
}

void asciiImageStruct::setColorsDotXO(uint16_t dotColorIn, uint16_t xColorIn, uint16_t oColorIn) {
  dotColor = dotColorIn;
  xColor   = xColorIn;
  oColor = oColorIn;
}

void asciiImageStruct::removeTail() {
  int myX;
  for (int row = 0; row < noOfRows; row++) {
    for (int col = 0; col < abs(step) ; col++) {
      if (step < 0) {
        myX = xPos + noOfCols + col;
      } else {
        myX = xPos - col;
      }
      tft.drawPixel(myX, row + yPos, dotColor);
    }
  }
}

void asciiImageStruct::move() {
  if (step == 0) {
    return;
  }
  if (millis() - lastMove >= moveDelay) {
    lastMove = millis();
    isTurning = false;
    if (xPos < 0 ) {
      step = abs(step);
      isTurning = true;
    }
    if (xPos > tft.width() - noOfCols) {
      step = -abs(step);
      isTurning = true;
    }
    xPos += step;
    removeTail();
    draw();
  }
}


void asciiImageStruct::draw() {
  uint16_t color;
  int myX;
  for (int row = 0; row < noOfRows; row++) {
    for (int col = 0; col < noOfCols; col++) {
      switch (char(pixelChars[row][col])) {
        case '.' : color = dotColor;
          break;
        case 'X' : color = xColor;
          break;
        case 'O' : color = oColor;
          break;
        default:
          color = ILI9341_WHITE;
      }
      if (step >= 0) {
        myX = col + xPos;
      } else {
        myX = xPos  + noOfCols - col;
      }
      tft.drawPixel(myX, row + yPos, color);
    }
  }
}

/*
  // Color definitions
  #define ILI9341_BLACK 0x0000       ///<   0,   0,   0
  #define ILI9341_NAVY 0x000F        ///<   0,   0, 123
  #define ILI9341_DARKGREEN 0x03E0   ///<   0, 125,   0
  #define ILI9341_DARKCYAN 0x03EF    ///<   0, 125, 123
  #define ILI9341_MAROON 0x7800      ///< 123,   0,   0
  #define ILI9341_PURPLE 0x780F      ///< 123,   0, 123
  #define ILI9341_OLIVE 0x7BE0       ///< 123, 125,   0
  #define ILI9341_LIGHTGREY 0xC618   ///< 198, 195, 198
  #define ILI9341_DARKGREY 0x7BEF    ///< 123, 125, 123
  #define ILI9341_BLUE 0x001F        ///<   0,   0, 255
  #define ILI9341_GREEN 0x07E0       ///<   0, 255,   0
  #define ILI9341_CYAN 0x07FF        ///<   0, 255, 255
  #define ILI9341_RED 0xF800         ///< 255,   0,   0
  #define ILI9341_MAGENTA 0xF81F     ///< 255,   0, 255
  #define ILI9341_YELLOW 0xFFE0      ///< 255, 255,   0
  #define ILI9341_WHITE 0xFFFF       ///< 255, 255, 255
  #define ILI9341_ORANGE 0xFD20      ///< 255, 165,   0
  #define ILI9341_GREENYELLOW 0xAFE5 ///< 173, 255,  41
  #define ILI9341_PINK 0xFC18        ///< 255, 130, 198

*/

Include file for the graphics: asciiData.h

#pragma once

asciiImgType asciiImage1  = {
  "................................",
  "........XXXXXXXXXXXXXX..........",
  "........XXXXXXXOXXXXXXXXXXXXXXX.",
  ".............XXOXXXXXXX.........",
  "..XXXXXXXXXX..XOXXXXX...........",
  ".XXXXXXXXXXXXXXOXXXXXXXXXX......",
  ".XXXXXXXXXXOOOOOOOOOXXXXXXX.....",
  ".XXXXXXXXXXXXXXOXXXXXXXXXXXX....",
  "..XXXXXXXXXXXXXOXXXXXXXXXXX.....",
  "...XXXXXXXXXXXXOXXXXXXXXXX......",
  "................................"
};

char asciiImage2[noOfRows][noOfCols]  = {
  "................................",
  "...........XXXXXXXXXX...........",
  "..........XXXXX..XXXXX..........",
  "...........XXXX..XXXX...........",
  "...........XXXXXXXXXX...........",
  "........XXXXXXXXXXXXXXXX........",
  "........XXXXXXXXXXXXXXXX........",
  "........XXXXXXXXXXXXXXXX........",
  "........XXX..........XXX........",
  "........XXX..........XXX........",
  "................................"
};

And this is a more complex use:

Sketch with more Sprites
/*
  Forum: https://forum.arduino.cc/t/displaying-rgb-bitmap-on-tft-from-c-file/1191496
  Wokwi: https://wokwi.com/projects/382120404275155969
*/

#include "asciiGraphs.h"

// Single sprites created from ASCII arrays
asciiImageStruct img1 {asciiImage1};
asciiImageStruct img2 {asciiImage2};
asciiImageStruct img3 {asciiImage1};
asciiImageStruct img4 {asciiImage1};

// An array of sprites
constexpr int noOfSprites {3};
asciiImageStruct sprite[noOfSprites] {
  {asciiImage1},
  {asciiImage1},
  {asciiImage1}
};

uint16_t xColors[noOfSprites] {
  ILI9341_YELLOW,
  ILI9341_ORANGE,
  ILI9341_PINK
};


void setup() {
  Serial.begin(115200);
  tft.begin();
  tft.setRotation(1);
  img1.init();
  img2.init();
  img3.init();
  img4.init();


  // Single sprites prepared for static drawing

  int xCenter = (tft.width() - noOfCols) / 2;

  img2.setXYandStepAndDelay(xCenter, 200, 0, 0);
  img2.draw();

  img2.setXY(xCenter - noOfCols, 200);
  img2.xColor = ILI9341_RED;
  img2.draw();

  img2.setXY(xCenter + noOfCols, 200);
  img2.xColor = ILI9341_GREEN;
  img2.draw();

  img2.setXY(xCenter - 2 * noOfCols, 200);
  img2.xColor = ILI9341_CYAN;
  img2.draw();

  img2.setXY(xCenter + 2 * noOfCols, 200);
  img2.xColor = ILI9341_PURPLE;
  img2.draw();

  img4.setXYandStepAndDelay(xCenter + 4 * noOfCols, 200, -1, 0);  //step < 0 -> Sprite is drawn right to left
  img4.xColor = ILI9341_CYAN;
  img4.oColor = ILI9341_BLUE;
  img4.draw();

  img4.setXYandStepAndDelay(xCenter - 4 * noOfCols, 200, 0, 0); //step >= 0 -> Sprite is drawn left to right
  img4.xColor = ILI9341_MAGENTA;
  img4.oColor = ILI9341_DARKGREY;
  img4.draw();

  // From here single sprites prepared for moving

  img4.setXYandStepAndDelay(xCenter, 80, -4, 10);
  img4.xColor = ILI9341_CYAN;
  img4.oColor = ILI9341_BLUE;

  img1.setXYandStepAndDelay(0, 120, 4, 10);

  img3.setXYandStepAndDelay(tft.width() - 32, 160, -4, 10);
  img3.xColor = ILI9341_GREEN;
  img3.oColor = ILI9341_GREEN;

  // Array of sprites prepared for moving
  for (int i = 0; i < noOfSprites; i++) {
    sprite[i].init();
    sprite[i].setXYandStepAndDelay(i * noOfCols, i * (noOfRows + 16), 2 + i * 2, 10);
    sprite[i].xColor = xColors[i];
  }

}

void loop() {
  img1.move();
  img3.move();
  img4.move();
  for (int i = 0; i < noOfSprites; i++) {
    sprite[i].move();
  }
  checkTurning();
}

void checkTurning() {
  if (img1.isTurning) {
    Serial.println("img1 has turned");
    changeColor();
  }
  if (img3.isTurning) {
    Serial.println("img3 has turned");
  }
  if (img4.isTurning) {
    Serial.println("img4 has turned");
  }
  for (int i = 0; i < noOfSprites; i++) {
    if (sprite[i].isTurning) {
      Serial.print("Sprite ");
      Serial.print(i + 1);
      Serial.println(" has turned");
    }

  }
}

void changeColor() {
  if (img1.xColor == ILI9341_BLUE) {
    img1.xColor = ILI9341_RED;
    img1.oColor = ILI9341_BLUE;
  } else {
    img1.xColor = ILI9341_BLUE;
    img1.oColor = ILI9341_RED;
  }
}

Use the same includes as in the simple example!

Both sketches can be tested on Wokwi:

image

A sprite is drawn with ASCII characters

asciiImgType asciiImage1  = {
  "................................",
  "........XXXXXXXXXXXXXX..........",
  "........XXXXXXXOXXXXXXXXXXXXXXX.",
  ".............XXOXXXXXXX.........",
  "..XXXXXXXXXX..XOXXXXX...........",
  ".XXXXXXXXXXXXXXOXXXXXXXXXX......",
  ".XXXXXXXXXXOOOOOOOOOXXXXXXX.....",
  ".XXXXXXXXXXXXXXOXXXXXXXXXXXX....",
  "..XXXXXXXXXXXXXOXXXXXXXXXXX.....",
  "...XXXXXXXXXXXXOXXXXXXXXXX......",
  "................................"
};

where the character

  • . (dot) is used for the background color
  • X (capital x) for foreground color 1
  • O (capital o) for foreground color 2

In this example

  • the width (no of columns) is set to 32 characters as a constant,
  • the height (no of rows) is in this example set to 11 rows as a constant.

Enjoy!

is it possible you could post a wiring diagram or tell me the connections or should this wiring work
VCC to 5V
GND to GND
CS to 10
reset to 8
A0 to 9
SDA to 11
SCK to 13

for the complex example

thank you by the way

Your welcome...

The pins depend your microcontroller board (Uno, Nano, ...?) and the pinout of your display.

Which controller do you use?
Could you also post either the complete name/brand of your display or a weblink to the product?

What you posted seems to fit to an Uno.

The sketches will not work immediately with your board as they use a different display driver.

I can try to make a version for your display .

Ok. Here it is (it compiles but I cannot test it as I do not have a ST7735 display):

Main sketch:

/*
  Forum: https://forum.arduino.cc/t/displaying-rgb-bitmap-on-tft-from-c-file/1191496
  Wokwi: https://wokwi.com/projects/382131471070749697
*/

// If the next line is uncommented it will compile for  ILI9341 as used on Wokwi
//#define WOKWI  
// otherwise for a ST7735 displays


#include "asciiGraphs.h"

// Single sprites created from ASCII arrays
asciiImageStruct img1 {asciiImage1};
asciiImageStruct img2 {asciiImage2};
asciiImageStruct img3 {asciiImage1};
asciiImageStruct img4 {asciiImage1};

// An array of sprites
constexpr int noOfSprites {3};
asciiImageStruct sprite[noOfSprites] {
  {asciiImage1},
  {asciiImage1},
  {asciiImage1}
};

uint16_t xColors[noOfSprites] {
  ILI9341_YELLOW,
  ILI9341_ORANGE,
  ILI9341_PINK
};


void setup() {
  Serial.begin(115200);
#ifdef WOKWI  
  tft.begin();
#else   
  tft.initR(INITR_BLACKTAB);      // Init ST7735S chip, black tab
#endif  
  tft.setRotation(1);
  img1.init();
  img2.init();
  img3.init();
  img4.init();


  // Single sprites prepared for static drawing

  int xCenter = (tft.width() - noOfCols) / 2;

  img2.setXYandStepAndDelay(xCenter, 200, 0, 0);
  img2.draw();

  img2.setXY(xCenter - noOfCols, 200);
  img2.xColor = ILI9341_RED;
  img2.draw();

  img2.setXY(xCenter + noOfCols, 200);
  img2.xColor = ILI9341_GREEN;
  img2.draw();

  img2.setXY(xCenter - 2 * noOfCols, 200);
  img2.xColor = ILI9341_CYAN;
  img2.draw();

  img2.setXY(xCenter + 2 * noOfCols, 200);
  img2.xColor = ILI9341_PURPLE;
  img2.draw();

  img4.setXYandStepAndDelay(xCenter + 4 * noOfCols, 200, -1, 0);  //step < 0 -> Sprite is drawn right to left
  img4.xColor = ILI9341_CYAN;
  img4.oColor = ILI9341_BLUE;
  img4.draw();

  img4.setXYandStepAndDelay(xCenter - 4 * noOfCols, 200, 0, 0); //step >= 0 -> Sprite is drawn left to right
  img4.xColor = ILI9341_MAGENTA;
  img4.oColor = ILI9341_DARKGREY;
  img4.draw();

  // From here single sprites prepared for moving

  img4.setXYandStepAndDelay(xCenter, 80, -4, 10);
  img4.xColor = ILI9341_CYAN;
  img4.oColor = ILI9341_BLUE;

  img1.setXYandStepAndDelay(0, 120, 4, 10);

  img3.setXYandStepAndDelay(tft.width() - 32, 160, -4, 10);
  img3.xColor = ILI9341_GREEN;
  img3.oColor = ILI9341_GREEN;

  // Array of sprites prepared for moving
  for (int i = 0; i < noOfSprites; i++) {
    sprite[i].init();
    sprite[i].setXYandStepAndDelay(i * noOfCols, i * (noOfRows + 16), 2 + i * 2, 10);
    sprite[i].xColor = xColors[i];
  }

}

void loop() {
  img1.move();
  img3.move();
  img4.move();
  for (int i = 0; i < noOfSprites; i++) {
    sprite[i].move();
  }
  checkTurning();
}

void checkTurning() {
  if (img1.isTurning) {
    Serial.println("img1 has turned");
    changeColor();
  }
  if (img3.isTurning) {
    Serial.println("img3 has turned");
  }
  if (img4.isTurning) {
    Serial.println("img4 has turned");
  }
  for (int i = 0; i < noOfSprites; i++) {
    if (sprite[i].isTurning) {
      Serial.print("Sprite ");
      Serial.print(i + 1);
      Serial.println(" has turned");
    }

  }
}

void changeColor() {
  if (img1.xColor == ILI9341_BLUE) {
    img1.xColor = ILI9341_RED;
    img1.oColor = ILI9341_BLUE;
  } else {
    img1.xColor = ILI9341_BLUE;
    img1.oColor = ILI9341_RED;
  }
}

asciiGraphs.h:

#pragma once

#include "SPI.h"
#include "Adafruit_GFX.h"



#ifdef WOKWI

#include "Adafruit_ILI9341.h"
#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

#else

#include "Adafruit_ST7735.h"
#include "colordefs.h"
#define TFT_CS        10
#define TFT_RST        9 
#define TFT_DC          8
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

#endif



constexpr int noOfRows {11};
constexpr int noOfCols {32};

typedef char asciiImgType[noOfRows][noOfCols];

#include "asciiData.h"

struct asciiImageStruct {
  asciiImgType & pixelChars;
  int xPos;
  int yPos;
  int step;
  boolean isTurning;
  uint16_t dotColor ;
  uint16_t xColor;
  uint16_t oColor;
  unsigned long lastMove;
  unsigned long moveDelay;
  void init();
  void setXY(int x, int y);
  void setStepAndDelay(int aStep, unsigned long moveDely);
  void setXYandStepAndDelay(int x, int y, int aStep,unsigned long moveDely);
  void draw();
  void move();
  void removeTail();
  void setColorsDotXO(uint16_t dotColorIn, uint16_t xColorIn, uint16_t oColorIn);
};

void asciiImageStruct::init() {
  xPos = 0;
  yPos = 0;
  dotColor = ILI9341_BLACK;
  xColor   = ILI9341_BLUE;
  oColor  = ILI9341_RED;
  isTurning = false;
  lastMove = 0;
  moveDelay = 0;
}

void asciiImageStruct::setXY(int x, int y) {
  xPos = x;
  yPos = y;
}

void asciiImageStruct::setStepAndDelay(int aStep, unsigned long moveDely) {
  step = aStep;
  moveDelay = moveDely;
}

void asciiImageStruct::setXYandStepAndDelay(int x, int y, int aStep, unsigned long moveDely) {
  setXY(x, y);
  setStepAndDelay(aStep, moveDely);
}

void asciiImageStruct::setColorsDotXO(uint16_t dotColorIn, uint16_t xColorIn, uint16_t oColorIn) {
  dotColor = dotColorIn;
  xColor   = xColorIn;
  oColor = oColorIn;
}

void asciiImageStruct::removeTail() {
  int myX;
  for (int row = 0; row < noOfRows; row++) {
    for (int col = 0; col < abs(step) ; col++) {
      if (step < 0) {
        myX = xPos + noOfCols + col;
      } else {
        myX = xPos - col;
      }
      tft.drawPixel(myX, row + yPos, dotColor);
    }
  }
}

void asciiImageStruct::move() {
  if (step == 0) {
    return;
  }
  if (millis() - lastMove >= moveDelay) {
    lastMove = millis();
    isTurning = false;
    if (xPos < 0 ) {
      step = abs(step);
      isTurning = true;
    }
    if (xPos > tft.width() - noOfCols) {
      step = -abs(step);
      isTurning = true;
    }
    xPos += step;
    removeTail();
    draw();
  }
}


void asciiImageStruct::draw() {
  uint16_t color;
  int myX;
  for (int row = 0; row < noOfRows; row++) {
    for (int col = 0; col < noOfCols; col++) {
      switch (char(pixelChars[row][col])) {
        case '.' : color = dotColor;
          break;
        case 'X' : color = xColor;
          break;
        case 'O' : color = oColor;
          break;
        default:
          color = ILI9341_WHITE;
      }
      if (step >= 0) {
        myX = col + xPos;
      } else {
        myX = xPos  + noOfCols - col;
      }
      tft.drawPixel(myX, row + yPos, color);
    }
  }
}

asciiData.h:

#pragma once

asciiImgType asciiImage1  = {
  "................................",
  "........XXXXXXXXXXXXXX..........",
  "........XXXXXXXOXXXXXXXXXXXXXXX.",
  ".............XXOXXXXXXX.........",
  "..XXXXXXXXXX..XOXXXXX...........",
  ".XXXXXXXXXXXXXXOXXXXXXXXXX......",
  ".XXXXXXXXXXOOOOOOOOOXXXXXXX.....",
  ".XXXXXXXXXXXXXXOXXXXXXXXXXXX....",
  "..XXXXXXXXXXXXXOXXXXXXXXXXX.....",
  "...XXXXXXXXXXXXOXXXXXXXXXX......",
  "................................"
};

char asciiImage2[noOfRows][noOfCols]  = {
  "................................",
  "...........XXXXXXXXXX...........",
  "..........XXXXX..XXXXX..........",
  "...........XXXX..XXXX...........",
  "...........XXXXXXXXXX...........",
  "........XXXXXXXXXXXXXXXX........",
  "........XXXXXXXXXXXXXXXX........",
  "........XXXXXXXXXXXXXXXX........",
  "........XXX..........XXX........",
  "........XXX..........XXX........",
  "................................"
};

New now to define the ILI-colors:
colordefs.h:

#pragma once

#define ILI9341_BLACK 0x0000       ///<   0,   0,   0
#define ILI9341_NAVY 0x000F        ///<   0,   0, 123
#define ILI9341_DARKGREEN 0x03E0   ///<   0, 125,   0
#define ILI9341_DARKCYAN 0x03EF    ///<   0, 125, 123
#define ILI9341_MAROON 0x7800      ///< 123,   0,   0
#define ILI9341_PURPLE 0x780F      ///< 123,   0, 123
#define ILI9341_OLIVE 0x7BE0       ///< 123, 125,   0
#define ILI9341_LIGHTGREY 0xC618   ///< 198, 195, 198
#define ILI9341_DARKGREY 0x7BEF    ///< 123, 125, 123
#define ILI9341_BLUE 0x001F        ///<   0,   0, 255
#define ILI9341_GREEN 0x07E0       ///<   0, 255,   0
#define ILI9341_CYAN 0x07FF        ///<   0, 255, 255
#define ILI9341_RED 0xF800         ///< 255,   0,   0
#define ILI9341_MAGENTA 0xF81F     ///< 255,   0, 255
#define ILI9341_YELLOW 0xFFE0      ///< 255, 255,   0
#define ILI9341_WHITE 0xFFFF       ///< 255, 255, 255
#define ILI9341_ORANGE 0xFD20      ///< 255, 165,   0
#define ILI9341_GREENYELLOW 0xAFE5 ///< 173, 255,  41
#define ILI9341_PINK 0xFC18        ///< 255, 130, 198

On Wokwi Complex Example for UNO

The wiring for the ST7735 for an UNO is prepared for this:

VCC       5V
GND      GND
CS        10
RST        9 
D/C        8   // D/C is also called A0 sometimes - Data Command
SDA       11
SCK       13

I left RST and D/C pins like they are often used in examples. If you swap them you have to change the #defines also in asciiGraphs.h at the appropriate lines.

Good luck! :wink:

P.S.: The dimensions of your display may be smaller than those of the ILI9341 (width 240, height 320). in that case some of the sprites will be out of view... Just play around with the main sketch.

It might also be helpful to add the line tft.fillScreen(0); after the initR command to get a blank background.

  tft.initR(INITR_BLACKTAB);      // Init ST7735S chip, black tab
  tft.fillScreen(0);

P.P.S: This main sketch worked fine (except that the colors and rotation are different) on a 0.96inch LCD with 128 by 160 pixels which I was lucky to find ... :wink:

Modified main sketch for 0.96 LCD
/*
  Forum: https://forum.arduino.cc/t/displaying-rgb-bitmap-on-tft-from-c-file/1191496
 not on Wokwi!!
*/

// If the next line is uncommented it will compile for  ILI9341 as used on Wokwi
//#define WOKWI  
// otherwise for a ST7735 displays


#include "asciiGraphs.h"

// Single sprites created from ASCII arrays
asciiImageStruct img1 {asciiImage1};
asciiImageStruct img2 {asciiImage2};

// An array of sprites
constexpr int noOfSprites {3};
asciiImageStruct sprite[noOfSprites] {
  {asciiImage1},
  {asciiImage1},
  {asciiImage1}
};

uint16_t xColors[noOfSprites] {
  ILI9341_YELLOW,
  ILI9341_ORANGE,
  ILI9341_PINK
};


void setup() {
  Serial.begin(115200);
#ifdef WOKWI  
  tft.begin();
#else   
  tft.initR(INITR_BLACKTAB);      // Init ST7735S chip, black tab
  tft.fillScreen(1);
#endif  
  tft.setRotation(1);
  img1.init();
  img2.init();
    // Single sprites prepared for static drawing

  int xCenter = (tft.width() - noOfCols) / 2;

  int yOffset = 90;
  img2.setXYandStepAndDelay(xCenter, yOffset, 0, 0);
  img2.draw();

  img2.setXY(xCenter - noOfCols, yOffset);
  img2.xColor = ILI9341_RED;
  img2.draw();

  img2.setXY(xCenter + noOfCols, yOffset);
  img2.xColor = ILI9341_GREEN;
  img2.draw();

  img2.setXY(xCenter - 2 * noOfCols, yOffset);
  img2.xColor = ILI9341_CYAN;
  img2.draw();

  img2.setXY(xCenter + 2 * noOfCols, yOffset);
  img2.xColor = ILI9341_PURPLE;
  img2.draw();

 
  // From here single sprites prepared for moving

  img1.setXYandStepAndDelay(0, 80, 4, 10);


  // Array of sprites prepared for moving
  for (int i = 0; i < noOfSprites; i++) {
    sprite[i].init();
    sprite[i].setXYandStepAndDelay(i * noOfCols, i * (noOfRows+2)+32, 2 + i * 2, 10);
    sprite[i].xColor = xColors[i];
  }

}

void loop() {
  img1.move();
  for (int i = 0; i < noOfSprites; i++) {
    sprite[i].move();
  }
  checkTurning();
}

void checkTurning() {
  if (img1.isTurning) {
    Serial.println("img1 has turned");
    changeColor();
  }
  for (int i = 0; i < noOfSprites; i++) {
    if (sprite[i].isTurning) {
      Serial.print("Sprite ");
      Serial.print(i + 1);
      Serial.println(" has turned");
    }

  }
}

void changeColor() {
  if (img1.xColor == ILI9341_BLUE) {
    img1.xColor = ILI9341_RED;
    img1.oColor = ILI9341_BLUE;
  } else {
    img1.xColor = ILI9341_BLUE;
    img1.oColor = ILI9341_RED;
  }
}
1 Like

As I found a small ST7735 display at home I was able to modify and test the sketch further.

New sketch and includes

Main Sketch

/*
  Forum: https://forum.arduino.cc/t/displaying-rgb-bitmap-on-tft-from-c-file/1191496
  Wokwi: https://wokwi.com/projects/382188352744225793
*/

// If the next line is uncommented it will compile for  ILI9341 as used on Wokwi
//#define ILI9341DISPLAY
// otherwise for a ST7735 displays


#ifdef ILI9341DISPLAY
constexpr int yOffStatic {200};
constexpr int yOffMoving {32};
#else

constexpr int yOffStatic {90};
constexpr int yOffMoving {32};

#endif

#include "asciiGraphs.h"

// Single sprites created from ASCII arrays
asciiImageStruct img1 {asciiImage1};
asciiImageStruct img2 {asciiImage2};

// An array of sprites
constexpr int noOfSprites {3};
asciiImageStruct sprite[noOfSprites] {
  {asciiImage1},
  {asciiImage1},
  {asciiImage1}
};

uint16_t xColors[noOfSprites] {
  MY_YELLOW,
  MY_ORANGE,
  MY_PINK
};


void setup() {
  Serial.begin(115200);
#ifdef ILI9341DISPLAY
  tft.begin();
#else
  tft.initR(INITR_BLACKTAB);      // Init ST7735S chip, black tab
  tft.invertDisplay(true);
  tft.fillScreen(MY_BLACK);
  Serial.println(tft.width());
  Serial.println(tft.height());
#endif
  tft.setRotation(1);
  img1.init();
  img2.init();
  // Single sprites prepared for static drawing

  int xCenter = (tft.width() - noOfCols) / 2;

  img2.setXYandStepAndDelay(xCenter, yOffStatic, 0, 0);
  img2.draw();

  img2.setXY(xCenter - noOfCols, yOffStatic);
  img2.xColor = MY_RED;
  img2.draw();

  img2.setXY(xCenter + noOfCols, yOffStatic);
  img2.xColor = MY_GREEN;
  img2.draw();

  img2.setXY(xCenter - 2 * noOfCols, yOffStatic);
  img2.xColor = MY_CYAN;
  img2.draw();

  img2.setXY(xCenter + 2 * noOfCols, yOffStatic);
  img2.xColor = MY_PURPLE;
  img2.draw();


  // From here single sprites prepared for moving
  // Thissprite starts from left to right at xPos = 0 and yPos = 80 with 4 pixel steps and
  // moves earliest every 10 ms
  img1.setXYandStepAndDelay(0, 80, 4, 10);


  // Array of sprites prepared for moving
  // xPos = i * noOfCols -> First sprite starts a zero x, the second one sprite width to the right etc.
  // yPos =  i * (noOfRows+2)+yOffMoving -> First sprite starts a yOffMoving,
  //                                        the second sprite one sprite height plus 2 deeper etc.
  // step = 2 + i *2 -> The first sprite uses 2 pixel steps, the second 4, the third 6 steps
  // delay = 10 -> all sprites move earliest after 10 ms

  for (int i = 0; i < noOfSprites; i++) {
    sprite[i].init();
    sprite[i].setXYandStepAndDelay(i * noOfCols, i * (noOfRows + 2) + yOffMoving, 2 + i * 2, 10);
    sprite[i].xColor = xColors[i];
  }

}

void loop() {
  img1.move();
  for (int i = 0; i < noOfSprites; i++) {
    sprite[i].move();
  }
  checkTurning();
}


// The function checkTurning() checks whether the sprite has changed direction
// If so, the function changeColor() is called. This function toggles the colors of the sprite img1
// It starts from right to left with blue body and a red cross
// At the left border the color switches to red body and a blue cross and vice versa at the right border
// For img1 and all other moving sprites a Serial messages shows that they have turned. 
// For the sprite array the xPos is also checked to determine whether the sprite turned at the left or
// at the right border just to demonstrate how to integrate further functionality

void checkTurning() {
  if (img1.isTurning) {
    Serial.println("img1 has turned");
    changeColor();
  }
  for (int i = 0; i < noOfSprites; i++) {
    if (sprite[i].isTurning) {
      Serial.print("Sprite ");
      Serial.print(i + 1);
      Serial.print(" has turned at ");
      if (sprite[i].xPos < 10) {
        Serial.println("left");
      } else {
        Serial.println("right");
      }
    }

  }
}

void changeColor() {
  if (img1.xColor == MY_BLUE) {
    img1.xColor = MY_RED;
    img1.oColor = MY_BLUE;
  } else {
    img1.xColor = MY_BLUE;
    img1.oColor = MY_RED;
  }
}

asciiGraphs.h

#pragma once

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "colordefs.h"

#ifdef ILI9341DISPLAY

#include "Adafruit_ILI9341.h"
#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

#else

#include "Adafruit_ST7735.h"
#define TFT_CS        10
#define TFT_RST        8 
#define TFT_DC         7
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

#endif



constexpr int noOfRows {11};
constexpr int noOfCols {32};

typedef char asciiImgType[noOfRows][noOfCols];

#include "asciiData.h"

struct asciiImageStruct {
  asciiImgType & pixelChars;
  int xPos;
  int yPos;
  int step;
  boolean isTurning;
  uint16_t dotColor ;
  uint16_t xColor;
  uint16_t oColor;
  unsigned long lastMove;
  unsigned long moveDelay;
  void init();
  void setXY(int x, int y);
  void setStepAndDelay(int aStep, unsigned long moveDely);
  void setXYandStepAndDelay(int x, int y, int aStep,unsigned long moveDely);
  void draw();
  void move();
  void removeTail();
  void setColorsDotXO(uint16_t dotColorIn, uint16_t xColorIn, uint16_t oColorIn);
};

void asciiImageStruct::init() {
  xPos = 0;
  yPos = 0;
  dotColor = MY_BLACK;
  xColor   = MY_BLUE;
  oColor  = MY_RED;
  isTurning = false;
  lastMove = 0;
  moveDelay = 0;
}

void asciiImageStruct::setXY(int x, int y) {
  xPos = x;
  yPos = y;
}

void asciiImageStruct::setStepAndDelay(int aStep, unsigned long moveDely) {
  step = aStep;
  moveDelay = moveDely;
}

void asciiImageStruct::setXYandStepAndDelay(int x, int y, int aStep, unsigned long moveDely) {
  setXY(x, y);
  setStepAndDelay(aStep, moveDely);
}

void asciiImageStruct::setColorsDotXO(uint16_t dotColorIn, uint16_t xColorIn, uint16_t oColorIn) {
  dotColor = dotColorIn;
  xColor   = xColorIn;
  oColor = oColorIn;
}

void asciiImageStruct::removeTail() {
  int myX;
  for (int row = 0; row < noOfRows; row++) {
    for (int col = 0; col < abs(step) ; col++) {
      if (step < 0) {
        myX = xPos + noOfCols + col;
      } else {
        myX = xPos - col;
      }
      tft.drawPixel(myX, row + yPos, dotColor);
    }
  }
}

void asciiImageStruct::move() {
  if (step == 0) {
    return;
  }
  if (millis() - lastMove >= moveDelay) {
    lastMove = millis();
    isTurning = false;
    if (xPos < 0 ) {
      step = abs(step);
      isTurning = true;
    }
    if (xPos > tft.width() - noOfCols) {
      step = -abs(step);
      isTurning = true;
    }
    xPos += step;
    removeTail();
    draw();
  }
}


void asciiImageStruct::draw() {
  uint16_t color;
  int myX;
  for (int row = 0; row < noOfRows; row++) {
    for (int col = 0; col < noOfCols; col++) {
      switch (char(pixelChars[row][col])) {
        case '.' : color = dotColor;
          break;
        case 'X' : color = xColor;
          break;
        case 'O' : color = oColor;
          break;
        default:
          color = MY_WHITE;
      }
      if (step >= 0) {
        myX = col + xPos;
      } else {
        myX = xPos  + noOfCols - col;
      }
      tft.drawPixel(myX, row + yPos, color);
    }
  }
}

colordefs.h

#pragma once


#ifdef ILI9341DISPLAY

// ILI9341 Colors RGB565
#define MY_BLACK 0x0000       ///<   0,   0,   0
#define MY_NAVY 0x000F        ///<   0,   0, 123
#define MY_DARKGREEN 0x03E0   ///<   0, 125,   0
#define MY_DARKCYAN 0x03EF    ///<   0, 125, 123
#define MY_MAROON 0x7800      ///< 123,   0,   0
#define MY_PURPLE 0x780F      ///< 123,   0, 123
#define MY_OLIVE 0x7BE0       ///< 123, 125,   0
#define MY_LIGHTGREY 0xC618   ///< 198, 195, 198
#define MY_DARKGREY 0x7BEF    ///< 123, 125, 123
#define MY_BLUE 0x001F        ///<   0,   0, 255
#define MY_GREEN 0x07E0       ///<   0, 255,   0
#define MY_CYAN 0x07FF        ///<   0, 255, 255
#define MY_RED 0xF800         ///< 255,   0,   0
#define MY_MAGENTA 0xF81F     ///< 255,   0, 255
#define MY_YELLOW 0xFFE0      ///< 255, 255,   0
#define MY_WHITE 0xFFFF       ///< 255, 255, 255
#define MY_ORANGE 0xFD20      ///< 255, 165,   0
#define MY_GREENYELLOW 0xAFE5 ///< 173, 255,  41
#define MY_PINK 0xFC18        ///< 255, 130, 198

#else

// ST7735 Colors BGR565
#define MY_BLACK        0x0000
#define MY_DARKGREEN    0x03E0
#define MY_DARKCYAN     0x7BE0
#define MY_MAROON       0x000F
#define MY_PURPLE       0x780F
#define MY_OLIV         0x03EF
#define MY_LIGHTGREY    0xC618
#define MY_DARKGREY     0x7BEF
#define MY_BLUE         0xF800
#define MY_GREEN        0x07E0
#define MY_CYAN         0xFFE0
#define MY_RED          0x001F
#define MY_MAGENTA      0xF81F
#define MY_YELLOW       0x7FF
#define MY_WHITE        0xFFFF
#define MY_ORANGE       0x053F
#define MY_GREENYELLOW  0x2FF5
#define MY_PINK         0xC41F

#endif

asciiData.h

#pragma once

asciiImgType asciiImage1  = {
  "................................",
  "........XXXXXXXXXXXXXX..........",
  "........XXXXXXXOXXXXXXXXXXXXXXX.",
  ".............XXOXXXXXXX.........",
  "..XXXXXXXXXX..XOXXXXX...........",
  ".XXXXXXXXXXXXXXOXXXXXXXXXX......",
  ".XXXXXXXXXXOOOOOOOOOXXXXXXX.....",
  ".XXXXXXXXXXXXXXOXXXXXXXXXXXX....",
  "..XXXXXXXXXXXXXOXXXXXXXXXXX.....",
  "...XXXXXXXXXXXXOXXXXXXXXXX......",
  "................................"
};

char asciiImage2[noOfRows][noOfCols]  = {
  "................................",
  "...........XXXXXXXXXX...........",
  "..........XXXXX..XXXXX..........",
  "...........XXXX..XXXX...........",
  "...........XXXXXXXXXX...........",
  "........XXXXXXXXXXXXXXXX........",
  "........XXXXXXXXXXXXXXXX........",
  "........XXXXXXXXXXXXXXXX........",
  "........XXX..........XXX........",
  "........XXX..........XXX........",
  "................................"
};

The main changes are

  • Calculated BGR565 colors from RGB565 and created specific #defines for ILI9341 and St7735
  • Added tft.invertDisplay(true); for the ST7735 to get a black background
  • Changed the code to use the appropriate color values
  • Added constants to handle the different height of the displays (could be done by calculation, but that's an issue for future optimization)
  • Added some comments and the demo of "how to find out where the sprite turned"

The sketch can be tested on Wokwi: New ASCII Complex UNO

Have fun!

:wink:

1 Like

I am using an off brand uno (ELEGOO UNO R3)

I got it to work by putting

 tft.fillScreen(0);

That's great news :slight_smile:

I also had to use the RGB565 instead of BGR565 By changing

#ifdef ILI9341DISPLAY 

to
#ifndef ILI9341DISPLAY
to get the right colours

Then your device works different than my OLED. But that's irrelevant as long as it works now for you.

Would be interesting to know the brand and type of your display, e.g. a web link to the product.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.