Arduino 2.4″ TFT LCD 扩展板显示 SD 卡 BMP 图片教程
元件清单
| Arduino UNO | ×1 |
| 2.4 英寸 TFT LCD 触摸扩展板(含 SD 卡槽) | ×1 |
| Micro SD 卡(FAT32 格式) | ×1 |
项目简介
本教程延续前两期《2.4″ TFT LCD 扩展板接线与触摸修正》和《绘图与触摸按钮实现》,重点讲解如何从 SD 卡读取 BMP 图片并在屏幕上显示。
准备工作
- 将 SD 卡插入电脑,格式化为 FAT32
- 准备 24 位 BMP 格式图片,分辨率需匹配屏幕方向:
setRotation(0)(默认竖屏):240×320 像素setRotation(1)(横屏):320×240 像素
- 将图片复制到 SD 卡根目录,记下文件名(如
Img1.bmp) - 将 SD 卡插入扩展板卡槽


库文件
使用 SPFD5408_Adafruit_GFX 与 SPFD5408_Adafruit_TFTLCD 库(随教程提供)。若示例代码出现白屏,请尝试更换适配你屏幕驱动 IC 的库版本。
代码示例 1:循环播放多张图片
#include <SPFD5408_Adafruit_GFX.h>
#include <SPFD5408_Adafruit_TFTLCD.h>
#include <SPI.h>
#include <SD.h>
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define SD_CS 10
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, A4);
void setup() {
Serial.begin(9600);
tft.reset();
uint16_t identifier = tft.readID();
pinMode(10, OUTPUT); digitalWrite(10, HIGH);
tft.begin(identifier);
if (!SD.begin(SD_CS)) { progmemPrintln(PSTR("failed!")); return; }
}
void loop() {
bmpDraw("Logo.bmp", 0, 0); delay(2000);
bmpDraw("Img2.bmp", 0, 0); delay(2000);
bmpDraw("Img3.bmp", 0, 0); delay(2000);
}
// BMP 绘制核心函数(勿动)
#define BUFFPIXEL 20
void bmpDraw(char *filename, int x, int y) {
File bmpFile;
int bmpWidth, bmpHeight;
uint8_t bmpDepth;
uint32_t bmpImageoffset, rowSize;
uint8_t sdbuffer[3*BUFFPIXEL];
uint16_t lcdbuffer[BUFFPIXEL];
uint8_t buffidx = sizeof(sdbuffer);
boolean goodBmp = false, flip = true;
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
uint8_t lcdidx = 0;
boolean first = true;
if((x >= tft.width()) || (y >= tft.height())) return;
Serial.println(); progmemPrint(PSTR("Loading image '")); Serial.print(filename); Serial.println("'");
if ((bmpFile = SD.open(filename)) == NULL) { progmemPrintln(PSTR("File not found")); return; }
if(read16(bmpFile) == 0x4D42) { // BMP 签名
progmemPrint(PSTR("File size: ")); Serial.println(read32(bmpFile));
(void)read32(bmpFile); // 忽略创建者字节
bmpImageoffset = read32(bmpFile);
progmemPrint(PSTR("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
progmemPrint(PSTR("Header size: ")); Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile); bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) { // 平面数=1
bmpDepth = read16(bmpFile);
progmemPrint(PSTR("Bit Depth: ")); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 24位无压缩
goodBmp = true;
progmemPrint(PSTR("Image size: ")); Serial.print(bmpWidth); Serial.print('x'); Serial.println(bmpHeight);
rowSize = (bmpWidth * 3 + 3) & ~3; // 4字节对齐
if(bmpHeight < 0) { bmpHeight = -bmpHeight; flip = false; }
w = bmpWidth; h = bmpHeight;
if((x+w-1) >= tft.width()) w = tft.width() - x;
if((y+h-1) >= tft.height()) h = tft.height() - y;
tft.setAddrWindow(x, y, x+w-1, y+h-1);
for (row=0; row= sizeof(sdbuffer)) {
if(lcdidx > 0) { tft.pushColors(lcdbuffer, lcdidx, first); lcdidx = 0; first = false; }
bmpFile.read(sdbuffer, sizeof(sdbuffer)); buffidx = 0;
}
b = sdbuffer[buffidx++]; g = sdbuffer[buffidx++]; r = sdbuffer[buffidx++];
lcdbuffer[lcdidx++] = tft.color565(r,g,b);
}
}
if(lcdidx > 0) tft.pushColors(lcdbuffer, lcdidx, first);
progmemPrint(PSTR("Loaded in ")); Serial.print(millis() - startTime); Serial.println(" ms");
}
}
}
bmpFile.close();
if(!goodBmp) progmemPrintln(PSTR("BMP format not recognized."));
}
// 读取 16/32 位小端数据
uint16_t read16(File f) { uint16_t result; ((uint8_t *)&result)[0] = f.read(); ((uint8_t *)&result)[1] = f.read(); return result; }
uint32_t read32(File f) { uint32_t result; ((uint8_t *)&result)[0] = f.read(); ((uint8_t *)&result)[1] = f.read(); ((uint8_t *)&result)[2] = f.read(); ((uint8_t *)&result)[3] = f.read(); return result; }
void progmemPrint(const char *str) { char c; while(c = pgm_read_byte(str++)) Serial.print(c); }
void progmemPrintln(const char *str) { progmemPrint(str); Serial.println(); }
代码示例 2:触摸切换图片(幻灯片模式)
#include <SPFD5408_Adafruit_GFX.h>
#include <SPFD5408_Adafruit_TFTLCD.h>
#include <SPI.h>
#include <SD.h>
#include <SPFD5408_TouchScreen.h>
#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif
// 触摸屏引脚(根据你的扩展板调整)
#define YP A3
#define XM A2
#define YM 9
#define XP 8
// 触摸校准值(需先运行校准程序获取)
#define TS_MINX 176
#define TS_MINY 159
#define TS_MAXX 921
#define TS_MAXY 884
#define MINPRESSURE 10
#define MAXPRESSURE 1000
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define SD_CS 10
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, A4);
char x[] = "x1.bmp"; // 文件名数组,通过修改 x[1] 实现 x1~x4.bmp 切换
void setup() {
Serial.begin(9600);
tft.reset();
uint16_t identifier = tft.readID();
pinMode(10, OUTPUT); digitalWrite(10, HIGH);
tft.begin(identifier);
if (!SD.begin(SD_CS)) { progmemPrintln(PSTR("failed!")); return; }
tft.setRotation(1); // 横屏
bmpDraw(x, 0, 0);
}
void loop() {
// 限制文件名范围 x1~x4
if(x[1] < '1') x[1] = '1';
if(x[1] > '4') x[1] = '4';
TSPoint p = ts.getPoint();
pinMode(XM, OUTPUT); pinMode(YP, OUTPUT); // 恢复引脚模式
if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
// 屏幕左右两侧作为翻页按钮
if(p.y > 0 && p.y < 100) { // 左侧:上一张
Serial.println("Left"); x[1]--; bmpDraw(x, 0, 0); delay(300);
} else if(p.y > 200 && p.y < 320) { // 右侧:下一张
Serial.println("Right"); x[1]++; bmpDraw(x, 0, 0); delay(300);
}
}
}
// bmpDraw 函数同示例 1,此处省略
接线说明
本扩展板直插 Arduino UNO,无需额外接线。LCD 控制引脚固定为 A0-A3,SD 卡片选引脚为 D10,触摸屏使用 A2、A3、D8、D9。
制造工艺
- 贺卡产业:历史、生产与未来趋势
- 信用卡:历史、设计、制造与未来趋势
- 液晶显示器(LCD):技术、制造与未来展望
- Primal Display:树莓派 LCD 温度监测仪
- Kuman 3.5″ TFT 显示屏在 RetroPie 上安装全步骤指南
- ILI9341 2.4 英寸 TFT 触摸屏扩展板位图动画专业指南
- DIY 蓝牙控制 Arduino 间谍小车
- DIY Arduino LCD 游戏机:16x2 字符屏打造“躲避防守队员”足球小游戏
- AI从文本食谱生成逼真菜肴图片:Stacked GAN跨模态嵌入新突破
- DATA MODUL 推出 23.1 英寸超薄 TFT 显示器,支持智能 Wi-Fi 控制
- Distec 推出 Ortustech 7 英寸半透反射式 TFT 显示屏:坚固耐用、阳光下可读、低功耗
- Nuvo-7160GC:坚固 GPU PC 交付 6 TFLOPS、支持 120W GPU 与 4K 输出,面向机器视觉、VR 与自动化