0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

STM32应用案例 基于STM32F103ZE开发的数码相册

嵌入式技术 来源:嵌入式技术 作者:嵌入式技术 2022-06-02 09:09 次阅读

1.硬件平台

2.示例效果

SD卡检测和图片搜索

poYBAGKWuzaAfJxgAAXecAb-MmM388.png

图片加载与显示

pYYBAGKWu06Adh3FAAo-vcnwBR8460.png

3.软件设计

3.1 遍历目录

  遍历目录,搜索所有的bmp格式图片,以链表方式保存图片名,方便接下来图片切换。

typedef struct FILE_info
{
	char file_name[100];
	u16 number;//保存第几张图片
	struct FILE_info *next;
	struct FILE_info *pre;
}FILE_INFO;
FILE_INFO *bmp_head=NULL;
/*创建链表*/
FILE_INFO *List_CreateHead(FILE_INFO *head)
{
	if(head!=NULL)return head;
	head=malloc(sizeof(FILE_INFO));
	memset(head,0,sizeof(FILE_INFO));
	head->next=NULL;
	head->pre=NULL;
	return head;
}
/*添加节点*/
FILE_INFO *List_AddNode(FILE_INFO *head)
{
	if(head==NULL)return NULL;//链表头不存在
	FILE_INFO *phead=head;
	while(phead->next!=NULL)
	{
		phead=phead->next;
	}
	FILE_INFO *new_node=malloc(sizeof(FILE_INFO));
	memset(new_node,0,sizeof(FILE_INFO));
	new_node->pre=phead;
	phead->next=new_node;
	new_node->next=NULL;
	return new_node;
}
/*遍历目录*/
u8 SDCard_PrintDir(const TCHAR* path)
{
	DIR dp;	
	u8 res;
	u8 stat=0;
	bmp_head=List_CreateHead(bmp_head);//创建链表头	
	res=f_opendir(&dp,path);
  FILINFO file_info;
  if(res)
  {
    printf("打开目录失败res=%d\r\n",res);
		free(bmp_head);//释放链表头
    return 1;
  }	
	FILE_INFO *temp=NULL;
	while(1)
	{
		res=f_readdir(&dp,&file_info);
		if(res!=FR_OK || file_info.fname[0]==0)break;
		if(strstr(file_info.fname,".bmp"))//查找bmp图片
		{
			temp=List_AddNode(bmp_head);//添加节点
			if(temp==NULL)
			{
				stat=2;//动态分配空间失败
				goto AA;
			}
			strcpy(temp->file_name,file_info.fname);//文件名
			picture_count++;
			temp->number=picture_count;//第几张图片
			//printf("文件名:%s\r\n",temp->file_name);
		}
	}
AA:
	f_closedir(&dp);//关闭目录
	return stat;
}

3.2 图片解析与显示

  图片通过SD卡保存,SD卡采用SDIO驱动。由于STM32F103ZE主频只有72MHZ,为了提高刷新速度,将主频超频至128MHZ。再通过外扩SRAM建立屏幕缓冲区,借助DMA数据搬运,从而提升屏幕刷新效率。

超频处理后需要注意串口波特率计算和定时器工作频率

void STM32_Clock_Init(u8 PLL)
{
	u8 temp;
	RCC->CFGR&=0XFFFFFFFC;	//修改时钟频率为内部8M	   
	RCC->CR&=~0x01000000;  	//PLLOFF 
 	RCC->CFGR&=~(0XF<<18);	//清空原来的设置  
	RCC->CR|=1<<16;//开启HSE时钟
	while(!(RCC->CR>>17));//等待外部时钟就绪
	RCC->CFGR|=0x4<<8;//APB1时钟由系统时钟2分频
	PLL-=2;//实际倍频数和填入参数差2,9倍频写入的数值为7
	RCC->CFGR|=PLL<<18;//PLL时钟9倍频
	RCC->CFGR|=1<<16;	  //HSE作为PLL时钟输入源
	FLASH->ACR|=0x32;	  //FLASH 2个延时周期
	RCC->CR|=1<<24;//PLL时钟使能
	while(!(RCC->CR>>25));//等待PLL锁定
	RCC->CFGR|=0x2<<0;//PLL输出作为系统时钟
	while(1)
	{
		temp=(RCC->CFGR>>2)&0x3;
		if(temp==0x2)break;
	}	
}

3.3 DMA配置

  直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。

/******DMA_CH1从存储器到存储器************
**形参:u32 cpar -- 外设地址
**			u32 cmar -- 存储器地址
**
**************************************/
void DMA_CH1_Init(void)
{
	RCC->AHBENR|=1<<0;//dma1时钟使能
	DMA1_Channel1->CCR|=1<<14;//存储器到存储器模式
	DMA1_Channel1->CCR|=0x3<<12;//设置CH1优先级为最高
	DMA1_Channel1->CCR|=0x1<<10;//存储器数据宽度16位
	DMA1_Channel1->CCR|=0x1<<8;//外设数据宽度16位	
	DMA1_Channel1->CCR|=1<<7;//存储器地址增量
	DMA1_Channel1->CCR&=~(1<<6);//外设地址不增量
	DMA1_Channel1->CCR&=~(1<<5);//不执行循环操作
	//DMA1_Channel1->CCR|=1<<5;//执行循环操作
	DMA1_Channel1->CCR&=~(1<<4);//从外设读
}
/**********开启DMA1_CH1数据传输*************
***
***形参:u16 data_len -- DMA要传输数目
***********************************************/
void DMA_CH1_Start(u32 cpar,u32 cmar,u16 data_len)
{
	DMA1_Channel1->CPAR=cpar;//外设地址
	DMA1_Channel1->CMAR=cmar;//存储器地址
	DMA1_Channel1->CCR&=~(1<<0);//关闭通道传输
	DMA1_Channel1->CNDTR=data_len;//设置传输数量
	DMA1_Channel1->CCR|=1<<0;//开启通道传输
}

3.4 图片解析与显示

本示例主要以BMP图片为例,其他格式图形需要移植第三方库才可实现。
由于我们常规BMP图片多为24位真彩色,即RGB888;而本次使用的LCD屏是16位真彩色RGB565,因而需要进行颜色格式转换。

/*颜色转换RGB888转RGB565*/
u16 RGB888_Transform_RGB565(u32 rgb)
{
	u8 r,g,b;
	u16 rgb565;
	r=(rgb>>16)>>3;
	g=(rgb>>8)>>2;
	b=(rgb&0xff)>>3;
	rgb565=(r<<11)|(g<<5)|(b<<0);
	return rgb565;
}
u16 picture_count=0;//图片总数量
/*BMP图片显示*/
static u8 buff_rgb888[320*3];//用来保存读取到的原始数据
static u16 buff_rgb565[320*480];//用来保存转换完成的RGB565数据
u8 BMP_Display(const char *file,u16 number)
{
	FIL fp;
	FRESULT res;
	UINT br;
	u16 w,h;
	char buff[100];
	snprintf(buff,sizeof(buff),"0:/photo/%s",file);
	res=f_open(&fp,buff,FA_READ);
	if(res!=FR_OK)return 1;
	BMP_HEADER bmphead;
	BMP_INFO bmpinfo;
	memset(&bmphead,0,sizeof(BMP_HEADER));
	memset(&bmpinfo,0,sizeof(BMP_INFO));
	res=f_read(&fp,&bmphead,sizeof(BMP_HEADER),&br);
	if(res!=FR_OK)return 2;
	res=f_read(&fp,&bmpinfo,sizeof(BMP_INFO),&br);
	if(res!=FR_OK)return 2;
//	printf("图片类型:%c%c\r\n",bmphead.bfType>>8,bmphead.bfType);
//	printf("图片尺寸:%d*%d\r\n",bmpinfo.biWidth,bmpinfo.biHeight);
//	printf("颜色位数:%d\r\n",bmpinfo.biBitCount);
	w=bmpinfo.biWidth;
	h=bmpinfo.biHeight;
	u32 oneline_size=bmpinfo.biWidth*3;//一行的字节数
	u32 read_oneline_size=oneline_size;//要读取的一行字节数
	/*取出有效的rgb颜色值的一行字节数*/
  while(oneline_size%4)oneline_size++;/*保存一行字节数为4的倍数*/
	u32 addr=bmphead.bfOffBits+(bmpinfo.biHeight-1)*oneline_size;
	/*将指针偏移到最后一行*/
	u32 i=0,j=0;;
	u32 rgb888;
	u32 cnt=0;
	for(i=0;i

3.5 主函数main.c

  在主函数main.c中主要完成各个外设初始化、SD卡挂载、图片获取、触摸屏坐标和按键值获取,最终实现通过触摸屏滑动或者按下切换图片。

FATFS fs;
int main()
{

	u8 key;
	STM32_Clock_Init(16);
	Beep_Init();
	Led_Init();
	Key_Init();
	Usartx_Init(USART1,115200,128);
	TIMx_Init(TIM2,128,20*1000);
	W25Q64_Init();//W25Q64初始化
	IIC_Init();//IIC初始化
	NT35310_Init();//LCD初始化
	XPT2046_Init();
	TOUCH_Calibration();//触摸屏校准
	printf("触摸屏校准完成\r\n");
	SRAM_Init();
	u8 res;
AA:
	res=f_mount(&fs,"0",1);
	if(res)
	{
		LCD_Clear(LIGHTBLUE);
		LCD_Display_Str(LCD_WIDTH/2-strlen("请检查SD卡是否插好!")*12/2,210,24,(u8 *)"请检查SD卡是否插好!",RED);
		LCD_Display_Str(LCD_WIDTH/2-strlen("注意文件系统格式须为FAT32!")*12/2,240,24,(u8 *)"注意文件系统格式须为FAT32!",RED);
		LCD_Refresh();//更新显示
		Delay_Ms(1000);
		goto AA;
	}
BB:
	LCD_Clear(LIGHTBLUE);
	res=SDCard_PrintDir("photo");//遍历目录
	if(res)
	{
		LCD_Refresh();//更新显示
		LCD_Display_Str(LCD_WIDTH/2-strlen("BMP图片不存在!")*12/2,210,24,(u8 *)"BMP图片不存在!",RED);
		LCD_Display_Str(LCD_WIDTH/2-strlen("请将图片存储在/photo下")*12/2,240,24,(u8 *)"请将图片存储在/photo下",RED);
		LCD_Refresh();//更新显示
		Delay_Ms(1000);
		goto BB;
	}
	LCD_Clear(LIGHTBLUE);
	LCD_Display_Str(LCD_WIDTH/2-strlen("正在加载图片。。")*12/2,210,24,(u8 *)"正在加载图片。。",RED);
	LCD_Refresh();//更新显示
	Delay_Ms(1000);
	FILE_INFO *bmp_temp=bmp_head;
	if(bmp_temp->next!=NULL)
	{
		bmp_temp=bmp_temp->next;
		BMP_Display(bmp_temp->file_name,bmp_temp->number);
	}
	u16 x1,x2;
	int stat=0;
	while(1)
	{
		res=XPT2046_ReadXY();
		if(res)
		{
			x1=touch_info.x;
			while(T_PEN==0)//等待松开
			{
				XPT2046_ReadXY();
				x2=touch_info.x;
			}
			if(x1-x2>50)stat=1;
			else if(x2-x1>50)stat=2;
		}
		key=Key_Scan();
		if(key==1 || stat==1)
		{
			stat=0;
			BEEP=1;
			Delay_Ms(50);
			BEEP=0;
			if(bmp_temp->next!=NULL)
			{
				bmp_temp=bmp_temp->next;
				BMP_Display(bmp_temp->file_name,bmp_temp->number);
			}
		}
		else if(key==2 || stat==2)
		{
			stat=0;
			BEEP=1;
			Delay_Ms(50);
			BEEP=0;
			if(bmp_temp->pre!=NULL && bmp_temp->pre->file_name[0]!=0)
			{
				bmp_temp=bmp_temp->pre;
				BMP_Display(bmp_temp->file_name,bmp_temp->number);
			}
			//printf("%s\r\n",bmp_temp->file_name);
		}
	}
}

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • lcd
    lcd
    +关注

    关注

    34

    文章

    4281

    浏览量

    164352
  • STM32
    +关注

    关注

    2241

    文章

    10678

    浏览量

    349106
  • TFT
    TFT
    +关注

    关注

    10

    文章

    374

    浏览量

    109867
  • STM32F103ZE
    +关注

    关注

    2

    文章

    14

    浏览量

    10799
收藏 人收藏

    评论

    相关推荐

    基于STM32设计的数码相册

    项目是基于STM32设计的数码相册,能够通过LCD显示屏解码显示主流的图片,支持bmp、jpg、gif等格式。用户可以通过按键或者触摸屏来切换图片,同时还可以旋转显示,并能够自适应居中显示,小尺寸图片居中显示,大尺寸图片自动缩小显示(超出屏幕范围)。图片从SD卡中获取。
    的头像 发表于 06-24 21:14 1.2w次阅读
    基于<b class='flag-5'>STM32</b>设计的<b class='flag-5'>数码相册</b>

    STM32F103ZE最小系统版

    1.单片机:STM32F103ZE最小系统版6.0✔N1RVcKX0SpK₴回????/宝或點***击***链节至瑬览器【STM32F103ZET6小系统板 STM32开发
    发表于 08-06 07:51

    STM32F103ZE的AHB时钟

    的时间去循环执行,因此需要一个简单的任务调度来解决这个问题。STM32F103ZE的AHB时钟为72MHz,通过HSE的8M倍频到72M,然后APB1预分频系数为2,所以TIM2-7时钟为2*36M...
    发表于 08-10 06:21

    怎样将uTenux移植到STM32F103ZE开发板上去呢

    uTenux是什么?怎样将uTenux移植到STM32F103ZE开发板上去呢?
    发表于 11-02 06:42

    基于stm32F103ZE单片机的USART串口怎么使用?

    基于stm32F103ZE单片机的USART串口怎么使用?
    发表于 12-10 06:57

    STM32F103ze简介

    一、STM32F103ze 简介本文中,采用的 MCU 具体型号为 STM32F103ZET6,其拥有丰富的外设资源(USB,IIC,USART,TIMER)等,大容量的RAM和ROM,以及上百
    发表于 02-11 06:04

    STM32F103ZE构建固件库模板的方法

    摘自:STM32F103ZE新建固件库模板作者:追兮兮发布时间:2020-10-14 10:31:45网址:https://blog.csdn.net/weixin_44234294/article/details/109065495
    发表于 02-14 06:56

    【技术精选】嵌入式STM32原创征文活动精选文章

    应用案例基于PAJ7620和STM32手势识别应用案例STM32应用案例 基于STM32F103ZE开发数码相册基于
    发表于 07-27 18:26

    STM32F103ZE最小系统原理图

    STM32F103ZE最小系统原理图
    发表于 09-20 11:07 196次下载
    <b class='flag-5'>STM32F103ZE</b>最小系统原理图

    基于stm32f103ze的四轴飞控代码

    基于stm32f103ze的四轴飞控代码
    发表于 01-13 10:21 30次下载

    嵌入式 STM32F103ZE主要特性

    Embest公司的STM32F103ZE ARM Cortex-M3嵌入式评估板采用ST公司的STM32F103ZE处理器,工作频率72MHz.评估板集成了USB, CAN, SD卡接口
    发表于 05-08 11:17 1.5w次阅读
    嵌入式 <b class='flag-5'>STM32F103ZE</b>主要特性

    新版STM32F103ZE核心板原理图免费下载

    本文档的主要内容详细介绍的是新版STM32F103ZE核心板原理图免费下载。
    发表于 02-26 11:46 0次下载
    新版<b class='flag-5'>STM32F103ZE</b>核心板原理图免费下载

    新版STM32F103ZE核心板原理图

    新版STM32F103ZE核心板原理图免费下载。
    发表于 06-18 11:14 0次下载

    STM32F103ZE构建固件库模板

    STM32F103ZE构建固件库模板
    发表于 12-08 18:51 13次下载
    <b class='flag-5'>STM32F103ZE</b>构建固件库模板

    STM32F103ZE最小系统板

    STM32F103ZE最小系统板,可能带有一些不足
    发表于 03-30 18:18 0次下载