uC/GUI 可以在无操作系统的环境下单独运行。

修改…/GUI/Include/GUIConf.h:

  1. #ifndef GUICONF_H  
  2. #define GUICONF_H  
  3. /* 无操作系统的支持 */  
  4. #define GUI_OS (0)  
  5. /* 不支持触摸屏 */  
  6. #define GUI_SUPPORT_TOUCH (0)  
  7. /* Support mixed ASCII/UNICODE strings */  
  8. #define GUI_SUPPORT_UNICODE (1)  
  9. /* 默认字体 */  
  10. #define GUI_DEFAULT_FONT &GUI_Font6x8  
  11. /* Size of dynamic memory ... For WM and memory devices*/  
  12. #define GUI_ALLOC_SIZE (1024*5)  
  13. /********************************************************************* 
  14. * 
  15. * Configuration of available packages 
  16. */  
  17. /* 支持视窗管理器 */  
  18. #define GUI_WINSUPPORT 1  
  19. /* 支持存储设备 */  
  20. #define GUI_SUPPORT_MEMDEV 1  
  21. /* Anti aliasing available */  
  22. #define GUI_SUPPORT_AA 1   

修改 …/GUI/Include/LCDConf.h :

  1. /* 配置 LCD 尺寸 */  
  2. #define LCD_XSIZE (240)  
  3. #define LCD_YSIZE (320)  
  4. /* LCD 的色深为16位 */  
  5. #define LCD_BITSPERPIXEL (16)  
  6. /* uC/GUI 自带了一些 LCD 控制器的驱动程序。如果采用的驱动程序是其自带的, 
  7. * 可以把这个宏定义为控制器的型号。这里配置为-1,表示不使用自带的驱动, 
  8. * 而使用 LCDDummy.c 中我们自定义的驱动程序 
  9. */  
  10. #define LCD_CONTROLLER -1  
  11. #define LCD_SWAP_XY (1)  
  12. /* 交换R(红色)B(蓝色)两种颜色,在下文会详细介绍 */  
  13. #define LCD_SWAP_RB (1)   

在 …/System/systemInit.c 中,我添加了用于防止 JTAG 失效和时钟初始化的函数,并在 main 函数中调用。使用 PLL,将时钟频率设为 50MHz:

  1. void  
  2. clockInit (void)  
  3. {  
  4.   SysCtlLDOSet (SYSCTL_LDO_2_75V);  /* 设置LDO输出电压 */  
  5.   SysCtlClockSet (CCLK_DIV |    /* 系统时钟设置 */  
  6.           SYSCTL_USE_PLL |  /* USE PLL */  
  7.           SYSCTL_OSC_MAIN | EXT_CLK);   /* System clock = 50MHz */  
  8.   TheSysClock = SysCtlClockGet ();  /* 获取当前的系统时钟频率 */  
  9. }  

编写驱动是移植的重点。由于所使用的 LCD 控制芯片未知,资料无从查找。但是我们已知周立功公司提供的 LCD 例程可以在这块 LCD 上正常运行。于是,我们可以参照周立功公司的例程来编写 GUI 驱动。

在 …/GUI/LCDDriver/LCDDummy.c 头部,包含周立功提供的头文件 LTM024D130.h,并利用 LTM024D130.c 中的函数,完成 LCD 的初始化和开启、关闭。

  1. #ifndef LCD_INIT_CONTROLLER  
  2. #define LCD_INIT_CONTROLLER() tftLcdInit()  
  3. #endif  
  4. ...  
  5. void  
  6. LCD_On (void)  
  7. {  
  8.   backlightOn ();  
  9. }  
  10.   
  11. void  
  12. LCD_Off (void)  
  13. {  
  14.   backlightOff ();  
  15. }  

从画线、矩形块填充以至位图填充等一系列的函数,都是靠调用画点函数来完成的,因此只要编写函数 LCD_L0_SetPixelIndex 和 LCD_L0_GetPixelIndex,其他绘图功能也就相应实现。在 LCD 上显示一个像素,需要知道其 RGB 值,但函数 LCD_L0_SetPixelIndex 中,传递进来的却是一个名为 PixelIndex 的值,这两者关系如何?

uC/GUI 的 API 函数,如 GUI_SetColor,其参数是一个24位的 BGR 值,如红色用 0×0000FF 表示,而 0xFF0000 表示蓝色。但 GUI 支持从2位到16位的各种显示器,为了将24位的值正确地转换并显示到 LCD 上,GUI 会调用 …/GUI/ConvertColor 目录下相应函数,将24位的 color 转换为与 LCD_BITSPERPIXEL 相应的 PixelIndex。也就是说,只要配置正确,PixelIndex 就是16位的 RGB 或 BGR 值。至于到底是 RGB 还是 BGR,取决于 LCD_SWAP_RB 的值:LCD_SWAP_RB 为0,则 PixelIndex 是 BGR 值。

根据以上结论,直接调用 LTM024D130.c 中的画点函数:

  1. /********************************************* 
  2. * 
  3. * LCD_L0_SetPixelIndex 
  4. * 
  5. ********************************************** 
  6. Purpose: 
  7. Sets the index of the given pixel. The upper layers of emWin 
  8. calling this routine make sure that the coordinates are in range, so 
  9. that no check on the parameters needs to be performed. 
  10. */  
  11. void  
  12. LCD_L0_SetPixelIndex (int x, int y, int PixelIndex)  
  13. {  
  14. /* Convert logical into physical coordinates (Dep. on LCDConf.h) */  
  15. #if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y  
  16.   int xPhys = LOG2PHYS_X (x, y);  
  17.   int yPhys = LOG2PHYS_Y (x, y);  
  18. #else  
  19. #define xPhys x  
  20. #define yPhys y  
  21. #endif  
  22. /* Write into hardware ... Adapt to your system */  
  23.   {  
  24.     pixelDraw (x, y, PixelIndex);  
  25.   }  
  26. }  
  27.   
  28. /********************************************* 
  29. * 
  30. * LCD_L0_GetPixelIndex 
  31. * 
  32. ********************************************** 
  33. Purpose: 
  34. Returns the index of the given pixel. The upper layers of emWin 
  35. calling this routine make sure that the coordinates are in range, so 
  36. that no check on the parameters needs to be performed. 
  37. */  
  38. unsigned int  
  39. LCD_L0_GetPixelIndex (int x, int y)  
  40. {  
  41.   LCD_PIXELINDEX PixelIndex;  
  42. /* Convert logical into physical coordinates (Dep. on LCDConf.h) */  
  43. #if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y  
  44.   int xPhys = LOG2PHYS_X (x, y);  
  45.   int yPhys = LOG2PHYS_Y (x, y);  
  46. #else  
  47. #define xPhys x  
  48. #define yPhys y  
  49. #endif  
  50. /* Read from hardware ... Adapt to your system */  
  51.   {  
  52.     PixelIndex = pixelRead (x, y);  
  53.   }  
  54.   return PixelIndex;  
  55. }  

以上可以说基本完成了驱动的编写,但运行时发现刷屏速度较慢。对于大多数 LCD 控制器,画水平线和竖直线的函数执行速度非常快,因为可以立即放置多个像素,而不需要计算。LCD_L0_DrawHLine 和 LCD_L0_DrawVLine 函数调用画点函数来画线,显然没有体现出这种优势,拖慢了速度。函数 LCD_L0_DrawHLine 修改如下:

  1. void  
  2. LCD_L0_DrawHLine (int x0, int y, int x1)  
  3. {  
  4.   if (GUI_Context.DrawMode & amp; LCD_DRAWMODE_XOR)  
  5.     {  
  6.       for (; x0 & lt; = x1; x0++)  
  7.     {  
  8.       LCD_L0_XorPixel (x0, y);  
  9.     }  
  10.     }  
  11.   else  
  12.     {  
  13.       if (x1 & gt; 239)  
  14.     {  
  15.       x1 = 239;  
  16.     }  
  17.       if (x0 & gt; 239)  
  18.     {  
  19.       x0 = 239;  
  20.     }  
  21. /* 设置增长方向为:左 --> 右,上 --> 下 */  
  22.       __writeCommand (0, 0x00, 0x04);  
  23.       __writeCommand (0, 0x01, 0x07);  
  24. /* 设置起始坐标 */  
  25.       setCoordinate (x0, y);  
  26.       while (x0++ & lt; = x1)  
  27.     __writeData16 (LCD_COLORINDEX);  
  28.     }  
  29. }  

第一个 if 分句中,之所以沿用原来的代码,是因为实践中发现,如果按照 else 分句中的形式修改,GUI 在 GUI_DRAWMODE_XOR 模式下工作不正常。

一些时间相关的函数,如 GUI_Delay,需要用到时钟。使用系统时钟节拍 SysTick,每1ms发出一个中断,同时将 GUI 的时间变量 OS_TimeMS++,就实现了时钟功能。SysTick 的中断服务函数如下:

  1. void  
  2. SysTick_ISR (void)  
  3. {  
  4.   OS_TimeMS++;  
  5.   if (OS_TimeMS & gt; 24 * 60 * 60 * 1000)  /* 一天后清零,防止溢出 */  
  6.     OS_TimeMS = 0;  
  7. }  

中断服务函数需要在 startup_ewarm.c 中注册。

以周立功公司提供的 uC/OS 移植模板为基础,将 GUI 的源代码添加进去。底层驱动 LCDDummy.c 无需再修改,可以直接使用。

在 …/GUI/Include/GUIConf.h 中,将 GUI_OS 设为1。其他配置基本可以不变。

由于加入了操作系统,systemInit.c 和 SysTick 部分的代码不再需要。在 target.h 中设定系统时钟:

  1. /* external clock 外部时钟 */  
  2. #define EXT_CLK SYSCTL_XTAL_6MHZ  
  3. /* 1:Enable PLL 使能PLL */  
  4. #define PLL_EN 1  
  5. /* CCLK divider CCLK分频系数 */  
  6. #define CCLK_DIV SYSCTL_SYSDIV_4  

用 GUI_X_uCOS.c 代替 GUI_X.c。这时,GUI_Delay 的参数单位由ms变成系统时钟节拍。

在编译过程中,根据编译器的错误提示,开启 os_cfg.h 中的一些选项。这样,就可以完成 OS 的添加。