UC/GUI在NIOSII上的移植

转自

http://blog.ednchina.com/user_default.aspx?u=penguin7447&page=2

http://www.61eda.com/Article/NIOSII/200804/1532.html

  

这是前些日子在使用uc/GUI的时候即下来的一些东西原来发布在EDACN的bbs上面。现在不知道沉到哪里去了。现在把它重新整理发布在这里。随后在明年过年的时候把后续的几个高级主题整理出来。

下面开始我的笔记!有兴趣的兄弟们可以来看看。

step1.
下载uC/GUI的代码。(废话没有源代码移植个鸟)
我下载的时uC/GUI3.32这是能得到的源代码中最全的一个版本。
看看里面都有些什么东西。由于这里的发间大小的限制的问题不能上传源代码。很是郁闷。有需要的同志可以联系我。Email:william7447@gmail.com

clip_image001
首先看看所有名叫Simulation的东西这是uC/GUI在VC中仿真的VC工程,他的仿真功能非常的实用可以在没有具体硬件的情况下先行开发软件,而丝毫不影响软件的兼容性。但是有一个问题比较郁闷,就是速度的问题。大家知道嵌入式系统的CPU运算能力有限,而电脑的cpu.........我的整个项目的gui是在电脑上完成的。拿到目标系统上面编译.......通过。
经过紧张的下载.....................
运行..........显示出了第一个画面,无比的兴奋。但测试发现极其郁闷而几乎无法解决的问题......目标系统的处理能力只有100mips而我的电脑的cpu是P4 3.0。速度的差别太大了。解决这个问题几乎成了我后半段工作的主题。
GUI文件夹存放全部uC/GUI源代码的地方

clip_image001[4]
看看它的属性有多达390个文件,全部是.c和.h。可以看出GUI系统是一个庞大复杂的东西。我在调试系统的时候跟踪过完整的消息循环再进入了60多个子函数调用后还没有看到希望,就彻底的放弃了跟踪的想法。下来会具体说明这里面都有些什么东西。

config文件夹uC/GUI的配置文件夹。里面存放的是uC/GUI的配置头文件。改动里面的相应的就可以改动uC/GUI的配置。

 

这个GUI功能十分强大。我也在探索之中。
这几天刚刚入门,只能说我自己的移植过程,以后陆续添上它的使用。有什么不对的地方大家请指出来。

uC/GUI移植之准备工作。

先来看看吧uC/GUI移植到NIOS II都要准备些什么东西。
首先就是要了解uC/GUI的源代码包括了一些什么东西。
前面提到了这个gui有两个文件夹一个GUI存放gui的核心文件,一个config为gui提供配置信息。
先看core里面有什么东西。
clip_image001[6]
GUIAntiAlias 抗锯齿支持,看上去挺牛的。
根据对抗锯齿的使用发现,uC/GUI的抗锯齿的效果好坏主要取决于系统的发色数,即系统的色彩表现能力,例如系统仅有灰度显示能力的时候,uC/GUI在对一条直线进行处理的时候它是在直线的两侧添加颜色较浅的点来实现抗锯齿的。效果十分明显。
GUIConvertMono (b/w)和灰度显示的色彩转换支持。
GUIConvertColor 彩色显示的色彩转换支持
实际上就是色彩空间变换,为什么需要色彩转换呢?
在gui内部定义了一套调色板及色彩的数据格式,但是有的控制器的色彩数据格式和gui内部定义的并不一样,甚至色彩的数量(即lcd的发色数)也不同,这样就需要将两种不同的数据格式进行转换。这样才能在lcd上看到正常的颜色。
GUICore µC/GUI 核心文件,提供了GUI基本的功能,比如画点,画线,为图之类的东西。什么窗口,窗口控件都是基于这些基本功能的。
GUIFont 不用多说了
GUILCDDriver LCD控制器。下面会说这个东西。
GUIMemDev Memory device 支持。这个东西可用在很多情况下,但最主要的功能是防止在项目重叠时,防止屏幕的闪烁。如果没有Memory device 的支持数据会直接写到控制器中去,这样当进行各种屏幕跟新的时候就会出现闪烁现象。如果有Memory device 支持,就会避免这种现象。具体的还没有测试,不过看说明是蛮牛的。关于这个东西会有一个较详细的测试。
GUITouch Touch-panel 支持。虽然说是支持,甚至连鼠标都支持,但是底层驱动程序的四个函数是空的需要用户自己添加内容,我们使用mxb7843这个四线电阻触摸屏控制器。班子还没有做好,做好就测试。
GUIWidget 窗体控件库,功能强大,提供诸如按钮,文本框之类的复杂的功能。
GUIWM 窗口库。
widget wm配合memory device使用功能强大。

下面看看CONFIG文件夹
三个文件:
GUIConf.h
GUITouchConf.h
LCDConf.h
看名字也知道干什么的了。
下面一个一个说。

#ifndef GUICONF_H
#define GUICONF_H

#define GUI_OS                    (1)  /* 多任务支持,如果使用rtos就打开这个选项,除了自家的ucos,别的rtos也支持*/
#define GUI_SUPPORT_TOUCH         (1)  /* 支持触摸屏*/
#define GUI_SUPPORT_UNICODE       (1)  /*unicode字符串支持,能显示中文的哦,只要能把字库放进来,现在的问题我把字库放不进来,文件太大了,编译器限制,郁闷!*/

#define GUI_DEFAULT_FONT          &GUI_Font6x8/*默认字体*/
#define GUI_ALLOC_SIZE            12500  /* WM 和 memory devices分配的动态内存*/

/*********************************************************************
*
*         Configuration of available packages
*/

#define GUI_WINSUPPORT            1  /* Window manager package available */
#define GUI_SUPPORT_MEMDEV        1  /* Memory devices available */
#define GUI_SUPPORT_AA            1  /* Anti aliasing available */
这三个不用说了吧!
#endif  /* Avoid multiple inclusion */
GUITouchConf.h这个文件........由于硬件不到位没有深入研究触摸这块还不太理解,日后补上。
LCDConf.h这个文件比较特别,随着控制器的不同,内容而不同。
如果针对的是硬件控制器,就会在这个文件里面定义控制器的基地址,所有的寄存器,显示内存的地址镜像关系,等等一系列硬件控制器的特征信息。当然了还会定义lcd的尺寸,调色板,等一些重要的信息。还有救治针对不同的lcd的设置,配置不同的控制器初始化代码。
还有一种就是MEM控制器。就是没有硬件控制器在内存里面申请一个和LCD物理象素点一一对应的内存区域作为显示缓冲区,然后由用户想办法把数据送到LCD上去。他给的例子里面是用定时中断来模拟LCD控制的控制时序,将数据流送到LCD上。在该模式下如果是一个很小lcd该方法很好节省了硬件成本。但是大量占用CPU刷新率低。如果lcd象素很高,那就是个问题了。但是在某些应用中不得不使用这种方式。在我的工程里面就使用了这种方式。
我的屏640*480*3bit。
这里有关硬件的控制器是一个大问题,即底层的驱动程序怎么办?uC/GUI提供了很多的芯片的驱动程序,但是如果选用的芯片没有怎么办?或者屏的参数比较奇怪怎么办?比如我用的屏640*480*3bit,就是8色的那种,一般的屏都是16色。我打算在过年的时候开一个有关驱动程序的专题,讨论这些问题。还有驱动程序的效率对整个gui的效率影响很大。
准备就这么多该说说移植了。

该移植了!
首先弄个NIOS II系统。
然后打开NIOS II IDE创建一个工程。
什么都可以!我使用的Hello World这个工程。使用例子的好处省心。
然后找到这个工程的在硬盘中的物理位置,将下载的代码中的两个文件夹GUIconfig拷贝进去该软件工程的目录里面。

由于前一段的工作是基于Altera Fpga 的用的就是NIOS II处理器,后面我会专门针对arm来讨论相关的问题,最近的项目是基于arm9的。
clip_image002[12]
图中就是copy好的目录。
然后回到NIOS II IDE refresh工程就能看到ide自动将这两个文件加添加进了工程,还有里面所有的文件。
但是不是所有的文件都是有用的,nios II的编译器会把所有的文件编译,这样在链接的时候就出问题了,因为有的文件是针对不同的配置写的。但是所有的都被编译了,这样子就导致大量的链接错误,无数重复定义。这就需要将无用的文件从工程中清除。一个地方就是LCDDrivers由于底层的绘图函数是在drivers里面定义的所以有多少个drivers就会有多少个同样名称的函数。这里就需要将无用的driver清除。还有一个地方就是gui/core的GUI_DrawBMP.c和GUI_DrawBitmap.c着两个文件内容一模一样,一字不差!所以要清除一个!还有一个重要问题是文件的包含路径。nios ide不是自动添加文件包含路径的,用惯了ads的人特不习惯。而且在5.1包含路径设置位置比较难找!在这里添加四个路径:
E:FPGALcdsoftwarehello_world_0Config
E:FPGALcdsoftwarehello_world_0guiCore
E:FPGALcdsoftwarehello_world_0guiWM
E:FPGALcdsoftwarehello_world_0guiWidget


clip_image002[14]
还有就是要在系统库中加上ucos。uC/GUIi默认打开多任务支持。
包含好了路径就可以编译了。
但是提示还有链接错误!

 

非常郁闷,怎么看也看不出来怎么回事。提示一个字体未定义!
关键还是默认字体!
经过仔细察看发现一个问题!!!!大家看看图就明白了!
NIOS II IDE使用java开发的,java大小写敏感!这点还是Windows作的好。
clip_image001[8]
还有一个问题就是优化级别的问题,我发现在NIOS II系统里面most级别的优化和none的优化(就是不优化)执行速度能差2~3倍。特别是一些计算密集型的代码例如:crc和gui应用。
这回编译就没有错误了!GUI初步移植成功,下来测试一下!由于没有硬件支持只能看看软件的。调试工程用内存查看器,就看到了uC/GUI的运行的结果。
执行下面的语句:
int main()  {
    LCD_Part = 0;
    alt_irq_register (  LCM_0_IRQ,
                        (void*)0,
                        LCD_isr);
    alt_irq_enable(LCM_0_IRQ);
    GUI_Init();
    GUI_DispChar('A'); /*显示一个A*/
    printf("Hello from Nios II! ");
    while(1)    {
    }
  return 0;
}
我用的是MEMC驱动程序,即把GUI执行的结果保存到内存中。这样子才有了直接察看内存来看结果BT方法。
可以在内存查看器中看到数据的变化(由于数据量巨大,只列出头几列的数据)
1f f0 00 ...
e0 0e 00 ...
e0 0e 00 ..
ff fe 00 ...
e0 0e 00 ..
e0 0e 00 ..
e0 0e 00 ..
00 00 00 ...
转化为二进制
000111111111000000
111000000000111000
111000000000111000
111111111111111000
111000000000111000
111000000000111000
111000000000111000
000000000000000000
我的屏是RGB三色屏共有8种颜色,0表示该点灭,1表示亮。3位表示一个彩色的象素点。能看出来由1组成了一个A吗?
GUI初步抑制成功,下面将探索它的各种功能。(这部分着在摸索,每天弄一点,跟新可能会很慢!)
使用MEMC是因为这种方式的移植最简单根本不牵扯硬件,而且因为项目经费紧张,不可能买一个独立的控制器,特别是体现不出来FPGA的优势。这里的控制器是一个自己写的小东西,实现的对LCD的控制,这部分正在测试,测试好了也会拿出来给大家共享的。
下来的几天主要测试uC/GUI的复杂应用。包括widget, wm这些东西。

 

---------------------------------------------------------------------

uC/GUI Simulation的应用
uC/GUI提供了一格功能是强大的工具,即Simulation工具他可以在windows环境下模拟uC/GUI的运行结果,为GUI应用程序的开发体供了极大的方便,在模拟器上开发GUI应用程序代码可以几乎无修改的直接应用于目标硬件。
这个模拟器的原理是GUI程序运行后产生一个实时更新的BMP图片然后由gui模拟程序显示出来。这个功能作得太好了,这样子gui程序的开发简直是无敌了。
在下载的uC/GUI源代码中,解压后就能看到一个名叫Simulation的VC6Workspace和project。
在顶楼的图中可以清楚地看到这两个文件。这是uC/GUI的开发人员帮我们做好的。直接打开这个工程就可以在VC6中开发GUI应用程序,uC/GUI高度抽象,应用程序与底层很好的分离,这样为GUI应用程序的开发提供了极大的方便。
下面打开这工程看看里面有什么东西。我使用的VS.Net。没有什么区别,个人认为VS.Net的功能较VC6强大许多。是一个优秀的集成开发环境。
打开工程后我们看看里面都有些什么东西。

 

clip_image001[10]
config和gui文件加我们前面都说过了,里面放的就是Gui的配置文件和gui的源代码。
这里面多了几个文件夹。
Application文件夹,用户存放应用程序文件的地方。
Simulation文件夹模拟器提供初始化和一些配置信息,我们根本不用改动这些东西。
System文件夹,大家知道每个C程序都有一个main函数,这里面就放了这一个东西。
还有一个地方,就是LCD_Driver这个文件夹里面放的是LCDWIN.c这样无论你怎么修改GUI的配置,模拟器都会使用这个驱动程序来实现GUI程序运行结果的正确的显示。

 

LCDWin.c就是基于windows模拟器的驱动程序,就是通过这个驱动生成模拟器里显示的bmp图片。
弄清楚这些东西,就可以开始uC/GUI编程了。
打开MainTask.c这个文件我们就在这里面编写我们的GUI应用程序。
#include "GUI.h"
extern const GUI_BITMAP bmMicriumLogo;
extern const GUI_BITMAP bmMicriumLogo_1bpp;

下面是自带的一段示例代码。
我们来看看她都干了些什么东西。
/*
  *******************************************************************
  *
  *              main()
  *
  *******************************************************************
*/
void MainTask(void) {
  int Cnt =0;
  int i,YPos;
  int LCDXSize = LCD_GET_XSIZE();
  int LCDYSize = LCD_GET_YSIZE();  /*取得lcd物理尺寸,这个参数是在lcdconf.h里面定义的*/
  const GUI_BITMAP *pBitmap;        /*一个指向预显示的位图的指针,在这里位图是在.c文件里面存储的ps:.c的体积大的吹牛*/
  GUI_Init();                                     /*初始化GUI,这谁痘看得出来*/
/*这里面除了初始了在guiconf.h里面定义的时用的GUI的所有功能,包括widget,wm等功能的初始化,当然还有lcd的控制器的初始化*/
  GUI_SetBkColor(GUI_RED); GUI_Clear();      /*设置背景颜色为RED,其结果如图*//*
clip_image001[12]
/*说明一下这个模拟器的窗口,最大的那个窗口显示的就是GUI程序的运行结果。标题里显示的是当前LCD的配置参数,colors显示的当前gui系统能显示的所有的颜色,即调色板。log是gui的日志,这个功能会在后面说明*/
  GUI_Delay(1000);   /*延迟1000个时钟节拍,这里我们的gui是应用在ucos rtos上面,这里的时钟节拍就是ucos的时钟节拍*/
  GUI_SetBkColor(GUI_BLUE);  /*背景设为BLUE*/
  GUI_Clear();  /*清除当前的window,没有窗口就清理整个屏幕*/
  GUI_Delay(1000);
  GUI_SetColor(GUI_WHITE);
  for (i="0"; i<1000; i+=10) {
    GUI_DrawHLine(i,0,100);
    GUI_DispStringAt("Line ",0,i);
    GUI_DispDecMin(i);
  } /*这段代码的功能就是每隔10行显示文字line和一条直线。*/
clip_image002[16]
  GUI_Delay(1000);
  GUI_SetColor(0x0);  //设置显示颜色为黑色!?黑色对着呢!1时点亮0是熄灭你看看是不黑色。
  GUI_SetBkColor(0xffffff);
  for (i="0"; i<160; i++) {
    int len = (i<80) ? i : 160-i;
    GUI_DrawHLine(i,20,len+20);
  } //显示一个三角形
clip_image003[4]
GUI_Clear();
  if (LCD_GET_YSIZE()>(100+bmMicriumLogo_1bpp.YSize)) {
    pBitmap=&bmMicriumLogo; //设置要显示的位图为MicriumLogo
  } else {
    GUI_SetColor(GUI_BLUE);
    pBitmap=&bmMicriumLogo_1bpp;
  }
  GUI_DrawBitmap(pBitmap,(LCDXSize-pBitmap->XSize)/2,10);
  YPos="20"+pBitmap->YSize; //显示位图MicriumLogo
  GUI_SetFont(&GUI_FontComic24B_1);
  GUI_DispStringHCenterAt("www.micrium.com",LCDXSize/2,YPos); //在指定位置以FontComic24B_1字体显示文字www.micrium.com
  GUI_Delay(1000);
  GUI_SetColor(GUI_RED);
  GUI_DispStringHCenterAt("?2002 ", LCDXSize/2,YPos+30);
  GUI_SetFont(&GUI_Font10S_1);
  GUI_DispStringHCenterAt("Micri祄 Inc.",LCDXSize/2,YPos+60);;  //在指定位置以Font10S_1字体显示文字Micrium Inc
  GUI_Delay(1000);
}
截图
clip_image004[4]
一个完整的gui应用程序的例子就出来了。接下来将是gui应用程序的开发。
从最简单的文字到window到复杂的控件。
一步一步来,我也在学习。
在硬件控制器彻底搞定之前都将使用这个东西开发应用程序。

 

------------------------------------------------------------

uC/GUI NIOS II移植之Text显示

今天研究了uC/GUI的文字显示系统。
这个系统的功能相当强大,提供了一下几个函数。
GUI_DispChar() 显示一个字符
GUI_DispCharAt() 在某个位置显示一个字符
GUI_DispChars() 显示n个设定的字符
GUI_DispString() 显示一个字符串
GUI_DispStringAt() 在某个位置显示一个字符串

还有好大一堆函数,不过这几个是最基本的。
先看一段有关这些代码的事例程序:
void MainTask(void) {
    unsigned int i;
    GUI_Init();
初始化,设置的默认字体是6*8的一种字体,具体叫什么忘了
    GUI_SetColor(GUI_YELLOW);    设置显示颜色为YELLOW,这里指的是字符的颜色
    GUI_DispChars('*', 108);           从当前坐标起显示108个*,就是截图里面的最上面的那排*
    for(i = 0; i < 480; i+=8)   {
        GUI_DispCharAt('*', 1, i);
    }                                                   在第一列显示一列*
    GUI_DispChars('*', 108);            在最下面一行显示一排*
    for(i = 0; i <= 480; i+=8)   {
        GUI_DispCharAt('*', 634, i);   
    }                                                   在最右边的一列显示一列*

    GUI_SetColor(GUI_GREEN);          设置显示的颜色为GREEN
    GUI_SetFont(&GUI_Font8x10_ASCII);  设置字体为GUI_Font8*10_ASCII
    GUI_DispCharAt('A', 100, 100);             在坐标100,100处显示一个A
    GUI_DispString("! Hello World!   ");        显示Hello World!大家注意这是紧跟着A显示出来的,即它是在当前光标处显示字符的
    GUI_SetFont(&GUI_Font32_ASCII);     设置字体
    GUI_SetColor(GUI_YELLOW);                  设置显示颜色为YELLOW,下面代码显示的字符都是黄色的
    GUI_DispChars('*', 15);                        显示15个*
    GUI_SetBkColor(GUI_BLUE);               设置背景颜色为BLUE,大家注意这个背景颜色,是衬在字下面的,而不是整个的背景
    GUI_DispCharAt('B', 600, 400);        
    GUI_SetFont(&GUI_Font32B_ASCII);
    GUI_SetColor(GUI_RED);
    GUI_DispStringAt("Hello World!", 1, 200); 
在1,100这个地方显示字符串,注意覆盖掉了原先显示出来的*
    GUI_Delay(1000);
}
效果图
clip_image001[14]
这样基本的字符显示函数就完了。大家都会使用了。
在前提到这个GUI支持UNICODE。
既然支持UNICODE那就应该能显示中文才对啊!
当然能显示中文,但关键问题是字体!
这里就讲一讲有关字体的提取。
首先要用到一个字体转换工具,因为我们得到的uC/GUI代码基本上都是D版的,里面所附的字体转换工具都是DOME版,根本转换不出来正常的字体.c文件。在这里要用到另外一个程序。
声明:该程序转载自www.ucgui.com,所有权归原作者ucgui所有,这里只是转载。仅上船该程序的可执行文件
http://www.ednchina.com/Upload/Blog/cecb4a69-b388-4a9f-916d-2b216f8edcc9.rar
声明:在这里特便感谢原作者做出的贡献!
首先运行程序,看到如图的程序界面,相当的简单。
clip_image002[18]
然后点击选择字体。按扭出现新的对话框,我选择的字体如图所示。
clip_image003[6]
确定后回到主界面,点击clip_image004[6]
看到这个对话框文件就转换好了!
clip_image005[4]
直接加载进模拟器工程就可以享受中文字体带来喜悦了!
在这里上传两个转换好的字体宋体(5号字)和Times new roman(5号字)两个字体,供大家参考,其中Times字体去掉了除ascii码之外所有的其他字模。
http://www.ednchina.com/Upload/Blog/622a4994-39aa-4380-a8cc-4cef5e57b7df.rar
说一下这里的5号字对应的就是16*16的汉字字体。
宋体那个文件体积巨大3Mb多,如果是大字体的话就有十几MB了!
我们现在运行下面的程序,体验一下中文的喜悦!
#include "GUI.h"
extern GUI_FLASH const GUI_FONT GUI_FontHZ_FangSong_GB2312_14;
extern GUI_FLASH const GUI_FONT GUI_FontHZ_Times_New_Roman_14;
extern GUI_FLASH const GUI_FONT GUI_Font8x10_ASCII;
extern GUI_FLASH const GUI_FONT GUI_Font32_ASCII;
extern GUI_FLASH const GUI_FONT GUI_Font32B_ASCII; /*这几行一定要有,声明从外部引用这个数据结构,建议大家将所有的字体的定义弄成一个头文件,这样子比较方便!*/
void MainTask(void) {
    unsigned int i;
    GUI_Init();
    GUI_SetColor(GUI_YELLOW);
    GUI_DispChars('*', 108);
    for(i = 0; i < 480; i+=8)   {
        GUI_DispCharAt('*', 1, i);
    }
    GUI_DispChars('*', 108);
    for(i = 0; i <= 480; i+=8)   {
        GUI_DispCharAt('*', 634, i);
    }   
    GUI_SetColor(GUI_GREEN);
    GUI_SetFont(&GUI_FontHZ_Times_New_Roman_14);
    GUI_DispCharAt('A', 100, 100);
    GUI_DispString("! Hello World!   "); /*仔细看这里的字体已经是Times new roman了和上面的是不一样的*/
    GUI_SetFont(&GUI_Font32_ASCII);
    GUI_SetColor(GUI_YELLOW);
    GUI_DispChars('*', 15);
    GUI_SetBkColor(GUI_BLUE);
    GUI_DispCharAt('B', 600, 400);
    GUI_SetFont(&GUI_FontHZ_FangSong_GB2312_14);
    GUI_SetColor(GUI_RED);
    GUI_DispStringAt("大家好这里是中文显示演示程序!", 1, 200); /*将上面程序中的Hello World替换成了中文!*/
    GUI_Delay(10000);
}
clip_image006[4]
还有一个郁闷的问题,文件太大了有的编译器有限制!例如VC.NET的编译器。好在NIOS II编译器没有这个限制。 看看图:
clip_image007
实际测试不影响使用,我们测试了4000多个汉字没有发现什么问题。

 

---------------------------------------------------------------------

uC/GUI NIOS II移植之2D图形库

今天继续昨天的话题。
来看2D图形库。这里面uC/GUI提供了强大的功能。先看看有什么函数。

clip_image002[20]

 

里面有不少东西,这是截的图懒的一个一个把他们敲上来了。

先看第一个函数,GUI_SetDrawMode();设置GUI的绘图模式。靠上去好像很高深。这个函数就有一个参数mode。
mode又两个选项GUI_DRAWMODE_NORMAL和GUI_DRAWMODE_XOR。
先看一个例子大家就明白这个MODE是什么意思了。
void MainTask(void) {
    unsigned int i;
    GUI_Init();
    GUI_SetFont(&GUI_FontHZ_Times_New_Roman_14);
    GUI_SetDrawMode(GUI_DRAWMODE_NORMAL);设置为GUI_DRAWMODE_NORMAL
    GUI_SetBkColor(GUI_YELLOW);
    GUI_Clear();                                                          //这句话比较有意思,执行了之后他会将整个窗口填充为Bk设置的颜色,要不只有在在绘制的图形的下面才有Bk色。
    GUI_SetColor(GUI_RED);
    GUI_FillCircle(300, 200, 130);                              //画第一个园,红色的,显眼一点。
    GUI_SetColor(GUI_GREEN);                                //设置绘图颜色为GREEN
    GUI_FillCircle(140, 200, 130);                             //以NORMAL方式画第二个圆
    GUI_SetDrawMode(GUI_DRAWMODE_XOR);     //设置绘图方式为XOR
    GUI_FillCircle(460, 200, 130);                             //以XOR方式绘制第三个圆,这里大家仔细看看同样绘制了一GREEN颜色的圆,为什么不是GREEN的?XOR惹的祸。这个函数在黑白显示里面尤为重要!
    GUI_SetColor(GUI_BLUE);                                 
    GUI_DispStringAt("First Circle", 300, 340);
    GUI_DispStringAt("Seconde Circle", 140, 340);
    GUI_DispStringAt("Third Circle", 460, 340);        //这些是为了观察方便添上去的
    GUI_SetColor(GUI_BLACK);
    GUI_SetDrawMode(GUI_DRAWMODE_NORMAL);
    GUI_FillCircle(300, 200, 3);
    GUI_FillCircle(140, 200, 3);
    GUI_FillCircle(460, 200, 3);
    GUI_DrawCircle(300, 200, 131);                         //画圆,但是画出来的只有轮廓,上面调用的函数GUI_FillCircle()是将这员填充颜色的。uC/GUI里面所有的在封闭图形比如说圆和长方形的绘图函数Fill和Draw都有类似的关系
    GUI_Delay(5000);
}
效果图
clip_image001[16]
接下来就应该显示位图了及BMP文件。但是大多数的嵌入式系统不支持文件系统那该怎么办?
uC/GUI提供了一个解决方案,把位图转化为.C文件。
这个工具就叫uC-GUI-BitmapConvert.exe
执行这个工具,打开一个我事先准备好的位图文件。
然后如图选择转换该文件。
clip_image002[22]
其实在这里选择把位图转换成多少色的都没有关系,gui会自动适佩目标系统的颜色。
之所以这么选择是为了节省存储空间,毕竟嵌入式系统容量有限。
转换好了以后立即就能看到效果。
clip_image003[8]
在界面的最上方显示的是这个位图的大小这里可看到是419*490。
下面显示的就是调色板,即这个位图所有能显示出来的颜色。
线面就是预览了。难看的不行了。
然后选择另存为,就出现了.c文件这个选项。
clip_image004[8]
这是转换好的位图.c文件和位图原文件。
http://www.ednchina.com/Upload/Blog/abb12d5c-6ee8-4898-b9e0-1a7fc1c424c8.rar
uC/GUI还支持位图文件的压缩。在保存的时候选择就可以了。
clip_image005[6]
比较一下文件可以看到两个文件的大小相差了一倍。
为压缩的600多k,压缩的才300。按照他文档的说明,可以提供2的压缩率。
来看看他们都有什么不同。
这是为压缩的:
#include "stdlib.h"
#include "GUI.H"

/*   Palette
The following are the entries of the palette table.
Every entry is a 32-bit value (of which 24 bits are actually used)
the lower   8 bits represent the Red component,
the middle  8 bits represent the Green component,
the highest 8 bits (of the 24 bits used) represent the Blue component
as follows:   0xBBGGRR
*/

const GUI_COLOR Colors3[] = {
     0x000000,0x0000FF,0x00FF00,0x00FFFF
    ,0xFF0000,0xFF00FF,0xFFFF00,0xFFFFFF
};                                        /*这个位图的调色板可以看出来里面有8种颜色*/

const GUI_LOGPALETTE Pal3 = {
  8,        /* number of entries */
  0,         /* No transparency */
  &Colors3[0]
};                                       

const unsigned char ac3[] = {
0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,   
/*这里面存放的就是bitmap的数据太多了就被我精简了,只显示一行。有兴趣的去下载附件看看。*/
};

const GUI_BITMAP bm3 = {
419, /* XSize */
490, /* YSize */
210, /* BytesPerLine */
4, /* BitsPerPixel */
ac3,  /* Pointer to picture data (indices) */
&Pal3  /* Pointer to palette */
};

下面是压缩的:
#include "stdlib.h"
#include "GUI.H"

/*   Palette
The following are the entries of the palette table.
Every entry is a 32-bit value (of which 24 bits are actually used)
the lower   8 bits represent the Red component,
the middle  8 bits represent the Green component,
the highest 8 bits (of the 24 bits used) represent the Blue component
as follows:   0xBBGGRR
*/
const GUI_COLOR Colors3_compressed_with_palette[] = {
     0x000000,0x0000FF,0x00FF00,0x00FFFF
    ,0xFF0000,0xFF00FF,0xFFFF00,0xFFFFFF
};

const GUI_LOGPALETTE Pal3_compressed_with_palette = {
  8,        /* number of entries */
  0,         /* No transparency */
  &Colors3_compressed_with_palette[0]
};

const unsigned char ac3_compressed_with_palette[] = {
  /* RLE: 418 Pixels @ 000,000*/ 254, 0x07, 164, 0x07,
  /* RLE: 001 Pixels @ 418,000*/ 1, 0x00,
  /* RLE: 418 Pixels @ 000,001*/ 254, 0x07, 164, 0x07,
/*同上砍掉了很多东西,有兴趣的看附件*/};
const GUI_BITMAP bm3_compressed_with_palette = {
419, /* XSize */
490, /* YSize */
210, /* BytesPerLine */
GUI_COMPRESS_RLE4, /* BitsPerPixel */
ac3_compressed_with_palette,  /* Pointer to picture data (indices) */
&Pal3_compressed_with_palette  /* Pointer to palette */
,GUI_DRAW_RLE4
};
看看有什么区别,根据我的理解,压缩就是把有信息的象素点标出来。黑色的就不标记。

不过在显示效果上没有任何区别!但是显示压缩的位图明显能感觉到速度较慢。
这是测试用的代码:
extern const GUI_BITMAP bm3;
extern const GUI_LOGPALETTE Pal3;
extern const unsigned char ac3[];
extern const GUI_BITMAP bm3_compressed_with_palette;
//这是一些要用到的外部变量声明

    GUI_SetDrawMode(GUI_DRAWMODE_NORMAL);
    GUI_SetBkColor(GUI_BLACK);
    GUI_SetColor(GUI_WHITE);
    GUI_Clear(); /*清理桌面,变成黑的*/

    GUI_DrawBitmap(&bm3, 10,10);   /*在左上角为起始点的10,10座标为圆点显示位图*/
    GUI_Delay(5000);
    GUI_Clear();
    GUI_Delay(1000);
    GUI_DrawBitmap(&bm3_compressed_with_palette, 50, 10); /*在左上角为起始点的50,10座标为圆点显示位图,效果上没有区别,但是速度明显的慢*/
    GUI_Delay(5000);
直接添加到上段代码的后面就行了。
clip_image006[6]
超出显示范围的内容就被自动砍掉了。这是第一个显示的截图,第二个由于效果上没却别,就不浪费论坛空间了。

再来看看GUI_DrawBitmapExp();这个函数,这个函数有多达十个参数。
void GUI_DrawBitmapExp(int x0,    int y0,  //显示位图的起始座标(指的是在LCD上的位置)
                       int XSize, int YSize,               //这个两参数的含义是在待显示的位图中选取一个XSize*YSize大小的范围来显示,从0,0座标开始。取值范围1~~255
                       int XMul,  int YMul,                //比例因数,即放大比率!议会就能看到这个参数的效果
                       int BitsPerPixel,                 &n bsp;   //位图的每个象素的位数,可以在bm3这个结构体中找到
                       int BytesPerLine,                  //待显示位图每行的字节数,可以在bm3这个结构体中找到
                       const U8* pData,                  //指向位图,实际存储数据变量的指针。
                       const GUI_LOGPALETTE* pPal);   //指向GUI_LOGPALETTE数据结构的指针    GUI_Clear();
    GUI_Delay(1000);
    GUI_DrawBitmapExp(10, 10, 255, 255, 1, 1, bm3.BitsPerPixel, bm3.BytesPerLine, &ac3, &Pal3); //看看这段代码的含义,特别注意pData的取值是指向ac3的指针
这句的效果
clip_image007[4]
    GUI_Delay(5000);
    GUI_DrawBitmapExp(10, 10, 255, 255, 2, 2, bm3.BitsPerPixel, bm3.BytesPerLine, &ac3, &Pal3);
这句的效果,图片被放大了!
clip_image008[4]
   GUI_Delay(5000);

GUI_Clear();
    GUI_DrawBitmapMag(&bm3 ,10, 10, 2, 2);
    GUI_Delay(5000);
也是放大显示一个图像!效果和上面的是一样的。
没有什么区别。

下来在演示一个polygons的例子。
static const GUI_POINT _aPointArrow[] = {
  {  0,   0},
  {-40, -30},
  {-10, -20},
  {-10, -70},
  { 10, -70},
  { 10, -20},
  { 40, -30},
};                            //定义一个多变性所有的顶点
    GUI_Clear();
    GUI_SetColor(GUI_BLUE);
    GUI_FillPolygon (&_aPointArrow[0], 7, 260, 180);    //填充颜色
    GUI_DrawPolygon(&_aPointStar, 7, 460, 200);    仅有边框
//7表着个要Fill的多变性有几个顶点
GUI_Delay(5000);

效果如图:
clip_image009[4]
今天用到的main函数。

http://www.ednchina.com/Upload/Blog/87886f3f-b745-492d-a944-4df06746c217.rar
今天就到此为止!明天继续!有兴趣的朋友还请关注。

 

--------------------------------------------------------------------------------

uC/GUI NIOS II移植之Window Manager(窗口管理器)

昨天太晚了没有时间更新了。今天继续。
今天来看看Window manager,窗口管理器。
先来看一个小例子。

#define MSG_CHANGE_TEXT WM_USER+0

#ifndef NULL
#define NULL 0
#endif
typedef struct {
  int x;
  int y;
  int xHere, yHere;
  const GUI_BITMAP* pBitmap;
} tDrawContext;
extern GUI_FLASH const GUI_FONT GUI_FontHZ_FangSong_GB2312_14;
extern GUI_FLASH const GUI_FONT GUI_FontHZ_Times_New_Roman_14;
extern GUI_FLASH const GUI_FONT GUI_Font8x10_ASCII;
extern GUI_FLASH const GUI_FONT GUI_Font32_ASCII;
extern GUI_FLASH const GUI_FONT GUI_Font32B_ASCII;
extern const GUI_BITMAP bm3;
extern const GUI_LOGPALETTE Pal3;
extern const unsigned char ac3[];
extern const GUI_BITMAP bm3_compressed_with_palette;
extern const GUI_BITMAP bmmap;                                        /*以上全部是外部变量声明,有位图,有字体*/

static WM_CALLBACK* _cbBkWindowOld;                             /*声明背景窗口的回调函数(Call back function),后面会具体说明这个Call back是干什么的*/
static char _acInfoText[40];                                                 /*要在背景窗口中显示的文字*/

static WM_HWIN _hWindow2;                                                /*窗口2*/

static void        _cbWindow2(WM_MESSAGE* pMsg) {             /*窗口2的call back*/
    int x, y;
    switch (pMsg->MsgId) {                                                      /*pMsg这个参数用来告诉这个回调函数发生了什么事件的!这里列出了系统已经定义好的所有的事件*/
        case WM_CREATE:
            /*to do add code here*/
        break;

        case WM_DELETE:
             /*to do add code here*/
        break;

        case WM_HIDE:
             /*to do add code here*/
        break;

        case WM_MOVE:
             /*to do add code here*/
        break;

        case WM_NOTIFY_PARENT:
             /*to do add code here*/
        break;

        case WM_PAINT:                               /*这个Paint事件,准确地翻译我不知道,但他的功能主要就是自动重绘窗口,这十分重要,有了自动重绘你只要在这个CB里面告诉GUI你想绘什么东西就行了,GUI会自动在适当的时机重绘*/
            GUI_SetBkColor(GUI_RED);
            GUI_Clear();
            GUI_SetColor(GUI_WHITE);
            GUI_SetFont(&GUI_Font24_ASCII);
            x =        WM_GetWindowSizeX(pMsg->hWin);
            y =        WM_GetWindowSizeY(pMsg->hWin);
            GUI_DispStringHCenterAt("Test Window No.2", x / 2, 1); /*在这里面你可以调用上面贴子中所有出现过的内容,但不是在整个屏幕上绘图了,而是在这个窗口中绘图*/
        break;

        case WM_SHOW:
             /*to do add code here*/
        break;

        case WM_SIZE:
             /*to do add code here*/
        break;

        case WM_TOUCH:
             /*to do add code here*/
        break;

        default:
            WM_DefaultProc(pMsg);   /*在回调函数中还有很多其他系统定义的事件,例如WM_SIZE你可以在发生了该事件后改变窗口的内容。有了这个回调函数就可以实现很多的功能*/
    }
}

static void _ChangeInfoText(char* pStr) {      /*将要在背景窗口中显示的文字放到一个全局变量里面去,再由Bk窗口的回调函数自动刷新*/
  WM_MESSAGE Message;
  Message.MsgId  = MSG_CHANGE_TEXT;
  Message.Data.p = pStr;
  WM_SendMessage(WM_HBKWIN, &Message);  /*发送一个消息告诉Bk的cb发生了文字改变的事件*/
  WM_InvalidateWindow(WM_HBKWIN);
}

static void _cbBkWindow(WM_MESSAGE* pMsg) {  /*Bk窗口的CB函数,在这里可以更清楚地看到cb是怎么工作的*/
  switch (pMsg->MsgId) {
  case MSG_CHANGE_TEXT:                     /*发生了MSG change设个事件,将待显示的文本拷贝的变量中去*/
    strcpy(_acInfoText, pMsg->Data.p);  /*这里有点小小的编程技巧,在这里没有使用break,而是直接执行下面的case里面的内容这样就直接刷新的Bk窗口*/
  case WM_PAINT:
    GUI_SetBkColor(GUI_CYAN);
    GUI_Clear();
    GUI_SetColor(GUI_RED);
    GUI_SetFont(&GUI_Font24_ASCII);
    GUI_DispStringHCenterAt("WindowManager - Sample", 160, 5);
    GUI_SetFont(&GUI_FontHZ_FangSong_GB2312_14);
    GUI_DispStringAt(_acInfoText, 5, 40);  /*在这里就可以看到桌面是怎么来的了,这里的图片和lcd的大小不一样,如果一样就是桌面了*/
    GUI_DrawBitmap(&bm3, 50, 60);
    break;                                                      /*这里就看到了Bk窗口里面发生的一切*/
  default:
    WM_DefaultProc(pMsg);
  }
}
/*
  *******************************************************************
  *
  *              main()
  *
  *******************************************************************
*/

void MainTask(void) {
    unsigned int i;
    WM_HWIN hClient;
    GUI_Init();
    _cbBkWindowOld = WM_SetCallback(WM_HBKWIN, _cbBkWindow);
    GUI_Delay(1000);
    _ChangeInfoText("uC/GUI演示程序!");
    _hWindow2 = WM_CreateWindow(330, 130, 300, 300, WM_CF_SHOW | WM_CF_FGND, _cbWindow2, 0);
    GUI_Delay(2000);
}
clip_image001[18]
这段代码就比较复杂了,可以看出来想把GUI用好不是一件容易的事情!

那如果不使用call back机制呢。一样可以实现相同的功能。但是屏幕的刷新可就是你的责任了。
用户就需要调用相关的函数来实现屏幕内容的刷新。
可能有很多人还不理解这个cb机制。我也说不太清。

在前几天的所有例子中都是用户控制刷屏的。就直在调用GUI_Delay()的时候内容才会改变!
单步运行就知道了。

下面看看队窗口的操作
    WM_ResizeWindow(_hWindow2, -100, -100);
    WM_MoveTo(_hWindow2, 50, 100);
执行这两句,窗口就变了样了。
clip_image002[24]
当然了你还可以一次让它移动1个像素,这样看上去就是平滑移动的!
窗口管理还有很多的内容,以后慢慢再贴出来。

posted on 2010-08-22 11:03  齐威王  阅读(1380)  评论(0编辑  收藏  举报

导航