一、项目介绍
项目是基于STM32设计的数码相册,能够通过LCD显示屏解码显示主流的图片,支持bmp、jpg、gif等格式。用户可以通过按键或者触摸屏来切换图片,同时还可以旋转显示,并能够自适应居中显示,小尺寸图片居中显示,大尺寸图片自动缩小显示(超出屏幕范围)。图片从SD卡中获取。
二、设计思路
2.1 硬件设计
本项目所需的主要硬件:
STM32F103ZET6
LCD屏幕
SD卡模块
按键和触摸屏
2.2 软件设计
(1)解码图片
在STM32芯片中,解码图片需要将读取到的数据存入图形缓冲区中,以便进行图画显示。常用的解码算法有JPEG解码和BMP解码。
(2)图片显示
为了更好的实现图片旋转和缩放功能,在显示图片时需对其进行矩阵运算。通过左右翻转和上下翻转,可实现图片的旋转功能。通过计算图片与显示屏幕之间的比例关系并进行缩放,实现自适应居中和图片的缩放功能。
(3)SD卡
SD卡模块可通过SPI接口与STM32芯片进行通信,读取SD卡中的图片数据,实现对图片的加载和显示。
(4)按键和触摸屏
在使用过程中,用户可以通过按键和触摸屏对图片进行切换、旋转和缩放等操作。通过设置中断处理函数,响应用户的操作并及时更新显示屏幕上的图片。
2.3 图片播放流程图
2.4 显示效果
三、代码设计
3.1 主函数
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "usart.h"
#include < string.h >
#include < stdio.h >
#include "sd.h" //SD卡
#include "ff.h" //文件系统
#include "bmp.h" //文件系统
#include "iic.h"
#include "at24c02.h"
#include "xpt2046.h"
#include "lcd.h"
FATFS fs; // 用户定义的文件系统结构体
int main()
{
DIR dir_dp;
FILINFO file_info;
u32 sd_size; //存放SD卡返回的容量
BeepInit(); //蜂鸣器初始化
LedInit(); //LED灯初始化
UsartInit(USART1,72,115200);
KeyInit(); //按键初始化
IICInit();
LcdInit();
TOUCH_Init();
//TOUCH_ADJUST(); //触摸屏校准
printf("串口工作正常! ");
if(SDCardDeviceInit())
{
printf("SD卡初始化失败! ");
}
sd_size=GetSDCardSectorCount(); //检测SD卡大小,返回值右移11位得到以M为单位的容量
printf("SD卡Sizeof:%d ",sd_size >>11);
f_mount(&fs,"0:",1); // 注册文件系统工作区,驱动器号 0,初始化后其他函数可使用里面的参数
LcdClear(0xFFFF);
//f_mkdir("0:/目录创建测试!"); //测试OK
//f_unlink("0:/123"); //删除目录,注意只能删除空目录
//f_unlink("0:/1.bmp");//删除文件
//printf("%d ",Show_BMP("1.bmp"));
if(f_opendir(&dir_dp,"0:/bmp")!=FR_OK)printf("目录打开失败! ");
//循环读取目录
while(f_readdir(&dir_dp,&file_info)==FR_OK)
{
if(file_info.fname[0]==0)break; //判断目录跳出条件,表示目录已经读取完毕
if(strstr(file_info.fname,".bmp")) //过滤目录
{
printf("文件名称: %s,文件大小: %ld 字节 ",file_info.fname,file_info.fsize);
}else printf("文件名称: %s,文件大小: %ld 字节 ",file_info.fname,file_info.fsize);
}
if(f_closedir(&dir_dp)!=FR_OK)printf("目录关闭失败! ");
while(1)
{
LED1=!LED1;
DelayMs(100);
}
}
3.2 BMP图片解码
#include "bmp.h"
unsigned short RGB888ToRGB565(unsigned int n888Color)
{
unsigned short n565Color = 0;
// 获取RGB单色,并截取高位
unsigned char cRed = (n888Color & RGB888_RED) > > 19;
unsigned char cGreen = (n888Color & RGB888_GREEN) > > 10;
unsigned char cBlue = (n888Color & RGB888_BLUE) > > 3;
// 连接
n565Color = (cRed < < 11) + (cGreen < < 5) + (cBlue < < 0);
return n565Color;
}
unsigned int RGB565ToRGB888(unsigned short n565Color)
{
unsigned int n888Color = 0;
// 获取RGB单色,并填充低位
unsigned char cRed = (n565Color & RGB565_RED) > > 8;
unsigned char cGreen = (n565Color & RGB565_GREEN) > > 3;
unsigned char cBlue = (n565Color & RGB565_BLUE) < < 3;
// 连接
n888Color = (cRed < < 16) + (cGreen < < 8) + (cBlue < < 0);
return n888Color;
}
/*
函数功能:实现截图功能
参 数:
char filename:文件名称
返 回 值:0表示成功,1表示失败
*/
u8 C_BMP(const char *filename,u32 Width,u32 Height)
{
FIL file; // 用户定义的文件系统结构体
u8 res; // 保存文件操作的返回值
BITMAPFILEHEADER BmpHead; //保存图片文件头的信息
BITMAPINFOHEADER BmpInfo; //图片参数信息
char *p;
u32 cnt,c_32;
int x,y;
u16 c_16; //存放16位的颜色
/*1. 创建一张BMP图片*/
res = f_open(&file,filename, FA_OPEN_ALWAYS | FA_WRITE);
if(res!=0)return 1;
/*2. 创建BMP的图片头参数*/
memset(&BmpHead,0,sizeof(BITMAPFILEHEADER)); //将指定空间赋值为指定的值
p=(char*)&BmpHead.bfType; //填充BMP图片的类型
*p='B';
*(p+1)='M';
//BmpHead.bfType=0x4d42;//'B''M' //0x4d42
BmpHead.bfSize=Width*Height*3+54; //图片的总大小
BmpHead.bfOffBits=54; //图片数据的偏移量
res =f_write(&file,&BmpHead,sizeof(BITMAPFILEHEADER),&cnt);
if(res!=0)return 1;
/*3. 创建BMP图片的参数*/
memset(&BmpInfo,0,sizeof(BITMAPINFOHEADER));
BmpInfo.biSize=sizeof(BITMAPINFOHEADER); //当前结构体大小
BmpInfo.biWidth=Width;
BmpInfo.biHeight=Height;
BmpInfo.biPlanes=1;
BmpInfo.biBitCount=24;
res =f_write(&file,&BmpInfo,sizeof(BITMAPINFOHEADER),&cnt);
if(res!=0)return 1;
/*4. 读取LCD屏的颜色数据,用于创建BMP图片*/
for(y=Height-1;y >=0;y--)
{
for(x=0;x< Width;x++)
{
c_16=LcdReadPoint(x,y); //读取LCD屏上一个点的颜色
c_32=RGB565ToRGB888(c_16); //颜色的转换
res =f_write(&file,&c_32,3,&cnt);
if(res!=0)return 1;
}
}
/*5. 关闭文件*/
f_close(&file);
}
/*
函数功能:BMP图片显示功能
参 数:
char filename:文件名称
返 回 值:0表示成功,1表示失败
*/
u8 Show_BMP(const char *filename)
{
FIL file; // 用户定义的文件系统结构体
u8 res; // 保存文件操作的返回值
BITMAPFILEHEADER BmpHead; //保存图片文件头的信息
BITMAPINFOHEADER BmpInfo; //图片参数信息
char *p;
u32 cnt,c_24;
int x,y;
u16 c_16; //存放16位的颜色
/*1. 打开一张BMP图片*/
res = f_open(&file,filename,FA_READ);
if(res!=0)return 1;
/*2. 读取BMP的图片头参数*/
res =f_read(&file,&BmpHead,sizeof(BITMAPFILEHEADER),&cnt);
if(res!=0)return 1;
/*3. 读取BMP图片的参数*/
res =f_read(&file,&BmpInfo,sizeof(BITMAPINFOHEADER),&cnt);
if(res!=0)return 1;
/*4.显示BMP图片*/
f_lseek(&file,BmpHead.bfOffBits); //移动到RGB数据的存放位置
//后期的优化:读取一行的数据,再显示一行。
for(y=0;y< BmpInfo.biHeight;y++)
{
for(x=0;x< BmpInfo.biWidth;x++)
{
res =f_read(&file,&c_24,3,&cnt);
if(res!=0)return 1;
c_16=RGB888ToRGB565(c_24); //转换颜色
LcdDrawPoint(x,y,c_16);
}
}
/*5. 关闭文件*/
f_close(&file);
}
3.3 jpeg图片解码
#include "piclib.h"
#include "nt35310_lcd.h"
_pic_info picinfo; //图片信息