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);
}
}
自动设备对象
- 简介
自动设备对象,第一次调用绘制函数的时候,会绘制所有的项目,之后绘制,仅绘制更新移动或更改对象使用的空间,优势是计算时间少,刷新快,因为不会更新整个屏幕***。
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;
- 分析正点原子代码
#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);
代码块中有本人的一些注释,仅供参考,如果有错,希望留言指出,谢谢诶,