|
特别说明:pdf版60期emWin教程已经发布:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=2932
armfly-x2,x3,v2,v3,v5开发板裸机和带系统的emWin工程已经全部建立,链接如下:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=1830
存储设备比较重要,如果想做出比较华丽,流畅的界面必须靠这个和前面的2-D绘图,做这期教程
花的时间比较长,时间是以前教程的两倍时间,主要是很多实验例子都要做验证。
存储设备可在各种情况下使用,主要用于防止在绘制重叠项目时出现显示器闪烁。其基本思想很简
单。不使用存储设备时,绘制操作直接写入显示器。屏幕在执行绘制操作时随时更新,从而在进行各种
更新时使屏幕闪烁。例如,如果要在背景中绘制一个位图,在前景中绘制一些透明文本,应首先绘制位
图,然后绘制文本。效果将是文本出现闪烁。但是,如果在此过程中使用存储设备,则所有绘制操作都
在存储器中执行。仅在所有操作都完成后才将最终结果显示在屏幕上,其优点是没有闪烁。在下节的示
例中可以看到这种差异,该示例展示了在使用和不使用存储设备时的一系列绘制操作。
差别可归纳如下:如果不使用存储设备,则可以看到一步步的绘制操作效果,缺点是会出现显示器
闪烁。使用存储设备时,一次可见到所有例程的效果,就象单次操作一样,不能实际看见中间步骤。如
上所述,其优点是完全消除了显示器的闪烁,这也是通常所期望的。
本期分为四个小节:
16. 1 存储设备基础知识
16. 2 存储设备基本函数及其应用
16. 3 移植到armfly-v5开发板上面一个例子
16. 4 实验总结
16. 1 存储设备基础知识
下面的基础知识全部来自官方手册。
16.1.1 使用存储设备:图示(这个图示很好的说明了问题)
下表所示为同一操作在使用和不使用存储设备时的屏幕截图。两种情况下的目的是相同的:
旋转工件并分别标志旋转角度 (此处为10度)。第一种情况下 (不使用存储设备),屏幕必须
清除,然后在新位置重绘多边形,并写入带新标志的字符串。第二种情况下 (使用存储设备),
在存储器中执行相同的操作,但屏幕此时不更新。仅在调用GUI_MEMDEV_CopyToLCD()例程时
出现更新,并且此更新一次就反映所有操作。请注意,这两种操作步骤的初始状态和最终输出是
相同的。
16.1.2 存储设备和窗口管理器
窗口管理器可与存储设备完美搭配。每个窗口都有一个标记,告诉窗口管理器是否应使用存储设
备进行渲染。此标记可以在创建窗口时指定,也可在任何时候进行设置/重设。
如果为特定窗口设置了存储设备标记,则WM在绘制窗口时自动使用存储设备。它会在绘制窗口前创
建一个存储设备,然后在绘制操作完成后将其删除。如果有足够的内存可用,会将整个窗口装入WM
所创建存储设备的内存中。如果没有足够的内存可用于将整个窗口装入一个存储设备中,则WM使用
“分段”来绘制窗口。有关 “分段”的详细信息,在文档的 “存储设备\ 分段存储设备”一章中说明。
用于绘制操作的内存仅在绘制操作期间分配。如果在绘制 (重绘)窗口时没有足够的内存可用,则不
使用存储设备重绘窗口。
16.1.3 基本函数用法
以下例程是在使用存储设备时通常会调用的,基本用法非常简单:
1. 创建存储设备 (使用GUI_MEMDEV_Create())。
2. 激活它 (使用GUI_MEMDEV_Select())。
3. 执行绘制操作。
4. 将结果复制到显示器中 (使用GUI_MEMDEV_CopyToLCD())。
5. 不再需要它时,删除该存储设备 (使用GUI_MEMDEV_Delete())。
其它的东西我就不复制过来了,有兴趣的好好看下手册这一章的介绍
16. 2 存储设备基本函数及其应用
存储设备的基本函数主要有以下这些函数。
下面举几个重要函数进行说明,提供的例子是可以直接在emWin模拟器上面运行的。
1. GUI_MEMDEV_CopyToLCDAA(),
使用的过程中有一点必须得注意,如果要显示的内容显示不全的话,需要增大创建的
存储设备大小,下面举一个例子
#include "GUI.h"
void MemInit(void)
{
GUI_MEMDEV_Handle hMem = GUI_MEMDEV_Create(0,0,180,45);
GUI_MEMDEV_Handle hMem1 = GUI_MEMDEV_Create(0,46,450,80);
/* 激活存储设备 (如果句柄为0则激活LCD) */
GUI_MEMDEV_Select(hMem);
GUI_SetFont(&GUI_Font8x16x3x3);
GUI_DispString("armfly");
/* 将存储设备(已抗锯齿处理的内容)复制到LCD */
GUI_MEMDEV_CopyToLCDAA(hMem);
GUI_MEMDEV_Select(hMem1);
GUI_SetFont(&GUI_FontD80);
GUI_DispStringAt("1234567", 0, 46);
/* 将存储设备(已抗锯齿处理的内容)复制到LCD */
GUI_MEMDEV_CopyToLCDAA(hMem1);
}
void MainTask(void)
{
GUI_Init();
MemInit();
while(1)
{
GUI_Delay(100);
}
}
当GUI_MEMDEV_Handle hMem1 = GUI_MEMDEV_Create(0,46,280,80);设置成这样的
时候,显示效果如下:
当GUI_MEMDEV_Handle hMem1 = GUI_MEMDEV_Create(0,46,450,80);设置成这样的
时候,显示效果如下:
2. GUI_MEMDEV_CreateFixed()
工程上面很多例子都用到了这个函数,这里举一个例子,首先来看看手册上面对这个函数的介绍:
创建固定尺寸、色彩深度(bpp)和指定色彩转换的存储设备。
下面举一个例子,首先把下面这个图片用位图转换器做转换。
第一步:
第二步:另存为的时候选择如下的格式
第三步: 得到相应的C文件,相应的C工程文件如下
GUI_CONST_STORAGE GUI_BITMAP bmlogo = {
198, // xSize
80, // ySize
396, // BytesPerLine
16, // BitsPerPixel
(unsigned char *)_aclogo, // Pointer to picture data
NULL, // Pointer to palette
GUI_DRAW_BMP565
};
void MemInit(void)
{
GUI_MEMDEV_Handle hMem0;
hMem0 = GUI_MEMDEV_CreateFixed(0, 0, 198, 80, GUI_MEMDEV_NOTRANS,
GUI_MEMDEV_APILIST_16,
GUI_COLOR_CONV_565);
GUI_MEMDEV_Select(hMem0);
GUI_DrawBitmap(&bmlogo, 0, 0);
GUI_MEMDEV_CopyToLCDAt(hMem0, 0, 0);
}
void MainTask(void)
{
GUI_Init();
MemInit();
while(1)
{
GUI_Delay(100);
}
}
完整的工程文件:
GUIDEMO_Start.zip
(7 KB, 下载次数: 342)
实验效果如下:
3. GUI_MEMDEV_DrawPerspectiveX()
函数介绍如下,有一点请注意,该函数目前仅用于色彩深度为32 bpp的存储设备和
彩深度为32 bpp的系统。
下面针对这个函数举一个例子,图片还是用的上面的armfly logo,只不过这次转换的格式
如下:
程序如下:
GUI_CONST_STORAGE GUI_BITMAP bmlogo = {
198, // xSize
80, // ySize
792, // BytesPerLine
32, // BitsPerPixel
(unsigned char *)_aclogo, // Pointer to picture data
NULL, // Pointer to palette
GUI_DRAW_BMP8888
};
void MemInit(void)
{
GUI_MEMDEV_Handle hMem0, hMem1, hMem2;
hMem0 = GUI_MEMDEV_CreateFixed(0, 0, 198, 80, GUI_MEMDEV_NOTRANS,
GUI_MEMDEV_APILIST_32,
GUI_COLOR_CONV_8888);
hMem1 = GUI_MEMDEV_CreateFixed(0, 0, 99, 80, GUI_MEMDEV_HASTRANS,
GUI_MEMDEV_APILIST_32,
GUI_COLOR_CONV_8888);
hMem2 = GUI_MEMDEV_CreateFixed(0, 0, 99, 80, GUI_MEMDEV_HASTRANS,
GUI_MEMDEV_APILIST_32,
GUI_COLOR_CONV_8888);
GUI_MEMDEV_Select(hMem0);
GUI_DrawBitmap(&bmlogo, 0, 0);
GUI_MEMDEV_Select(hMem1);
GUI_MEMDEV_DrawPerspectiveX(hMem0, 0, 0, 80, 50, 99, 15);
GUI_MEMDEV_Select(hMem2);
GUI_MEMDEV_DrawPerspectiveX(hMem0, 0, 15, 50, 80, 99, -15);
GUI_MEMDEV_CopyToLCDAt(hMem0, 0, 10);
GUI_MEMDEV_CopyToLCDAt(hMem1, 210, 10);
GUI_MEMDEV_CopyToLCDAt(hMem2, 320, 10);
}
void MainTask(void)
{
GUI_Init();
MemInit();
while(1)
{
GUI_Delay(100);
}
}
完整程序
GUIDEMO_Start1.zip
(11 KB, 下载次数: 234)
实验效果如下:
下面这个是在armfly-v5开发板上面跑的上面那个程序,
方法一:首先用内部RAM作为动态内存,由于内存动态内存不够申请三个,这里就只显示前两个
图片,显示效果如下:
程序修改为如下:
GUI_CONST_STORAGE GUI_BITMAP bmlogo = {
198, // xSize
80, // ySize
792, // BytesPerLine
32, // BitsPerPixel
(unsigned char *)_aclogo, // Pointer to picture data
NULL, // Pointer to palette
GUI_DRAW_BMP8888
};
void MemInit(void)
{
GUI_MEMDEV_Handle hMem0, hMem1, hMem2;
hMem0 = GUI_MEMDEV_CreateFixed(0, 0, 198, 80, GUI_MEMDEV_NOTRANS,
GUI_MEMDEV_APILIST_32,
GUI_COLOR_CONV_8888);
hMem1 = GUI_MEMDEV_CreateFixed(0, 0, 99, 80, GUI_MEMDEV_NOTRANS,
GUI_MEMDEV_APILIST_32,
GUI_COLOR_CONV_8888);
GUI_MEMDEV_Select(hMem0);
GUI_DrawBitmap(&bmlogo, 0, 0);
GUI_MEMDEV_Select(hMem1);
GUI_MEMDEV_DrawPerspectiveX(hMem0, 0, 0, 80, 50, 99, 15);
GUI_MEMDEV_CopyToLCDAt(hMem0, 0, 10);
GUI_MEMDEV_CopyToLCDAt(hMem1, 210, 10);
}
void MainTask(void)
{
GUI_Init();
MemInit();
while(1)
{
GUI_Delay(100);
}
}
方法二:使用外部2MB的SRAM作为动态内存,显示效果如下, 会发现有一次些错误的点,可能
是速度跟不上造成的。
程序要稍稍做点修改,主要修改下面的这三个,其它的不用改:
hMem0 = GUI_MEMDEV_CreateFixed(0, 0, 198, 80, GUI_MEMDEV_NOTRANS,
GUI_MEMDEV_APILIST_32,
GUI_COLOR_CONV_8888);
hMem1 = GUI_MEMDEV_CreateFixed(0, 0, 99, 80, GUI_MEMDEV_NOTRANS,
GUI_MEMDEV_APILIST_32,
GUI_COLOR_CONV_8888);
hMem2 = GUI_MEMDEV_CreateFixed(0, 0, 99, 80, GUI_MEMDEV_NOTRANS,
GUI_MEMDEV_APILIST_32,
GUI_COLOR_CONV_8888);
如果不做修改,显示效果是下面这样的,为什么会是这样的,大家可以思考一下。
4. GUI_MEMDEV_Rotate(), GUI_MEMDEV_RotateHQ()
这些函数旋转并缩放给定源存储设备。源设备将围绕其中心旋转和缩放,然后按给定的像素数移动。结果保存到
给定的目标存储设备中。两个函数之间的不同在于计算目标像素数据的算法。GUI_MEMDEV_Rotate()使用“最
近邻居”法,较快但不够准确。GUI_MEMDEV_RotateHQ()使用更复杂的方法,非常准确但比“最近邻居”法
慢。使用时请注意:两个存储设备 (源和目标)都需要是32位存储设备。任何其它情况下,函数都将立即返回。
下面举一个例子:
#include "GUI.h"
void MemInit(void)
{
GUI_MEMDEV_Handle hMemSource;
GUI_MEMDEV_Handle hMemDest;
GUI_RECT RectSource = {0, 0, 69, 39};
GUI_RECT RectDest = {0, 0, 79, 79};
hMemSource = GUI_MEMDEV_CreateFixed(RectSource.x0, RectSource.y0,
RectSource.x1 - RectSource.x0 + 1,
RectSource.y1 - RectSource.y0 + 1,
GUI_MEMDEV_NOTRANS,
GUI_MEMDEV_APILIST_32, GUI_COLOR_CONV_888);
hMemDest = GUI_MEMDEV_CreateFixed(RectDest.x0, RectDest.y0,
RectDest.x1 - RectDest.x0 + 1,
RectDest.y1 - RectDest.y0 + 1,
GUI_MEMDEV_NOTRANS,
GUI_MEMDEV_APILIST_32, GUI_COLOR_CONV_888);
GUI_MEMDEV_Select(hMemSource);
GUI_DrawGradientV(RectSource.x0, RectSource.y0,
RectSource.x1, RectSource.y1,
GUI_WHITE, GUI_DARKGREEN);
GUI_SetColor(GUI_BLUE);
GUI_SetFont(&GUI_Font20B_ASCII);
GUI_SetTextMode(GUI_TM_TRANS);
GUI_DispStringInRect("armfly", &RectSource, GUI_TA_HCENTER | GUI_TA_VCENTER);
GUI_DrawRect(0, 0, RectSource.x1, RectSource.y1);
GUI_MEMDEV_RotateHQ(hMemSource, hMemDest,
(RectDest.x1 - RectSource.x1) / 2,
(RectDest.y1 - RectSource.y1) / 2,
30 * 1000,
1000);
GUI_MEMDEV_CopyToLCDAt(hMemSource, 10, (RectDest.y1 - RectSource.y1) / 2);
GUI_MEMDEV_CopyToLCDAt(hMemDest, 100, 0);
}
void MainTask(void)
{
GUI_Init();
MemInit();
while(1)
{
GUI_Delay(100);
}
}
实现效果如下:
如果想在armfly-v5开发板上面跑的话,直接复制相应程序就可以,不用做任何修改。
5. GUI_MEMDEV_WriteExAt()
将给定存储设备的内容写入使用Alpha混合处理和缩放的当前选定存储设备的指定位置。
正对这个函数举一个例子:
#include "GUI.h"
void MainTask(void)
{
GUI_MEMDEV_Handle hMem0, hMem1;
GUI_Init();
hMem0 = GUI_MEMDEV_Create(0, 0, 100, 30);
hMem1 = GUI_MEMDEV_Create(0, 0, 200, 100);
GUI_MEMDEV_Select(hMem0);
GUI_SetTextMode(GUI_TM_TRANS);
GUI_SetFont(&GUI_Font32B_ASCII);
GUI_DispString("armfly");
GUI_MEMDEV_Select(hMem1);
GUI_SetBkColor(GUI_RED);
GUI_Clear();
GUI_DispStringAt("armfly", 0, 0);
GUI_MEMDEV_WriteExAt(hMem0, 0, 40, 2000, 2000, 160);
GUI_MEMDEV_CopyToLCD(hMem1);
while(1)
{
GUI_Delay(100);
}
}
实验效果如下:
16. 3 移植到armfly-v5开发板上面一个例子
提供一个armfly-v5开发板上面的例子,实验现象:
程序下载:
实验.zip
(15.76 MB, 下载次数: 674)
16. 4 实验总结
存储设备非常重要,希望大家认真学习。 |
|