1)实验平台:alientek 阿波罗 STM32F767 开发板2)摘自《STM32F7 开发指南(HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子

第四十九章 图片显示实验

在开发产品的时候,很多时候,我们都会用到图片解码,在本章中,我们将向大家介绍如

何通过 STM32F767 来解码 BMP/JPG/JPEG/GIF 等图片,并在 LCD 上显示出来。本章分为如下

几个部分:

49.1 图片格式简介

49.2 硬件设计

49.3 软件设计

49.4 下载验证

49.1 图片格式简介

我们常用的图片格式有很多,一般最常用的有三种:JPEG(或 JPG)、BMP 和 GIF。其中

JPEG(或 JPG)和 BMP 是静态图片,而 GIF 则是可以实现动态图片。下面,我们简单介绍一

下这三种图片格式。

首先,我们来看看 BMP 图片格式。BMP(全称 Bitmap)是 Window 操作系统中的标准图

像文件格式,文件后缀名为“.bmp”,使用非常广。它采用位映射存储格式,除了图像深度可

选以外,不采用其他任何压缩,因此,BMP 文件所占用的空间很大,但是没有失真。BMP 文

件的图像深度可选 lbit、4bit、8bit、16bit、24bit 及 32bit。BMP 文件存储数据时,图像的扫描

方式是按从左到右、从下到上的顺序。

典型的 BMP 图像文件由四部分组成:

1, 位图头文件数据结构,它包含 BMP 图像文件的类型、显示内容等信息;

2, 位图信息数据结构,它包含有 BMP 图像的宽、高、压缩方法,以及定义颜色等信息

1, 调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24 位

的 BMP)就不需要调色板;

2, 位图数据,这部分的内容根据 BMP 位图使用的位数不同而不同,在 24 位图中直接使

用 RGB,而其他的小于 24 位的使用调色板中颜色索引值。

关于 BMP 的详细介绍,请参考光盘的《BMP 图片文件详解.pdf》。接下来我们看看 JPEG

文件格式。

JPEG 是 Joint Photographic Experts Group(联合图像专家组)的缩写,文件后辍名为“.jpg”

或“.jpeg”,是最常用的图像文件格式,由一个软件开发联合会组织制定,同 BMP 格式不同,

JPEG 是一种有损压缩格式,能够将图像压缩在很小的储存空间,图像中重复或不重要的资料

会被丢失,因此容易造成图像数据的损伤(BMP 不会,但是 BMP 占用空间大)。尤其是使用过

高的压缩比例,将使最终解压缩后恢复的图像质量明显降低,如果追求高品质图像,不宜采用

过高压缩比例。但是 JPEG 压缩技术十分先进,它用有损压缩方式去除冗余的图像数据,在获

得极高的压缩率的同时能展现十分丰富生动的图像,换句话说,就是可以用最少的磁盘空间得

到较好的图像品质。而且 JPEG 是一种很灵活的格式,具有调节图像质量的功能,允许用不同

的压缩比例对文件进行压缩,支持多种压缩级别,压缩比率通常在 10:1 到 40:1 之间,压缩

比越大,品质就越低;相反地,压缩比越小,品质就越好。比如可以把 1.37Mb 的 BMP 位图

文件压缩至 20.3KB。当然也可以在图像质量和文件尺寸之间找到平衡点。JPEG 格式压缩的

主要是高频信息,对色彩的信息保留较好,适合应用于互联网,可减少图像的传输时间,可以

支持 24bit 真彩色,也普遍应用于需要连续色调的图像。

JPEG/JPG 的解码过程可以简单的概述为如下几个部分:

1、从文件头读出文件的相关信息。

JPEG 文件数据分为文件头和图像数据两大部分,其中文件头记录了图像的版本、长宽、

采样因子、量化表、哈夫曼表等重要信息。所以解码前必须将文件头信息读出,以备

图像数据解码过程之用。

2、从图像数据流读取一个最小编码单元(MCU) ,并提取出里边的各个颜色分量单元。

3、将颜色分量单元从数据流恢复成矩阵数据。

使用文件头给出的哈夫曼表,对分割出来的颜色分量单元进行解码,把其恢复成 8×8

的数据矩阵。

4、8×8 的数据矩阵进一步解码。

此部分解码工作以 8×8 的数据矩阵为单位,

其中包括相邻矩阵的直流系数差分解码、

使用文件头给出的量化表反量化数据、反 Zig- zag 编码、隔行正负纠正、反向离散余弦变

换等 5 个步骤, 最终输出仍然是一个 8×8 的数据矩阵。

5、颜色系统 YCrCb 向 RGB 转换。

将一个 MCU 的各个颜色分量单元解码结果整合起来,将图像颜色系统从 YCrCb 向

RGB 转换。

6、排列整合各个 MCU 的解码数据。

不断读取数据流中的 MCU 并对其解码,直至读完所有 MCU 为止,将各 MCU 解码

后的数据正确排列成完整的图像。

JPEG 的解码本身是比较复杂的,这里 FATFS 的作者,提供了一个轻量级的 JPG/JPEG 解

码库:TjpgDec,最少仅需 3KB 的 RAM 和 3.5KB 的 FLASH 即可实现 JPG/JPEG 解码,本例程

采用 TjpgDec 作为 JPG/JPEG 的解码库,关于 TjpgDec 的详细使用,请参考光盘:6,软件资料

图片编解码TjpgDec 技术手册 这个文档。

BMP 和 JPEG 这两种图片格式均不支持动态效果,而 GIF 则是可以支持动态效果。最后,

我们来看看 GIF 图片格式。

GIF(Graphics Interchange Format)是 CompuServe 公司开发的图像文件存储格式,1987 年开

发的 GIF 文件格式版本号是 GIF87a,1989 年进行了扩充,扩充后的版本号定义为 GIF89a。

GIF 图像文件以数据块(block)为单位来存储图像的相关信息。一个 GIF 文件由表示图形/图

像的数据块、数据子块以及显示图形/图像的控制信息块组成,称为 GIF 数据流(Data Stream)。

数据流中的所有控制信息块和数据块都必须在文件头(Header)和文件结束块(Trailer)之间。

GIF 文件格式采用了 LZW(Lempel-Ziv Walch)压缩算法来存储图像数据,定义了允许用户为

图像设置背景的透明(transparency)属性。此外,GIF 文件格式可在一个文件中存放多幅彩色图

形/图像。如果在 GIF 文件中存放有多幅图,它们可以像演幻灯片那样显示或者像动画那样演示。

一个 GIF 文件的结构可分为文件头(File Header)、GIF 数据流(GIF Data Stream)和文件终结

器(Trailer)三个部分。文件头包含 GIF 文件署名(Signature)和版本号(Version);GIF 数据流由控

制标识符、图象块(Image Block)和其他的一些扩展块组成;文件终结器只有一个值为 0x3B 的字

符(';')表示文件结束。

关于 GIF 的详细介绍,请参考光盘 GIF 解码相关资料。图片格式简介,我们就介绍到这里。

49.2 硬件设计

本章实验功能简介:开机的时候先检测字库,然后检测 SD 卡是否存在,如果 SD 卡存在,

则开始查找 SD 卡根目录下的 PICTURE 文件夹,如果找到则显示该文件夹下面的图片文件(支

持 bmp、jpg、jpeg 或 gif 格式),循环显示,通过按 KEY0 和 KEY2 可以快速浏览下一张和上

一张,KEY_UP 按键用于暂停/继续播放,DS1 用于指示当前是否处于暂停状态。如果未找到PICTURE 文件夹/任何图片文件,则提示错误。同样我们也是用 DS0 来指示程序正在运行。

所要用到的硬件资源如下:

1) 指示灯 DS0 和 DS1

2) KEY0、KEY2 和 KEY_UP 三个按键

3) 串口

4) LCD 模块

5) SD 卡

6) SPI FLASH

这几部分,在之前的实例中都介绍过了,我们在此就不介绍了。需要注意的是,我们在 SD

卡根目录下要建一个 PICTURE 的文件夹,用来存放 JPEG、JPG、BMP 或 GIF 等图片。

49.3 软件设计

打开本章实验工程目录可以看到,我们在工程根目录下面新建了一个 PICTURE 文件夹。

在该文件夹里面新建了 bmp.c、bmp.h、tjpgd.c、tjpgd.h、integer.h、gif.c、gif.h、piclib.c 和 piclib.h

等 9 个文件。打开实验工程可以看到,我们在工程中新建了 PICTURE 分组,添加了相关源文

件到工程,同时将 PICTURE 文件夹加入头文件包含路径。

对于这些文件,其中 bmp.c 和 bmp.h 用于实现对 bmp 文件的解码;tjpgd.c 和 tjpgd.h 用于

实现对 jpeg/jpg 文件的解码;gif.c 和 gif.h 用于实现对 gif 文件的解码;这几个代码太长了,所

以我们在这里不贴出来,请大家参考光盘本例程的源码,我们打开 piclib.c,代码如下:

extern u32 *ltdc_framebuf[2]; //LTDC LCD 帧缓存指针必须指向对应大小的内存区域_pic_info picinfo; //图片信息_pic_phy pic_phy; //图片显示物理接口lcd.h 没有提供划横线函数,需要自己实现void piclib_draw_hline(u16 x0,u16 y0,u16 len,u16 color){if((len==0)||(x0>lcddev.width)||(y0>lcddev.height))return;LCD_Fill(x0,y0,x0+len-1,y0,color);}//填充颜色//x,y:起始坐标//width,height:宽度和高度。//*color:颜色数组void piclib_fill_color(u16 x,u16 y,u16 width,u16 height,u16 *color){ u16 i,j;if(lcdltdc.pwidth!=0&&lcddev.dir==0)//如果是 RGB 屏,且竖屏,则填充函数不可直接用{for(i=0;i>5)+src2)&0x07E0F81F;return (dst2>>16)|dst2; }//初始化智能画点//内部调用void ai_draw_init(void){float temp,temp1; temp=(float)picinfo.S_Width/picinfo.ImgWidth;temp1=(float)picinfo.S_Height/picinfo.ImgHeight;if(temp1)temp1=1; //使图片处于所给区域的中间picinfo.S_XOFF+=(picinfo.S_Width-temp1*picinfo.ImgWidth)/2;picinfo.S_YOFF+=(picinfo.S_Height-temp1*picinfo.ImgHeight)/2;temp1*=8192;//扩大 8192 倍picinfo.Div_Fac=temp1;picinfo.staticx=0xffff;picinfo.staticy=0xffff;//放到一个不可能的值上面 } //判断这个像素是否可以显示//(x,y) :像素原始坐标//chg :功能变量. //返回值:0,不需要显示.1,需要显示u8 is_element_ok(u16 x,u16 y,u8 chg){ if(x!=picinfo.staticx||y!=picinfo.staticy){if(chg==1){picinfo.staticx=x;picinfo.staticy=y;} return 1;}else return 0;}//智能画图//FileName:要显示的图片文件 BMP/JPG/JPEG/GIF//x,y,width,height:坐标及显示区域尺寸//fast:使能 jpeg/jpg 小图片(图片尺寸小于等于液晶分辨率)快速解码,0,不使能;1,使能.//图片在开始和结束的坐标点范围内显示u8 ai_load_picfile(const u8 *filename,u16 x,u16 y,u16 width,u16 height,u8 fast){u8 res;//返回值u8 temp;if((x+width)>picinfo.lcdwidth)return PIC_WINDOW_ERR; //x 坐标超范围了.if((y+height)>picinfo.lcdheight)return PIC_WINDOW_ERR; //y 坐标超范围了. //得到显示方框大小 if(width==0||height==0)return PIC_WINDOW_ERR; //窗口设定错误picinfo.S_Height=height;picinfo.S_Width=width;//显示区域无效if(picinfo.S_Height==0||picinfo.S_Width==0){picinfo.S_Height=lcddev.height;picinfo.S_Width=lcddev.width;return FALSE; }if(pic_phy.fillcolor==NULL)fast=0;//颜色填充函数未实现,不能快速显示//显示的开始坐标点picinfo.S_YOFF=y;picinfo.S_XOFF=x;//文件名传递temp=f_typetell((u8*)filename); //得到文件的类型switch(temp){ case T_BMP:res=stdbmp_decode(filename); //解码 bmp break;case T_JPG:case T_JPEG:res=jpg_decode(filename,fast); //解码 JPG/JPEG break;case T_GIF:res=gif_decode(filename,x,y,width,height); //解码 gif break;default:res=PIC_FORMAT_ERR; //非图片格式!!! break;} return res;  }//动态分配内存void *pic_memalloc (u32 size){return (void*)mymalloc(SRAMDTCM,size);}//释放内存void pic_memfree (void* mf){myfree(SRAMDTCM,mf);}

此段代码总共 9 个函数,其中,piclib_draw_hline 和 piclib_fill_color 函数因为 LCD 驱动代

码没有提供,所以在这里单独实现,如果 LCD 驱动代码有提供,则直接用 LCD 提供的即可。

piclib_init 函数,该函数用于初始化图片解码的相关信息,其中_pic_phy 是我们在 piclib.h

里面定义的一个结构体,用于管理底层 LCD 接口函数,这些函数必须由用户在外部实现。

_pic_info 则是另外一个结构体,用于图片缩放处理。

piclib_alpha_blend 函数,该函数用于实现半透明效果,在小格式(图片分辨率小于 LCD 分

辨率)bmp 解码的时候,可能被用到。

ai_draw_init 函数,该函数用于实现图片在显示区域的居中显示初始化,其实就是根据图片

大小选择缩放比例和坐标偏移值。

is_element_ok 函数,该函数用于判断一个点是不是应该显示出来,在图片缩放的时候该函

数是必须用到的。

ai_load_picfile 函数,该函数是整个图片显示的对外接口,外部程序,通过调用该函数,可

以实现 bmp、jpg/jpeg 和 gif 的显示,该函数根据输入文件的后缀名,判断文件格式,然后交给

相应的解码程序(bmp 解码/jpeg 解码/gif 解码),执行解码,完成图片显示。注意,这里我们用

到一个 f_typetell 的函数,来判断文件的后缀名,f_typetell 函数在 exfuns.c 里面实现,具体请参

考光盘本例程源码。

最后,pic_memalloc 和 pic_memfree 分别用于图片解码时需要用到的内存申请和释放,通

过调用 mymalloc 和 myfreee 来实现。

接下来我们看看头文件 piclib.h 关键代码如下:

#define PIC_FORMAT_ERR 0x27 //格式错误#define PIC_SIZE_ERR 0x28 //图片尺寸错误#define PIC_WINDOW_ERR 0x29 //窗口设定错误#define PIC_MEM_ERR 0x11 //内存错误///#ifndef TRUE#define TRUE 1#endif#ifndef FALSE#define FALSE 0#endif //图片显示物理层接口//在移植的时候,必须由用户自己实现这几个函数typedef struct {u32(*read_point)(u16,u16); //u32 read_point(u16 x,u16 y)读点函数void(*draw_point)(u16,u16,u32); //void draw_point(u16 x,u16 y,u32 color)画点函数void(*fill)(u16,u16,u16,u16,u32);//void fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color) 单色填充函数void(*draw_hline)(u16,u16,u16,u16);//void draw_hline(u16 x0,u16 y0,u16 len,u16 color) 画水平线函数void(*fillcolor)(u16,u16,u16,u16,u16*);//void piclib_fill_color(u16 x,u16 y,u16 width,u16 height,u16 *color) 颜色填充}_pic_phy; extern _pic_phy pic_phy;/图像信息typedef struct{u16 lcdwidth; //LCD 的宽度u16 lcdheight; //LCD 的高度u32 ImgWidth; //图像的实际宽度和高度u32 ImgHeight;u32 Div_Fac; //缩放系数 (扩大了 8192 倍的)u32 S_Height; //设定的高度和宽度u32 S_Width;u32 S_XOFF; //x 轴和 y 轴的偏移量u32 S_YOFF;u32 staticx; //当前显示到的xy坐标u32 staticy;}_pic_info;extern _pic_info picinfo;//图像信息///void piclib_fill_color(u16 x,u16 y,u16 width,u16 height,u16 *color);…//此处省略部分函数声明void pic_memfree (void* mf); //pic 释放内存///#endif

这里基本就是我们前面提到的两个结构体的定义以及一些函数的申明,相信大家很容易明

白。最后我们看看 main.c 文件内容如下:

//得到 path 路径下,目标文件的总个数

//path:路径 //返回值:总有效文件数u16 pic_get_tnum(u8 *path){ u8 res;u16 rval=0;DIR tdir; //临时目录FILINFO *tfileinfo; //临时文件信息 tfileinfo=(FILINFO*)mymalloc(SRAMIN,sizeof(FILINFO));//申请内存 res=f_opendir(&tdir,(const TCHAR*)path); //打开目录if(res==FR_OK&&tfileinfo){while(1)//查询总的有效文件数{ res=f_readdir(&tdir,tfileinfo); //读取目录下的一个文件  if(res!=FR_OK||tfileinfo->fname[0]==0)break;//错误了/到末尾了,退出res=f_typetell((u8*)tfileinfo->fname);if((res&0XF0)==0X50)//取高四位,看看是不是图片文件{rval++;//有效文件数增加 1 } } } myfree(SRAMIN,tfileinfo);//释放内存return rval;}int main(void){u8 res;DIR picdir; //图片目录FILINFO *picfileinfo; //文件信息u8 *pname; //带路径的文件名u16 totpicnum; //图片文件总数u16 curindex; //图片当前索引u8 key; //键值u8 pause=0; //暂停标记u8 t;u16 temp;u32 *picoffsettbl; //图片文件 offset 索引表  Cache_Enable(); //打开 L1-Cache   MPU_Memory_Protection(); //保护相关存储区域 HAL_Init(); //初始化 HAL 库 Stm32_Clock_Init(432,25,2,9); //设置时钟,216Mhz  delay_init(216); //延时初始化uart_init(115200); //串口初始化usmart_dev.init(108); //初始化 USMART LED_Init(); //初始化 LED KEY_Init(); //初始化按键 SDRAM_Init(); //初始化 SDRAM LCD_Init(); //初始化 LCDW25QXX_Init(); //初始化 W25Q256my_mem_init(SRAMIN); //初始化内部内存池my_mem_init(SRAMEX); //初始化外部内存池my_mem_init(SRAMDTCM); //初始化 CCM 内存池exfuns_init(); //为 fatfs 相关变量申请内存 f_mount(fs[0],"0:",1); //挂载 SD 卡f_mount(fs[1],"1:",1); //挂载 FLASH.f_mount(fs[2],"2:",1); //挂载 NAND FLASH.POINT_COLOR=RED; while(font_init()) //检查字库{ LCD_ShowString(30,50,200,16,16,"Font Error!");delay_ms(200); LCD_Fill(30,50,240,66,WHITE);//清除显示 delay_ms(200); } Show_Str(30,50,200,16,"阿波罗 STM32F4/F7 开发板",16,0); Show_Str(30,70,200,16,"图片显示程序",16,0); Show_Str(30,90,200,16,"KEY0:NEXT KEY2:PREV",16,0); Show_Str(30,110,200,16,"KEY_UP:PAUSE",16,0); Show_Str(30,130,200,16,"正点原子@ALIENTEK",16,0); Show_Str(30,150,200,16,"2016 年 7 月 15 日",16,0);while(f_opendir(&picdir,"0:/PICTURE"))//打开图片文件夹{ Show_Str(30,170,240,16,"PICTURE 文件夹错误!",16,0);delay_ms(200); LCD_Fill(30,170,240,186,WHITE);//清除显示 delay_ms(200); } totpicnum=pic_get_tnum("0:/PICTURE"); //得到总有效文件数 while(totpicnum==NULL)//图片文件为 0 { Show_Str(30,170,240,16,"没有图片文件!",16,0);  delay_ms(200); LCD_Fill(30,170,240,186,WHITE);//清除显示 delay_ms(200); } picfileinfo=(FILINFO*)mymalloc(SRAMIN,sizeof(FILINFO)); //申请内存pname=mymalloc(SRAMIN,_MAX_LFN*2+1); //为带路径的文件名分配内存picoffsettbl=mymalloc(SRAMIN,4*totpicnum); //申请 4*totpicnum 个字节的内存//用于存放图片索引while(!picfileinfo||!pname||!picoffsettbl) //内存分配出错{ Show_Str(30,170,240,16,"内存分配失败!",16,0);delay_ms(200); LCD_Fill(30,170,240,186,WHITE);//清除显示 delay_ms(200); } //记录索引 res=f_opendir(&picdir,"0:/PICTURE"); //打开目录if(res==FR_OK){curindex=0;//当前索引为 0while(1)//全部查询一遍{temp=picdir.dptr; //记录当前 dptr 偏移 res=f_readdir(&picdir,picfileinfo); //读取目录下的一个文件 if(res!=FR_OK||picfileinfo->fname[0]==0)break; //错误了/到末尾了,退出res=f_typetell((u8*)picfileinfo->fname);if((res&0XF0)==0X50)//取高四位,看看是不是图片文件{picoffsettbl[curindex]=temp;//记录索引curindex++;} } } Show_Str(30,170,240,16,"开始显示...",16,0); delay_ms(1500);piclib_init(); //初始化画图 curindex=0; //从 0 开始显示 res=f_opendir(&picdir,(const TCHAR*)"0:/PICTURE"); //打开目录while(res==FR_OK)//打开成功{dir_sdi(&picdir,picoffsettbl[curindex]); //改变当前目录索引  res=f_readdir(&picdir,picfileinfo); //读取目录下的一个文件  if(res!=FR_OK||picfileinfo->fname[0]==0)break; //错误了/到末尾了,退出strcpy((char*)pname,"0:/PICTURE/"); //复制路径(目录)strcat((char*)pname,(const char*)picfileinfo->fname);//将文件名接在后面LCD_Clear(BLACK);ai_load_picfile(pname,0,0,lcddev.width,lcddev.height,1);//显示图片 Show_Str(2,2,lcddev.width,16,pname,16,1); //显示图片名字t=0;while(1) {key=KEY_Scan(0); //扫描按键if(t>250)key=1; //模拟一次按下 KEY0 if((t%20)==0)LED0_Toggle;//LED0 闪烁,提示程序正在运行.if(key==KEY2_PRES) //上一张{if(curindex)curindex--;else curindex=totpicnum-1;break;}else if(key==KEY0_PRES)//下一张{curindex++; if(curindex>=totpicnum)curindex=0;//到末尾的时候,自动从头开始break;}else if(key==WKUP_PRES){pause=!pause;LED1(!pause); //暂停的时候 LED1 亮. }if(pause==0)t++;delay_ms(10); } res=0; } myfree(SRAMIN,picfileinfo); //释放内存 myfree(SRAMIN,pname); //释放内存 myfree(SRAMIN,picoffsettbl); //释放内存 }

此部分除了 main 函数,还有一个 pic_get_tnum 的函数,用来得到 path 路径下,所有有效

文件(图片文件)的个数。在 main 函数里面我们通过读/写偏移量(图片文件在 PICTURE 文件

夹下的读/写偏移位置,可以看做是一个索引),来查找上一个/下一个图片文件,这里我们需要

用到 FATFS 自带的一个函数:dir_sdi,来设置当前目录的偏移量(因为 f_readdir 只能沿着偏移

位置一直往下找,不能往上找),方便定位到任何一个文件。dir_sdi 在 FATFS 下面被定义为 static

函数,所以我们必须在 ff.c 里面将该函数的 static 修饰词去掉,然后在 ff.h 里面添加该函数的申

明,以便 main 函数使用。

其他部分就比较简单了,至此,整个图片显示实验的软件设计部分就结束了。该程序将实

现浏览 PICTURE 文件夹下的所有图片,并显示其名字,每隔 3s 左右切换一幅图片。

49.4 下载验证

在代码编译成功之后,我们下载代码到 ALIENTEK 阿波罗 STM32 开发板上,可以看到 LCD

开始显示图片(假设 SD 卡及文件都准备好了,即:在 SD 卡根目录新建:PICTURE 文件夹,

并存放一些图片文件(.bmp/.jpg/.gif)在该文件夹内),如图 49.4.1 所示:

图 49.4.1 图片显示实验显示效果

按 KEY0 和 KEY2 可以快速切换到下一张或上一张,KEY_UP 按键可以暂停自动播放,同

时 DS1 亮,指示处于暂停状态,再按一次 KEY_UP 则继续播放。同时,由于我们的代码支持

gif 格式的图片显示(注意尺寸不能超过 LCD 屏幕尺寸),所以可以放一些 gif 图片到 PICTURE

文件夹,来看动画了。

本章,同样可以通过 USMART 来测试该实验,将 ai_load_picfile 函数加入 USMART 控制

(方法前面已经讲了很多次了),就可以通过串口调用该函数,在屏幕上任何区域显示任何你想

要显示的图片了!同时,可以发送:runtime 1,来开启 USMART 的函数执行时间统计功能,从

而获取解码一张图片所需时间,方便验证。

c语言头文件格式图片_阿波罗 STM32F767 开发板资料连载第四十九章 图片显示实验...相关推荐

  1. pdfstamper生成pdf无法显示汉字_正点原子STM32F4/F7水星开发板资料连载第四十六章 汉字显示实验...

    1)实验平台:正点原子水星 STM32F4/F7 开发板 2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 3)全套实验源码+手册+视频下载 ...

  2. 光盘显示0字节可用_正点原子STM32F4/F7水星开发板资料连载第四十六章 汉字显示实验

    1)实验平台:正点原子水星 STM32F4/F7 开发板 2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 3)全套实验源码+手册+视频下载 ...

  3. application.properties 不识别_阿波罗 STM32F767 开发板资料连载第五十八章 手写识别实验

    1)实验平台:alientek 阿波罗 STM32F767 开发板2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 第五十八章 手写识别实验 ...

  4. stm32l0的停止模式怎么唤醒_「正点原子STM32Mini板资料连载」第十九章 待机唤醒实验...

    1)实验平台:正点原子STM32mini开发板 2)摘自<正点原子STM32 不完全手册(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 第十九章 待机唤醒实验 本章我们将向 ...

  5. 判断按键值_「正点原子NANO STM32开发板资料连载」第十六章电容触摸按键实验...

    1)实验平台:ALIENTEK NANO STM32F411 V1开发板2)摘自<正点原子STM32F4 开发指南(HAL 库版>关注官方微信号公众号,获取更多资料:正点原子 第十六章电容 ...

  6. fastreport masterdata每页都显示_ALIENTEK 阿波罗 STM32F767 开发板资料连载十六章 OLED 显示实验...

    1)实验平台:alientek 阿波罗 STM32F767 开发板2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 http://weixi ...

  7. 判断按键值_ALIENTEK 阿波罗 STM32F767 开发板资料连载第七章 按键输入实验

    1)实验平台:alientek 阿波罗 STM32F767 开发板2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 第七章 按键输入实验 上 ...

  8. stm32f767中文手册_ALIENTEK 阿波罗 STM32F767 开发板资料连载第五章 SYSTEM 文件夹

    1)实验平台:alientek 阿波罗 STM32F767 开发板2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 第五章 SYSTEM 文 ...

  9. cc2530定时器和捕获比较_ALIENTEK 阿波罗 STM32F767 开发板资料连载十四章 输入捕获实验...

    1)实验平台:alientek 阿波罗 STM32F767 开发板2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 http://weixi ...

最新文章

  1. 你想学Java?资源都在这里了
  2. 一文就懂Kotlin作用域函数以及object关键字
  3. paho mqtt client调试记录
  4. node.js项目中常量的配置 - 个人文章 - SegmentFault 思否
  5. CLion 中使用 clang-format
  6. 先河系统为你讲解私有云服务器的优点
  7. java中地图查询比较慢,在java中缓慢的地图
  8. C# 遍历DLL导出函数
  9. 在ASP.NET中使用AJAX的简单方法 转载
  10. TypeScript:运算符
  11. [转]关于PSP的3.52 M33-2自制系统七大热点问题
  12. SPSS因子分析经典案例分享
  13. FFmpeg mxf扩展hdr、bt2020
  14. 区块链专利申请全球过半 厉害了我的国
  15. php亲戚称谓计算源码,亲戚称呼(亲戚关系计算器在线)
  16. 必看!2021年云计算行业五大趋势,云南昆明企业小型云计算平台搭建及解决方案
  17. urovo手持终重启_手持终端设备常见问题及维修方法
  18. 编写Java程序,模拟教练员和运动员出国比赛场景,其中运动员包括乒乓球运动员和篮球运动员。教练员包括乒乓球教练和篮球教练。为了方便出国交流,根乒乓球相关的人员都需要学习英语。
  19. MAC 删除默认的ABC输入法
  20. Windows10下Node版本管理与随意切换

热门文章

  1. Uncaught (in promise) Error: Avoided redundant navigation to current location: “/index“. 解决方法
  2. ise生成msk文件的用处_ISE中上载程序出错,msk文件缺失有关问题
  3. swift 项目_谷歌为何要养苹果的亲儿子Swift?原来意在可微分编程
  4. excanvas让canvas兼容ie7,8
  5. Exchange Server 2016管理系列课件03.管理邮箱配额限制
  6. Android JNI(实现自己的JNI_OnLoad函数)
  7. TCL——事务控制语言
  8. 离线计算框架MapReduce
  9. 许三多修路带给我们成功的启示
  10. 用计算机弹雅俗共赏,聊聊雅俗共赏:钢琴、饺子和面