之前的两篇帖子分别搞定了MAX78000开发板读取SD卡和驱动TFT液晶屏。这次将SD卡和液晶屏结合起来制作一个电子相册。
一、图片格式预处理:这个2.4寸SPI液晶屏模块240*320TFT模块,主控芯片为ILI9341。电脑中的图片是以jpg方式保存的图片。显示图片的第一步,就是要将jpg图片转换为位图形式,一种方法是在MAX78000开发板上解码jpg图片,需要用到jepg图片解码库。我这里是在电脑上预先将jpeg图片,转换为320X240大小的bmp(位图)的格式,保存在SD卡上。
# 将jpeg图片转换为bmp图片,并限定尺寸 import os import time import cv2 as cv filePath = os.path.dirname(os.path.abspath(__file__)) # 获取当前文件夹下的文件名列表 def readfilename(filepath): names = None try: names = os.listdir(filepath) except Exception as e: print(e) else: return names # 图片转换 def handleImage(filepath,names): for name in names: suffixs = name.split('.') suffix = suffixs.pop() if suffix in ['jpg']: img = cv.imread(filepath+"//"+name) # 调整图像大小 res = cv.resize(img, (320, 240),interpolation=cv.INTER_CUBIC) cv.imwrite(f'{filepath}/{suffixs[0]}.bmp', res) if __name__ == "__main__": filelist=readfilename("g://") print(filelist) handleImage("g://",filelist)
二、读取SD卡文件,并过滤bmp格式文件。
系统首先初始化各个硬件,然后从SD卡上读取文件,并将以“bmp”为后缀名的文件进行过滤。这里偷了个懒,SD卡中所有图片都以数字命名,从1开始,这样后边循环播放图片时,只需要简单地将文件名加一即可。首先统计出SD卡上有多少张图片。
//获取文件列表 返回获取到文件的个数 int ls_bmp(char cwd[]) { DIR dir; FILINFO fno; uint8_t num=0; if (!mounted) { mount(); } if ((err = f_opendir(&dir, cwd)) == FR_OK) { while (1) { err = f_readdir(&dir, &fno); if (err != FR_OK || fno.fname[0] == 0) { break; } printf("%s\n", fno.fname); if(strstr(fno.fname, ".bmp")){ num++; } } f_closedir(&dir); } else { printf("Error opening directory!\n"); return err; } return num; }
三、将RGB888格式数据转换为RGB565格式数据。
SD卡中读取到的bmp文件的数据,每个像素点是RGB888格式数据,即每个像素点由8X3位数据构成,分别记录红绿蓝三种颜色的信息。MAX78000开发板在TFT屏幕上显示时,使用的是RGB565格式数据,即每个像素点由8X2位数据构成,前5位为红色数据,中间6位为绿色数据,后边5位为蓝色数据。所以需要对每个点数据进行转换。
#define IMAGE_SIZE_X 320 #define IMAGE_SIZE_Y 240 uint8_t data565[IMAGE_SIZE_X * 2]; //step为传入数据中每个像素点所占字节数 3、4 void cover_rgb888_rgb565(uint8_t *data, uint8_t step) { uint8_t r, g, b; uint16_t rgb; uint16_t offset = 0; for (int i = 0; i < step * IMAGE_SIZE_X; i += step) { if (step == 4) { r = data[i]; g = data[i + 1]; b = data[i + 2]; } if (step == 3) { b = data[i]; g = data[i + 1]; r = data[i + 2]; } rgb = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3); data565[offset++] = (rgb >> 8) & 0xFF; data565[offset++] = rgb & 0xFF; } }
四、显示图片数据。
MAX78000开发板因为内存有限,与电脑处理图片不同,不能一次将整个图片文件载入内存进行处理。这里我采用每次读取一行(320个像素点)数据来进行处理,处理后在屏幕上绘制改行数据,然后继续后边一行的图片数据,如此循环,直至一张图片处理完毕。
//绘制SD卡图片到屏幕 void draw_sdimg_tft(uint8_t i) { FIL file; //FFat File Object FRESULT err; //FFat Result (Struct) char filename[7]; int row = 0; UINT bytes_read; uint8_t imgdata[IMAGE_SIZE_X * 3] = { 0 }; //全彩图 sprintf(filename, "/%d.bmp", i); printf("read img %s\n", filename); if ((err = f_open(&file, filename, FA_READ)) != FR_OK) { f_mount(NULL, "", 0); return err; } // Image data begins at 0x54 跳过文件头 if ((err = f_lseek(&file, 54)) != FR_OK) { printf("Error seeking file: %d\n", err); f_mount(NULL, "", 0); return err; } do { // 每次读取320个像素 if ((err = f_read(&file, imgdata, IMAGE_SIZE_X * 3, &bytes_read)) != FR_OK) { printf("Error reading file: %d\n", err); f_mount(NULL, "", 0); return err; } cover_rgb888_rgb565(imgdata, 3); //转换rgb格式 MXC_TFT_ShowImageCameraRGB565(0, row, data565,IMAGE_SIZE_X, 1); row++; } while (bytes_read == IMAGE_SIZE_X * 3); // bytes_read<255 means the cursor reached EOF if ((err = f_close(&file)) != FR_OK) { printf("Error closing file: %d\n", err); f_mount(NULL, "", 0); return err; } }
四、效果展示。
RGB565对图片还是有损失的,图片细腻程度还是有所下降。
五、源码。