#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#include <SD.h>
// -------------------------
// Pin configuration
// -------------------------
#define TFT_CS 10
#define TFT_RST 8
#define TFT_DC 9
#define SD_CS 4
// -------------------------
// TFT object
// -------------------------
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
// Buffer size
#define BUFFPIXEL 20
// ============================================================
// SETUP
// ============================================================
void setup() {
Serial.begin(9600);
Serial.println();
Serial.println("Starting...");
// Initialize TFT
tft.initR(INITR_BLACKTAB);
// Landscape mode
tft.setRotation(1);
// Clear screen
tft.fillScreen(ST77XX_BLACK);
Serial.println("TFT initialized.");
// Initialize SD card
Serial.print("Initializing SD card...");
if (!SD.begin(SD_CS)) {
Serial.println("FAILED!");
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_RED);
tft.setTextSize(2);
tft.setCursor(10, 30);
tft.println("SD ERROR");
while (1);
}
Serial.println("OK!");
tft.fillScreen(ST77XX_BLACK);
Serial.println("System ready.");
}
// ============================================================
// LOOP
// ============================================================
void loop() {
bmpDraw("logo.bmp", 0, 0);
delay(3000);
bmpDraw("mezapos.bmp", 0, 0);
delay(3000);
bmpDraw("sparti.bmp", 0, 0);
delay(3000);
bmpDraw("mani.bmp", 0, 0);
delay(3000);
bmpDraw("lisbon.bmp", 0, 0);
delay(3000);
}
// ============================================================
// DRAW BMP FILE
// ============================================================
void bmpDraw(const char *filename, uint8_t x, uint8_t y) {
File bmpFile;
int bmpWidth;
int bmpHeight;
uint8_t bmpDepth;
uint32_t bmpImageoffset;
uint32_t rowSize;
uint8_t sdbuffer[3 * BUFFPIXEL];
uint8_t buffidx = sizeof(sdbuffer);
boolean goodBmp = false;
boolean flip = true;
int w, h;
int row, col;
uint8_t r, g, b;
uint32_t pos = 0;
uint32_t startTime = millis();
// Check position
if ((x >= tft.width()) || (y >= tft.height())) {
return;
}
Serial.println();
Serial.print("Loading image: ");
Serial.println(filename);
// ----------------------------------------------------------
// Open BMP file
// ----------------------------------------------------------
bmpFile = SD.open(filename);
if (!bmpFile) {
Serial.print("File not found: ");
Serial.println(filename);
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_RED);
tft.setTextSize(2);
tft.setCursor(5, 20);
tft.println("FILE ERROR");
return;
}
// ----------------------------------------------------------
// BMP header
// ----------------------------------------------------------
if (read16(bmpFile) == 0x4D42) {
Serial.print("File size: ");
Serial.println(read32(bmpFile));
// Creator bytes
read32(bmpFile);
// Image data offset
bmpImageoffset = read32(bmpFile);
Serial.print("Image offset: ");
Serial.println(bmpImageoffset);
// --------------------------------------------------------
// DIB header
// --------------------------------------------------------
uint32_t headerSize = read32(bmpFile);
Serial.print("Header size: ");
Serial.println(headerSize);
bmpWidth = (int)read32(bmpFile);
bmpHeight = (int)read32(bmpFile);
Serial.print("Width: ");
Serial.println(bmpWidth);
Serial.print("Height: ");
Serial.println(bmpHeight);
// Number of planes
if (read16(bmpFile) == 1) {
// Bits per pixel
bmpDepth = read16(bmpFile);
Serial.print("Bit depth: ");
Serial.println(bmpDepth);
// Compression
uint32_t compression = read32(bmpFile);
// ------------------------------------------------------
// Only 24-bit uncompressed BMP supported
// ------------------------------------------------------
if ((bmpDepth == 24) && (compression == 0)) {
goodBmp = true;
Serial.print("Image size: ");
Serial.print(bmpWidth);
Serial.print(" x ");
Serial.println(bmpHeight);
// ----------------------------------------------------
// BMP rows are padded to 4-byte boundary
// ----------------------------------------------------
rowSize = (bmpWidth * 3 + 3) & ~3;
// ----------------------------------------------------
// Negative height means top-to-bottom BMP
// ----------------------------------------------------
if (bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
// ----------------------------------------------------
// Image dimensions
// ----------------------------------------------------
w = bmpWidth;
h = bmpHeight;
// Clip image to display
if ((x + w - 1) >= tft.width()) {
w = tft.width() - x;
}
if ((y + h - 1) >= tft.height()) {
h = tft.height() - y;
}
// ----------------------------------------------------
// Set display window
// ----------------------------------------------------
tft.setAddrWindow(
x,
y,
x + w - 1,
y + h - 1
);
// ----------------------------------------------------
// Read every row
// ----------------------------------------------------
for (row = 0; row < h; row++) {
// Calculate position of row in BMP
if (flip) {
pos = bmpImageoffset +
(bmpHeight - 1 - row) *
rowSize;
} else {
pos = bmpImageoffset +
row * rowSize;
}
// Move file pointer
if (bmpFile.position() != pos) {
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer);
}
// --------------------------------------------------
// Read every pixel
// --------------------------------------------------
for (col = 0; col < w; col++) {
// Need more data?
if (buffidx >= sizeof(sdbuffer)) {
bmpFile.read(
sdbuffer,
sizeof(sdbuffer)
);
buffidx = 0;
}
// BMP stores BGR
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
// ------------------------------------------------
// IMPORTANT:
// color565() is the correct function name
// ------------------------------------------------
uint16_t color = tft.color565(r, g, b);
tft.pushColor(color);
}
}
Serial.print("Loaded in ");
Serial.print(millis() - startTime);
Serial.println(" ms");
}
}
}
// ----------------------------------------------------------
// Close file
// ----------------------------------------------------------
bmpFile.close();
if (!goodBmp) {
Serial.println("BMP format not recognized.");
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_RED);
tft.setTextSize(2);
tft.setCursor(5, 20);
tft.println("BMP ERROR");
}
}
// ============================================================
// READ 16-BIT VALUE
// ============================================================
uint16_t read16(File &f) {
uint16_t result;
result = f.read();
result |= ((uint16_t)f.read()) << 8;
return result;
}
// ============================================================
// READ 32-BIT VALUE
// ============================================================
uint32_t read32(File &f) {
uint32_t result;
result = f.read();
result |= ((uint32_t)f.read()) << 8;
result |= ((uint32_t)f.read()) << 16;
result |= ((uint32_t)f.read()) << 24;
return result; }