基于F429使用EMWIN存储设备

F429BI 基于正点原子历程自己的理解和注意事项
本文是作者学习正点原子emwin的过程和学习心得,如果本文中有侵权,请联系作者删除,对你带来的不便请谅解。

存储设备基础理解

/*大概的流程分为以下几个步骤
1.先要定义你要显示的东西显示在什么区域
2.要创建存储设备,大概就是分配好内存吧(存储区域可以创建多个,就要定义多个句柄)
3.要把显示的东西放到哪个区域,选择哪个句柄,
4.绘制显示操作,
5.选中显示设备,
6.就可以开始显示了

*/

/*
对一些api的理解(错了可以指出来)
void GUI_MEMDEV_Clear(GUI_MEMDEV_Handle hMem);//操作的应该是存储设备
void GUI_MEMDEV_CopyFromLCD(GUI_MEMDEV_Handle hMem);//读回显示器的内容,并将其存储在给定内存设备中。
void GUI_MEMDEV_CopyToLCD(GUI_MEMDEV_Handle hMem);//将内存设备的内容从内存复制到 LCD。
void GUI_MEMDEV_CopyToLCDAt(GUI_MEMDEV_Handle hMem, int x, int y);//将内存设备的内容复制到 LCD 给定位置。
GUI_MEMDEV_Handle GUI_MEMDEV_Create(int x0, int y0, int xSize, int ySize);//创建内存设备。
void GUI_MEMDEV_Delete(GUI_MEMDEV_Handle MemDev);//不用这个显示了就把他删除,
*/

static GUI_RECT Rect = {100, 100, 400, 300}; //首先先创建好显示区域
void _DemoMemDev(void) 
{
	GUI_MEMDEV_Handle hMem;
	int i;
	hMem = GUI_MEMDEV_Create(Rect.x0, Rect.y0, Rect.x1 - Rect.x0, Rect.y1 - Rect.y0);	//创建存储设备
	GUI_MEMDEV_Select(hMem);	//选择hMem作为绘制操作目标的存储设备
	_Draw(0);  					//执行要显示的内容复制到存储设备中
	GUI_MEMDEV_Select(0);  		//选中LCD
		while (1)
		{
		for (i = 0; i < 3; i++) 
		{
			GUI_Delay(250);
			GUI_ClearRect(Rect.x0, Rect.y0, Rect.x1, Rect.y1);  //清除选中的屏幕
		GUI_Delay(250);
			GUI_MEMDEV_CopyToLCDAt(hMem, Rect.x0, Rect.y0); //将存储设备的内容从内存复制到LCD的指定位置			
		}
				GUI_Delay(500);
		}	
}

分段存储设备

内存不够,或者没办法一次性输出.
正点原子的是三个图形不断的变化,那这里我就先学学2D绘图,

2D绘图学习

void GUI_DrawPolygon(const GUI_POINT * pPoint, int NumPoints,int x, int y);//通过将终点连接到起点,绘制的多边形将自动闭合。
void GUI_FillPolygon(const GUI_POINT * pPoint, int NumPoints, int x, int y);//在当前窗口中绘制按点列表定义的填充的多边形。
const GUI_POINT aPoints[] = {
{ 40, 20},
{ 0, 20},
{ 20, 0}
};
#define SIZE_OF_ARRAY(Array) (sizeof(Array) / sizeof(Array[0])) //这个算法学习下,让你获取到有多少个一维数组

void GUI_RotatePolygon(GUI_POINT * pDest,const GUI_POINT * pSrc,int NumPoints,float Angle);//按指定角度旋转多边形

pDes指向目标多边形的指针
pSrc指向源多边形的指针
NumPoints在点列表中指定的点数
Angle用于旋转多边形的角度(弧度)

这个函数我想知道的的旋转点是不是第一个绘制点

经过研究发现,初始点就像坐标轴的原点,向右向下画,点的坐标就是正,向左向上坐标就是负
比如说你要根据哪个点旋转,你就应该把旋转点的坐标设置到初始点上。

const GUI_POINT aPoints[] = {
{-50, 0},
{-10, 10},
{ 0, 50},
{ 10, 10},
{ 50, 0},
{ 10,-10},
{ 0,-50},
{-10,-10}
};

分段显示理解

int GUI_MEMDEV_Draw(GUI_RECT * pRect, GUI_CALLBACK_VOID_P * pfDraw,void * pData, int NumLines,int Flags);//防止产闪烁的绘制函数。

pRect所使用 LCD 区域的 GUI_RECT 结构的指针。
pfDraw执行绘制的回调函数的指针。
pData用作回调函数参数的数据结构的指针。
NumLines 0(推荐)或内存设备的行数。
Flags(见下表)。
GUI_MEMDEV_HASTRANS默认:使用透明性标记创建内存设备,该标记确保正确绘制背景。
GUI_MEMDEV_NOTRANS (recommended)创建内存设备,无透明性。用户必须确保正确绘制背景。仅应用于优化目的

*1、我发现这里传进去的回调函数,貌似形参要是 (void ) 可以传入各种数据,到里面去强制转化就行;
2、还有一个值得说的就是,分段存储不需要申请内存,只需要把绘图的函数封装成函数,传入分段存储函数中

#define SIZE_OF_ARRAY(Array) (sizeof(Array) / sizeof(Array[0]))
static void _DrawIt(void * pData) //摘抄正点原子一部分画图函数
{
	GUI_Clear();//清屏
		GUI_SetColor(GUI_RED);//设置前景色
	GUI_FillPolygon((GUI_POINT *)pData, 8, 60, 60);//绘制填充多边形
	GUI_FillPolygon((GUI_POINT *)pData, 8, 120, 120);//绘制填充多边形
	GUI_SetTextMode(GUI_TEXTMODE_TRANS);//设置文字显示模式
	GUI_SetColor(GUI_GREEN);//设置前景色
		GUI_SetFont(&GUI_Font8x16x2x2);//设置字体大小
	GUI_DispStringHCenterAt("success!!!", 80, 40);//显示文字
}

//分段存储演示程序
void _DemoBandingMemdev(void) 
{
	 GUI_POINT aPoints1[8];//记录旋转后点的坐标,其实我觉得一个就够了,但是方便,就学正点的就好了
	int i;
	for (i = 0; i < 220; i++) 
		{
				float angle = i * 3.1415926 / 55;//改变旋转的角度
			
			GUI_RotatePolygon(aPoints1, aPoints, SIZE_OF_ARRAY(aPoints), angle);//旋转多边形,不显示
			GUI_RECT Rect = {0, 0, 320,170};//规定显示区域
			GUI_MEMDEV_Draw(&Rect,&_DrawIt,&aPoints1,0,0);//使用分段存储绘制
		//	GUI_Delay(40);
		}

}

自动设备对象

  1. 简介

自动设备对象,第一次调用绘制函数的时候,会绘制所有的项目,之后绘制,仅绘制更新移动或更改对象使用的空间,优势是计算时间少,刷新快,因为不会更新整个屏幕***。

2.自动设备对象API

int GUI_MEMDEV_CreateAuto(GUI_AUTODEV * pAutoDev);//创建自动设备对象。
void GUI_MEMDEV_DeleteAuto(GUI_AUTODEV * pAutoDev);//删除自动设备对象.
int GUI_MEMDEV_DrawAuto(GUI_AUTODEV *pAutoDev,GUI_AUTODEV_INFO * pAutoDevInfo,GUI_CALLBACK_VOID_P * pfDraw,void * pData);//使用分段内存设备执行指定绘制函数。
GUI_MEMDEV_DrawAuto()参数列表
pAutoDev指向 GUI_AUTODEV 对象的指针。
pAutoDevInfo指向 GUI_AUTODEV_INFO 对象的指针。
pfDraw指向要执行的用户定义绘制函数的指针。
pData指向传递给绘制函数的数据结构的指针。

附加信息
GUI_AUTODEV_INFO 结构包含用户函数必须绘制哪些项目的信息:
typedef struct {
char DrawFixed;
} GUI_AUTODEV_INFO;

  1. 分析正点原子代码
#define countof(Obj) (sizeof(Obj) / sizeof(Obj[0]))//获取数组有多少个一维数组,(不知道是不是这样叫)
//官方例程提供了一个函数
/*    GUI_COUNTOF(aPoints)    */

#define DEG2RAD      (3.1415926f / 180)
#define MAG          4

static const GUI_COLOR ColorsScaleR140[] = {
	0x000000, 0x00AA00, 0xFFFFFF, 0x0000AA,
	0x00FF00, 0xAEAEAE, 0x737373, 0xD3D3D3,
	0xDFDFDF, 0xBBDFBB, 0x6161DF, 0x61DF61,
	0xBBBBDF, 0xC7C7C7, 0x616193
};

//调色板
static const GUI_LOGPALETTE PalScaleR140 = {
	15,   //条目的数量
	0,    //无透明度
	&ColorsScaleR140[0]
};

static const unsigned char acScaleR140[] = {
};//位图数据省略

static const GUI_BITMAP bmScaleR140 = {
	200,          // XSize
	73,           // YSize
	100,          // BytesPerLine
	4,            // BitsPerPixel
	acScaleR140,  // Pointer to picture data (indices)
	&PalScaleR140 // Pointer to palette
};//


//多边形的外形
static const GUI_POINT _aNeedle[] = {
	{ MAG * ( 0), MAG * (  0 + 125) },
	{ MAG * (-3), MAG * (-15 + 125) },
	{ MAG * (-3), MAG * (-65 + 125) },
	{ MAG * ( 3), MAG * (-65 + 125) },
	{ MAG * ( 3), MAG * (-15 + 125) },
};


//PARAM,包含绘图所需信息的结构体
typedef struct 
{
	GUI_AUTODEV_INFO AutoDevInfo;  // 有关必须显示的内容的信息
	GUI_POINT        aPoints[7];   // Polygon data
	float            Angle;//旋转角度
} PARAM;


//获取角度,这里只是模拟。在实际使用中这个角度应该是一个实际值
static float _GetAngle(int tDiff) {
	if (tDiff < 15000) {
		return  225 - 0.006 * tDiff ;
	}
	tDiff -= 15000;
	if (tDiff < 7500) {
		return  225 - 90 + 0.012 * tDiff ;
	}
	return 225;
}


//绘图
static void _Draw(void * p)
{
	PARAM * pParam;
	pParam = (PARAM *)p;
	//显示背景
	if (pParam->AutoDevInfo.DrawFixed) {
		GUI_ClearRect (60, 80 + bmScaleR140.YSize, 60 + bmScaleR140.XSize - 1, 180);//清空对应区域,不会全部清除,
		GUI_DrawBitmap(&bmScaleR140, 60, 80);//绘制位图
	}

	//移动指针
	GUI_SetColor(GUI_WHITE);
	GUI_AA_FillPolygon(pParam->aPoints, countof(_aNeedle), MAG * 160, MAG * 220);  //绘制实心无锯齿多边形   初始点//初始点就是旋转点

	//显示前景色
	if (pParam->AutoDevInfo.DrawFixed) {
		GUI_SetTextMode(GUI_TM_TRANS);
		GUI_SetColor(GUI_RED);
		GUI_SetFont(&GUI_Font24B_ASCII);
		GUI_DispStringHCenterAt("RPM / 1000", 160, 140);
	}
}

void _DemoScale(void)//给系统调用
{
	GUI_AUTODEV AutoDev;    // Object for banding memory device  声明定义自动设备变量
	PARAM       Param;      // Parameters for drawing routine
	int         Cnt;
	int         tDiff;
	int         t0;

	//显示信息
	GUI_SetBkColor(GUI_BLACK);
	GUI_Clear();
	GUI_SetColor(GUI_WHITE);
	GUI_SetFont(&GUI_Font24_ASCII);
	GUI_DispStringHCenterAt("MEMDEV_AutoDev - Sample", 160, 5);
	GUI_SetFont(&GUI_Font8x16);
	GUI_DispStringHCenterAt("Scale using GUI_AUTODEV-object", 160, 50);

	//使能高分辨率抗锯齿
	GUI_AA_EnableHiRes();//启动高分辨率坐标
	GUI_AA_SetFactor(MAG);//设置抗锯齿质量因子
	while (1) 
	{
		t0 = GUI_GetTime();	//返回系统时钟节拍
		GUI_MEMDEV_CreateAuto(&AutoDev); //创建自动设备对象
//这个循环就是为了模拟显示一会,其实实际上可以丢到一个任务里面去,
		for (Cnt = 0; (tDiff = GUI_GetTime() - t0) < 24000; Cnt++) 
		{
			Param.Angle = _GetAngle(tDiff)* DEG2RAD;//获取角度//根据实际要展示的量转化成旋转角度
			GUI_RotatePolygon(Param.aPoints, _aNeedle, countof(_aNeedle), Param.Angle); //按照指定角度旋转多边形
            //printf("函数调用之前:%d\r\n",Param.AutoDevInfo.DrawFixed);
			GUI_MEMDEV_DrawAuto(&AutoDev, &Param.AutoDevInfo, &_Draw, &Param);  //使用自动设备对象绘制图形
            //printf("函数调用之后:%d\r\n",Param.AutoDevInfo.DrawFixed);
		}

		//显示milliseconds / picture图片
		GUI_SetColor(GUI_WHITE);
		GUI_SetFont(&GUI_Font8x16);
		GUI_DispStringHCenterAt("Milliseconds / picture:", 160, 200);
		GUI_SetTextAlign(GUI_TA_CENTER);
		GUI_SetTextMode(GUI_TM_NORMAL);
		GUI_DispNextLine();
		GUI_GotoX(160);
		GUI_DispFloatMin((float)tDiff / (float)Cnt, 2);

		//删除自动设备对象
		GUI_MEMDEV_DeleteAuto(&AutoDev);
		GUI_Delay(3000);
		GUI_ClearRect(0, 70, 319, 239);
	}
}

代码分析:
1、首先创建自动设备对象 GUI_MEMDEV_CreateAuto(&AutoDev); //创建自动设备对象
2、调用自动设备对象绘制图片GUI_MEMDEV_DrawAuto(&AutoDev,&Param.AutoDevInfo, &_Draw, &Param); //使用自动设备对象绘制图形
3、绘图回调函数里面
第一次会绘制所有要显示的,后面在进入这个函数,只会对比,修改改变的对象使用的空间
4.绘图完毕,就是不需要在使用了,就删除自动设别对象
GUI_MEMDEV_DeleteAuto(&AutoDev);

代码块中有本人的一些注释,仅供参考,如果有错,希望留言指出,谢谢诶,

基于F429使用EMWIN存储设备的学习暂时到这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值