使用 FatFs 显示 SD 卡中的 JPEG 文件需要结合文件系统操作、JPEG 解码和显示驱动三个部分。以下是详细步骤和代码示例(以 STM32 + ILI9341 LCD 为例):
步骤概览
- 初始化硬件:SD卡接口、文件系统(FatFs)、显示设备。
- 读取JPEG文件:使用 FatFs 打开文件并读取数据。
- 解码JPEG:使用轻量级解码库(如 TJpgDec 或 PicoJPEG)。
- 显示图像:将解码后的像素数据写入显示屏。
代码实现
1. 初始化 FatFs 和 SD 卡
FATFS fs;
FIL fil;
void SD_Init(void) {
// 挂载文件系统
if (f_mount(&fs, "", 1) != FR_OK) {
printf("SD Card Mount Errorn");
return;
}
}
2. JPEG 解码库选择
推荐使用 TJpgDec(FatFs 官方配套库)或 PicoJPEG(资源占用小)。
TJpgDec 配置示例
在 tjpgd_conf.h 中配置:
#define JD_SZBUF 5120 // 设置缓冲区大小(建议≥4KB)
#define JD_USE_SCALE 0 // 关闭缩放(节省内存)
3. 显示JPEG函数
#include "tjpgd.h"
#include "lcd.h" // 你的显示屏驱动
// TJpgDec 回调函数
static UINT tjpgd_data_reader(JDEC* jd, BYTE* buff, UINT len) {
FIL* fil = (FIL*)jd->device; // 从JDEC结构获取文件指针
UINT br;
f_read(fil, buff, len, &br);
return br;
}
static UINT tjpgd_data_writer(JDEC* jd, void* bitmap, JRECT* rect) {
// 获取LCD设备句柄(假设已实现)
LCD_HandleTypeDef* hlcd = (LCD_HandleTypeDef*)jd->device;
uint16_t* data = (uint16_t*)bitmap;
// 将RGB数据写入LCD(坐标由rect指定)
for (int y = rect->top; y <= rect->bottom; y++) {
for (int x = rect->left; x <= rect->right; x++) {
// 转换RGB888为RGB565(示例)
uint16_t color = RGB_TO_565(data[0], data[1], data[2]);
LCD_DrawPixel(hlcd, x, y, color);
data += 3; // 移动到下一个像素
}
}
return 1;
}
// 显示JPEG主函数
int ShowJPEG(const char* path) {
FIL fil;
if (f_open(&fil, path, FA_READ) != FR_OK) return -1;
JDEC jdec;
JRESULT res;
// 初始化解码器(传入文件句柄)
res = jd_prepare(&jdec, tjpgd_data_reader, NULL, 0, &fil);
if (res != JDR_OK) {
f_close(&fil);
return -2;
}
// 开始解码(传入LCD句柄)
LCD_HandleTypeDef hlcd; // 实际使用时需初始化
res = jd_decomp(&jdec, tjpgd_data_writer, 0);
f_close(&fil);
return (res == JDR_OK) ? 0 : -3;
}
关键点说明
内存管理:
- TJpgDec 需要
JD_SZBUF 大小的缓冲区(默认~3KB)。
- 大尺寸JPEG需分块处理,避免内存溢出。
性能优化:
- 双缓冲机制:用DMA传输数据到LCD,同时解码下一块。
- 缩小图像:设置
jd_decomp(scale) 参数,以1/2、1/4比例显示。
颜色转换:
错误处理:
- 检查
FR_OK (FatFs) 和 JDR_OK (TJpgDec) 确保流程正确。
在STM32CubeIDE中的配置
- 启用FatFs和SDIO(SD卡接口)。
- 添加TJpgDec库到项目(从FatFs官网下载)。
- 实现LCD驱动(支持
LCD_DrawPixel函数)。
替代方案:PicoJPEG
如果资源紧张,改用PicoJPEG(仅需~2KB RAM):
#include "picojpeg.h"
// 读取JPEG到缓冲区(分段处理)
uint8_t jpeg_buf[1024];
UINT bytes_read;
f_read(&fil, jpeg_buf, sizeof(jpeg_buf), &bytes_read);
// 初始化解码器
pjpeg_image_info_t info;
pjg_decode_init(&info, jpeg_buf, bytes_read, ...);
// 逐行解码并显示
while (pjg_decode_mcu() == PJPG_NO_MORE_BLOCKS) {
uint8_t* line = pjg_get_line_buffer();
// 转换并显示一行到LCD
}
总结
- 核心流程:FatFs读文件 → TJpgDec/PicoJPEG解码 → RGB数据写LCD。
- 优化方向:降低解码分辨率、使用硬件加速(如STM32 JPEG解码器)。
- 调试建议:先通过串口打印JPEG尺寸,确保文件读取正确。