教程不断更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429
第20章 emWin6.x存储设备之基本函数
本章节为大家讲解存储设备之基本函数,存储设备比较重要,如果想做出比较华丽,流畅的界面得靠这个。另外把存储设备放在本章节讲解是因为下个章节讲解BMP,JPG和GIF的图片显示要用到。
20.1 初学者重要提示
20.2 存储设备基础知识
20.3 存储设备基本函数及其应用
20.4 实验例程说明(RTOS)
20.5 实验例程说明(裸机)
20.6 总结
20.1 初学者重要提示
- 相对来说,存储设备章节还是比较重要的,初学者只需掌握本章节讲到的函数即可。未讲解的函数也有很多,以后的工程中用到的时候再查阅即可。
- 存储设备的的所有API函数在emWin手册中都有讲解,下图是中文版手册里面API函数的位置
下图是英文版手册里面API函数的位置:
20.2 存储设备基础知识
说明:介绍知识整理自emWin官方手册。
20.2.1 什么是存储设备
存储设备就是指的emWin的动态内存,操作存储设备就是操作emWin动态内存,只是对于这种类型的使用起了一个名字叫存储设备。
存储设备主要用于防止在绘制重叠项目时出现显示器闪烁。其基本思想很简单,不使用存储设备时,绘制操作直接写入显示器,屏幕在执行绘制操作时随时更新,导致在进行各种更新时使屏幕闪烁。例如,如果要在背景中绘制一个位图,在前景中绘制一些透明文本,应首先绘制位图,然后绘制文本,效果将使文本出现闪烁。但是,如果在此过程中使用存储设备,则所有绘制操作都在存储器中执行,仅在所有操作都完成后才将最终结果显示在屏幕上,其优点是没有闪烁。
下面我们通过一个实例来说明使用存储设备和不使用存储设备的区别。两种情况下的目的是相同的:将蓝色背景旋转10°,字符不旋转。
- 第一种情况下:不使用存储设备,屏幕必须清除,然后在新位置重绘多边形,并写入带新标志的字符串。
- 第二种情况下:使用存储设备,在存储器中执行相同的操作,但屏幕此时不更新。仅在调用 GUI_MEMDEV_CopyToLCD() 例程时出现更新,并且仅更新一次就反映出所有操作。请注意,这两种操作步骤的初始状态和最终输出是相同的。
通过上面四步对比可以发现:如果不使用存储设备,则可以看到一步步的绘制操作效果,缺点是会出现显示器闪烁。使用存储设备时,仅更新一次可见到所有操作的效果,就象单次操作一样,不能实际看见中间步骤,其优点是完全消除了显示器的闪烁,这个就是使用存储设备的优势。
20.2.2 支持的颜色深度(bpp)
bpp的含义是bit per pixel,即每个像素点由几位来表示,比如1bpp就表示每个像素点由1位二进制数来表示,8bpp就是由8位二进制数来表示,依此类推。
存储设备有 4 种不同的色彩深度可用:1bpp、 8bpp、 16bpp 和 32bpp。emWin支持两种存储设备的创建方式。
- 自动创建与显示屏颜色格式兼容的存储设备
有两种创建与显示屏颜色格式兼容的存储设备的方法。如果要避免闪烁,则应创建与显示器兼容的存储设备。兼容的存储设备必须具有与显示器相同或更高的色彩深度。如果使用了函数 GUI_MEMDEV_Create()、GUI_MEMDEV_CreateEx(),则 emWin 会自动为显示器选择正确类型的存储设备。窗口管理器也能为系统中的某些或全部窗口使用存储设备,同样也使用这些函数。这样会自动使用具有最低色彩深度(消耗动态内存最小)的存储设备。
- 创建指定颜色格式的存储设备
通过函数GUI_MEMDEV_CreateFixed()来实现创建指定颜色格式的存储设备。
20.2.3 存储设备和窗口管理器
(注意,窗口管理器在后面的章节中会讲到,这里作为了解内容即可)
窗口管理器可与存储设备完美搭配。每个窗口都有一个标记,告诉窗口管理器是否应使用存储设备进行渲染。此标记可以在创建窗口时指定,也可在任何时候进行设置或者重设。如果为特定窗口设置了存储设备标记,则窗口管理器在绘制窗口时自动使用存储设备。它会在绘制窗口前创建一个存储设备,然后在绘制操作完成后将其删除。如果有足够的内存可用,会将整个窗口装入窗口管理器所创建存储设备的内存中。如果没有足够的内存将整个窗口装入存储设备中,则窗口管理器使用“分段”来绘制窗口。用于绘制操作的内存仅在绘制操作期间分配。如果在绘制或者重绘窗口时没有足够的内存可用,则不使用存储设备重绘窗口。
20.2.4 基本函数用法
以下是使用存储设备时通常的使用流程,比较容易:
1. 创建存储设备(使用 GUI_MEMDEV_Create()等函数)。
2. 激活它(使用 GUI_MEMDEV_Select())。
3. 执行绘制操作。
4. 将结果复制到显示器中 (使用 GUI_MEMDEV_CopyToLCD()等函数)。
5. 不再需要它时,删除该存储设备 (使用 GUI_MEMDEV_Delete())。
20.3 存储设备基本函数及其应用
存储设备相关的API函数也非常多,这里我们选择几个常用的函数进行说明。
20.3.1 存储设备创建函数
存储设备的创建主要有以下三个函数:
- GUI_MEMDEV_Handle GUI_MEMDEV_Create(int x0, int y0, int XSize, int YSize)
在位置x0,y0创建长为Xsize,宽为Ysize的存储设备,即一块显示区。此函数会创建与显示器颜色格式兼容的存储设备(比如,STM32F429支持8种颜色格式设置,存储设备的创建就与这些颜色格式兼容)。
- GUI_MEMDEV_Handle GUI_MEMDEV_CreateEx(int x0, int y0,int XSize, int Ysize,int Flags))
此函数与上面的函数功能一样,只是多了一个参数flag,此参数有两种数值可以取:
-
- GUI_MEMDEV_HASTRANS
实际应用中推荐使用这个标志,表示使用透明性标记创建存储设备,该标记确保正确绘制背景。
使用此参数时,等效于函数GUI_MEMDEV_Create。
-
- GUI_MEMDEV_NOTRANS
创建存储设备,无透明性。优势是速度较快,使用此标记可加速存储设备约 30% - 50%,且可将存储设备用于非矩形区域。缺点是用户必须确保正确绘制背景。
- GUI_MEMDEV_Handle GUI_MEMDEV_CreateFixed(int x0, int y0,
Int xSize, int ySize, int Flags,
const tLCDDEV_APIList * pMemDevAPI,
constLCD_API_COLOR_CONV * pColorConvAPI);
此函数用于创建指定颜色格式的存储设备,这个函数涉及参数较多,我们这里不再进行说明,具体参数看emWin官方手册的API函数说明即可,实际调用是比较容易的。
下面是在模拟器上实际运行的例子,可以在模拟器上面运行的完整例子代码在V7-518_emWin6.x实验_存储设备之基础函数(模拟器)里面。
#include "GUI.h" #include "stdio.h" #ifndef GUI_CONST_STORAGE #define GUI_CONST_STORAGE const #endif extern GUI_CONST_STORAGE GUI_BITMAP bmpic; static GUI_CONST_STORAGE unsigned short _acpic[] = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFDE, 0xFFBE, 0xFFBE, 0xFFBE, 0xFFBE, 0xFFBE, 0xFFBE, 0xFFDE, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFBD, 0xF75B, 0xF6F9, 0xF697, 0xEE34, 0xEE13, 0xEDD1, 0xEDD1, 0xEDD1, 0xEDD1, 0xEDD1, 0xEDD1, 0xEE13, 0xEE55, 0xF6B7, 0xF71A, 0xF75C, 0xFFBE, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, /* 后面的数据未列出 */ }; GUI_CONST_STORAGE GUI_BITMAP bmpic = { 64, // xSize 64, // ySize 128, // BytesPerLine 16, // BitsPerPixel (unsigned char *)_acpic, // Pointer to picture data NULL, // Pointer to palette GUI_DRAW_BMP565 }; static GUI_CONST_STORAGE unsigned long _acpic1[] = { 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, /* 后面的数据未列出 */ }; GUI_CONST_STORAGE GUI_BITMAP bmpic1 = { 64, // xSize 64, // ySize 256, // BytesPerLine 32, // BitsPerPixel (unsigned char *)_acpic1, // Pointer to picture data NULL, // Pointer to palette GUI_DRAW_BMP8888 } /********************************************************************* * * MainTask */ void MainTask(void) { GUI_MEMDEV_Handle hMem0; GUI_MEMDEV_Handle hMem1; GUI_MEMDEV_Handle hMem2; GUI_MEMDEV_Handle hMem3; /* emWin初始化 */ GUI_Init(); /* 设置字体 */ GUI_SetFont(&GUI_Font16B_ASCII); //////////////////////////方式一///////////////////////////////////// /* 创建内存设备,并将RGB565格式的位图绘制到内存设备上 */ hMem0 = GUI_MEMDEV_CreateEx(0, 0, 64, 64, GUI_MEMDEV_HASTRANS); GUI_MEMDEV_Select(hMem0); GUI_DrawBitmap(&bmpic, 0, 0); GUI_MEMDEV_Select(0); /* 显示RGB565格式的位图 */ GUI_DispStringAt("This is RGB565 bitmap & GUI_MEMDEV_CreateEx", 100, 50); GUI_MEMDEV_WriteAt(hMem0, 20, 20); ////////////////////////////方式二/////////////////////////////////// /* 创建内存设备,并将RGB565格式的位图绘制到内存设备上 */ hMem1 = GUI_MEMDEV_CreateFixed(0, 0, 64, 64, GUI_MEMDEV_HASTRANS, GUI_MEMDEV_APILIST_16, GUI_COLOR_CONV_565); GUI_MEMDEV_Select(hMem1); GUI_DrawBitmap(&bmpic, 0, 0); GUI_MEMDEV_Select(0); /* 显示RGB565格式的位图 */ GUI_DispStringAt("This is RGB565 bitmap & GUI_MEMDEV_CreateFixed", 100, 150); GUI_MEMDEV_WriteAt(hMem1, 20, 120); //////////////////////////////方式三///////////////////////////////// /* 创建内存设备,并将ARGB8888格式的位图绘制到内存设备上 */ hMem2 = GUI_MEMDEV_CreateEx(0, 0, 64, 64, GUI_MEMDEV_HASTRANS); GUI_MEMDEV_Select(hMem2); GUI_DrawBitmap(&bmpic1, 0, 0); GUI_MEMDEV_Select(0); /* 显示ARGB8888格式的位图 */ GUI_DispStringAt("This is ARGB8888 bitmap & GUI_MEMDEV_CreateEx", 100, 250); GUI_MEMDEV_WriteAt(hMem2, 20, 220); ////////////////////////////////方式四/////////////////////////////// /* 创建内存设备,并将ARGB8888格式的位图绘制到内存设备上 */ hMem3 = GUI_MEMDEV_CreateFixed(0, 0, 64, 64, GUI_MEMDEV_HASTRANS, GUI_MEMDEV_APILIST_32, GUI_COLOR_CONV_8888); GUI_MEMDEV_Select(hMem3); GUI_DrawBitmap(&bmpic1, 0, 0); GUI_MEMDEV_Select(0); /* 显示ARGB8888格式的位图 */ GUI_DispStringAt("This is ARGB8888 bitmap & GUI_MEMDEV_CreateFixed", 100, 350); GUI_MEMDEV_WriteAt(hMem3, 20, 320); while (1) { GUI_Delay(10); } } /*************************** End of file ****************************/
实际显示效果如下,分辨率600*400:
20.3.2 存储设备的选择和显示函数
在20.3.1小节的例子中,我们用到了存储设备选择函数和显示函数:
- void GUI_MEASDEV_Select (GUI_MEASDEV_Handle hMem)
此函数用于选择要使用的存储设备,打算在哪个存储设备上面进行绘制操作,参数就添加哪个存储设备的句柄,。如果参数填为0,将激活LCD,即绘制操作是在LCD上面进行的,而不是在存储设备上面进行的。
- void GUI_MEMDEV_WriteAt(GUI_MEMDEV_Handle hMem, int x, int y);
此函数用于将存储设备的内容绘制到LCD显示屏上。
20.3.3 存储设备的其它函数
存储设备的还有很多其它的函数,我们这里暂时不做讲解了,20.3.1和20.3.2小节中的函数是实际项目中用到最多的,其余的函数在emWin的官方手册中大部分都有举例说明,可以在模拟器上面运行下,看看实际的效果。另外在我们论坛的这个帖子中也有其它部分函数说明,有兴趣可以看下:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=1892 。
20.4 实验例程说明(RTOS)
配套例子:
V7-520_emWin6.x实验_存储设备之基础函数(RTOS)
实验目的:
- 学习emWin的存储设备之基本函数。
- emWin功能的实现在MainTask.c文件里面。
实验内容:
1、K1按键按下,串口或者RTT打印任务执行情况(串口波特率115200,数据位8,奇偶校验位无,停止位1)。
2、(1) 凡是用到printf函数的全部通过函数App_Printf实现。
(2) App_Printf函数做了信号量的互斥操作,解决资源共享问题。
3、默认上电是通过串口打印信息,如果使用RTT打印信息:
MDK AC5,MDK AC6或IAR通过使能bsp.h文件中的宏定义为1即可
#define Enable_RTTViewer 1
4、各个任务实现的功能如下:
App Task Start 任务 :启动任务,这里用作BSP驱动包处理。
App Task MspPro任务 :消息处理,这里用作LED闪烁。
App Task UserIF 任务 :按键消息处理。
App Task COM 任务 :暂未使用。
App Task GUI 任务 :GUI任务。
μCOS-III任务调试信息(按K1按键,串口打印):
RTT 打印信息方式:
程序设计:
- 任务栈大小分配:
μCOS-III任务栈大小在app_cfg.h文件中配置:
#define APP_CFG_TASK_START_STK_SIZE 512u
#define APP_CFG_TASK_MsgPro_STK_SIZE 2048u
#define APP_CFG_TASK_COM_STK_SIZE 512u
#define APP_CFG_TASK_USER_IF_STK_SIZE 512u
#define APP_CFG_TASK_GUI_STK_SIZE 2048u
任务栈大小的单位是4字节,那么每个任务的栈大小如下:
App Task Start 任务 :2048字节。
App Task MspPro任务 :8192字节。
App Task UserIF 任务 :2048字节。
App Task COM 任务 :2048字节。
App Task GUI 任务 :8192字节。
- 系统栈大小分配:
μCOS-III的系统栈大小在os_cfg_app.h文件中配置:
#define OS_CFG_ISR_STK_SIZE 512u
系统栈大小的单位是4字节,那么这里就是配置系统栈大小为2KB
emWin动态内存配置:
GUIConf.c文件中的配置如下:
#define EX_SRAM 1/*1 used extern sram, 0 used internal sram */ #if EX_SRAM #define GUI_NUMBYTES (1024*1024*24) #else #define GUI_NUMBYTES (100*1024) #endif
通过宏定义来配置使用内部SRAM还是外部的SDRAM做为emWin的动态内存,当配置:
#define EX_SRAM 1 表示使用外部SDRAM作为emWin动态内存,大小24MB。
#define EX_SRAM 0 表示使用内部SRAM作为emWin动态内存,大小100KB。
默认情况下,本教程配套的所有emWin例子都是用外部SDRAM作为emWin动态内存。
emWin界面显示效果:
800*480分辨率界面效果。
20.5 实验例程说明(裸机)
配套例子:
V7-520_emWin6.x实验_存储设备之基础函数(RTOS)
实验目的:
- 学习emWin的存储设备之基本函数。
- emWin功能的实现在MainTask.c文件里面。
emWin界面显示效果:
800*480分辨率界面效果。
emWin动态内存配置:
GUIConf.c文件中的配置如下:
#define EX_SRAM 1/*1 used extern sram, 0 used internal sram */ #if EX_SRAM #define GUI_NUMBYTES (1024*1024*24) #else #define GUI_NUMBYTES (100*1024) #endif
通过宏定义来配置使用内部SRAM还是外部的SDRAM做为emWin的动态内存,当配置:
#define EX_SRAM 1 表示使用外部SDRAM作为emWin动态内存,大小24MB。
#define EX_SRAM 0 表示使用内部SRAM作为emWin动态内存,大小100KB。
默认情况下,本教程配套的所有emWin例子都是用外部SDRAM作为emWin动态内存。
20.6 总结
本章节主要为大家讲解了存储设备里面几个常用的函数,还有很多其它函数没有做讲解,有兴趣的话,这些没有讲到的函数可以练习下。