uC/GUI 可以在无操作系统的环境下单独运行。
修改…/GUI/Include/GUIConf.h:
- #ifndef GUICONF_H
- #define GUICONF_H
- /* 无操作系统的支持 */
- #define GUI_OS (0)
- /* 不支持触摸屏 */
- #define GUI_SUPPORT_TOUCH (0)
- /* Support mixed ASCII/UNICODE strings */
- #define GUI_SUPPORT_UNICODE (1)
- /* 默认字体 */
- #define GUI_DEFAULT_FONT &GUI_Font6x8
- /* Size of dynamic memory ... For WM and memory devices*/
- #define GUI_ALLOC_SIZE (1024*5)
- /*********************************************************************
- *
- * Configuration of available packages
- */
- /* 支持视窗管理器 */
- #define GUI_WINSUPPORT 1
- /* 支持存储设备 */
- #define GUI_SUPPORT_MEMDEV 1
- /* Anti aliasing available */
- #define GUI_SUPPORT_AA 1
修改 …/GUI/Include/LCDConf.h :
- /* 配置 LCD 尺寸 */
- #define LCD_XSIZE (240)
- #define LCD_YSIZE (320)
- /* LCD 的色深为16位 */
- #define LCD_BITSPERPIXEL (16)
- /* uC/GUI 自带了一些 LCD 控制器的驱动程序。如果采用的驱动程序是其自带的,
- * 可以把这个宏定义为控制器的型号。这里配置为-1,表示不使用自带的驱动,
- * 而使用 LCDDummy.c 中我们自定义的驱动程序
- */
- #define LCD_CONTROLLER -1
- #define LCD_SWAP_XY (1)
- /* 交换R(红色)B(蓝色)两种颜色,在下文会详细介绍 */
- #define LCD_SWAP_RB (1)
在 …/System/systemInit.c 中,我添加了用于防止 JTAG 失效和时钟初始化的函数,并在 main 函数中调用。使用 PLL,将时钟频率设为 50MHz:
- void
- clockInit (void)
- {
- SysCtlLDOSet (SYSCTL_LDO_2_75V); /* 设置LDO输出电压 */
- SysCtlClockSet (CCLK_DIV | /* 系统时钟设置 */
- SYSCTL_USE_PLL | /* USE PLL */
- SYSCTL_OSC_MAIN | EXT_CLK); /* System clock = 50MHz */
- TheSysClock = SysCtlClockGet (); /* 获取当前的系统时钟频率 */
- }
编写驱动是移植的重点。由于所使用的 LCD 控制芯片未知,资料无从查找。但是我们已知周立功公司提供的 LCD 例程可以在这块 LCD 上正常运行。于是,我们可以参照周立功公司的例程来编写 GUI 驱动。
在 …/GUI/LCDDriver/LCDDummy.c 头部,包含周立功提供的头文件 LTM024D130.h,并利用 LTM024D130.c 中的函数,完成 LCD 的初始化和开启、关闭。
- #ifndef LCD_INIT_CONTROLLER
- #define LCD_INIT_CONTROLLER() tftLcdInit()
- #endif
- ...
- void
- LCD_On (void)
- {
- backlightOn ();
- }
- void
- LCD_Off (void)
- {
- backlightOff ();
- }
从画线、矩形块填充以至位图填充等一系列的函数,都是靠调用画点函数来完成的,因此只要编写函数 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 中的画点函数:
- /*********************************************
- *
- * LCD_L0_SetPixelIndex
- *
- **********************************************
- Purpose:
- Sets the index of the given pixel. The upper layers of emWin
- calling this routine make sure that the coordinates are in range, so
- that no check on the parameters needs to be performed.
- */
- void
- LCD_L0_SetPixelIndex (int x, int y, int PixelIndex)
- {
- /* Convert logical into physical coordinates (Dep. on LCDConf.h) */
- #if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y
- int xPhys = LOG2PHYS_X (x, y);
- int yPhys = LOG2PHYS_Y (x, y);
- #else
- #define xPhys x
- #define yPhys y
- #endif
- /* Write into hardware ... Adapt to your system */
- {
- pixelDraw (x, y, PixelIndex);
- }
- }
- /*********************************************
- *
- * LCD_L0_GetPixelIndex
- *
- **********************************************
- Purpose:
- Returns the index of the given pixel. The upper layers of emWin
- calling this routine make sure that the coordinates are in range, so
- that no check on the parameters needs to be performed.
- */
- unsigned int
- LCD_L0_GetPixelIndex (int x, int y)
- {
- LCD_PIXELINDEX PixelIndex;
- /* Convert logical into physical coordinates (Dep. on LCDConf.h) */
- #if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y
- int xPhys = LOG2PHYS_X (x, y);
- int yPhys = LOG2PHYS_Y (x, y);
- #else
- #define xPhys x
- #define yPhys y
- #endif
- /* Read from hardware ... Adapt to your system */
- {
- PixelIndex = pixelRead (x, y);
- }
- return PixelIndex;
- }
以上可以说基本完成了驱动的编写,但运行时发现刷屏速度较慢。对于大多数 LCD 控制器,画水平线和竖直线的函数执行速度非常快,因为可以立即放置多个像素,而不需要计算。LCD_L0_DrawHLine 和 LCD_L0_DrawVLine 函数调用画点函数来画线,显然没有体现出这种优势,拖慢了速度。函数 LCD_L0_DrawHLine 修改如下:
- void
- LCD_L0_DrawHLine (int x0, int y, int x1)
- {
- if (GUI_Context.DrawMode & amp; LCD_DRAWMODE_XOR)
- {
- for (; x0 & lt; = x1; x0++)
- {
- LCD_L0_XorPixel (x0, y);
- }
- }
- else
- {
- if (x1 & gt; 239)
- {
- x1 = 239;
- }
- if (x0 & gt; 239)
- {
- x0 = 239;
- }
- /* 设置增长方向为:左 --> 右,上 --> 下 */
- __writeCommand (0, 0x00, 0x04);
- __writeCommand (0, 0x01, 0x07);
- /* 设置起始坐标 */
- setCoordinate (x0, y);
- while (x0++ & lt; = x1)
- __writeData16 (LCD_COLORINDEX);
- }
- }
第一个 if 分句中,之所以沿用原来的代码,是因为实践中发现,如果按照 else 分句中的形式修改,GUI 在 GUI_DRAWMODE_XOR 模式下工作不正常。
一些时间相关的函数,如 GUI_Delay,需要用到时钟。使用系统时钟节拍 SysTick,每1ms发出一个中断,同时将 GUI 的时间变量 OS_TimeMS++,就实现了时钟功能。SysTick 的中断服务函数如下:
- void
- SysTick_ISR (void)
- {
- OS_TimeMS++;
- if (OS_TimeMS & gt; 24 * 60 * 60 * 1000) /* 一天后清零,防止溢出 */
- OS_TimeMS = 0;
- }
中断服务函数需要在 startup_ewarm.c 中注册。
以周立功公司提供的 uC/OS 移植模板为基础,将 GUI 的源代码添加进去。底层驱动 LCDDummy.c 无需再修改,可以直接使用。
在 …/GUI/Include/GUIConf.h 中,将 GUI_OS 设为1。其他配置基本可以不变。
由于加入了操作系统,systemInit.c 和 SysTick 部分的代码不再需要。在 target.h 中设定系统时钟:
- /* external clock 外部时钟 */
- #define EXT_CLK SYSCTL_XTAL_6MHZ
- /* 1:Enable PLL 使能PLL */
- #define PLL_EN 1
- /* CCLK divider CCLK分频系数 */
- #define CCLK_DIV SYSCTL_SYSDIV_4
用 GUI_X_uCOS.c 代替 GUI_X.c。这时,GUI_Delay 的参数单位由ms变成系统时钟节拍。
在编译过程中,根据编译器的错误提示,开启 os_cfg.h 中的一些选项。这样,就可以完成 OS 的添加。