在嵌入式系统中通常用的图形用户界面有ucGUI,miniGUI,QT等。
ucGUI是嵌入式应用中的图形支持系统。.它设计用于为任何使用LCD图形显示的应用提供高效的独立于处理器及LCD控制器的图形用户接口,它适用单任务或是多任务系统环境, 并适用于任意LCD控制器和CPU下任何尺寸的真实显示或虚拟显示。
要将ucGUI移植到先关的液晶屏上我们首先要了解ucGUI的层次结构以及它各个层次之间的相互调用好相互协作关系。关于GUI的文件目录以及相关GUI层次结构本文不再叙述,详细的资料可以在网上找到。本文着重介绍如何在Smart ARM2200开发平台上移植带ucOS操作系统的ucGUI。
注意:在添加操作系统和GUI的时候,开始的工程模板为操作系统的模板!
1、 进行高层配置
(1)、GUI配置
将ucGUI目录下的config文件夹中的GUIConf.h头文件,将GUI_OS配置成1,这样GUI才能支持多任务的操作系统。由于开发板没有触摸,所以将GUI_SUPPORT_TOUCH配置为0。LCDConf.h中的文件改为如下:
#define LCD_XSIZE (240) /* X-resolution of LCD, Logical coor. */
#define LCD_YSIZE (320) /* Y-resolution of LCD, Logical coor. */
#define LCD_BITSPERPIXEL (16)
#define LCD_CONTROLLER -1
#define LCD_SWAP_RB 1
GUI提供了多种液晶控制器的驱动程序,开发板的控制器多对应的启动程序并没有出现在GUI里(这里BS以下ZLG,给的配套教材和开发板上TFT型号不一样!)。宏定义LCD_CONTROLLER定义为-1表示驱动程序在GUI中并没有提供,而需要用户自己来编写。如果用户采用的控制器驱动程序是GUI提供的,那么就把这个宏定义改为驱动器的型号(注意:是驱动器的型号而不是LCD的型号)。LCD_SWAP_RB定义为1,GUI的颜色和屏的颜色能对应(以前就是因为这个问题颜色一直有错误)。LCDConf.h中其他的代码可以不需要(个人认为其他的代码是GUI为它提供的驱动程序准备的)。
(2)、系统配置
在config.h文件中添加GUI中所有的头文件。如果不添加的话有些定义不能使用。
2、系统总线速率的更改
由于GUI在运行的过程中采用了16位数据传输,在传输速率上有一定的要求,因此我们需要在工程模板的Startup.s文件中更改总线速率。将原初始化外部总线控制器的代码(如下)
ResetInit
;Initial extenal bus controller.
;初始化外部总线控制器,根据目标板决定配置
LDR R0, =PINSEL2
IF :DEF: EN_CRP
LDR R1, =0x0f814910
ELSE
LDR R1, =0x0f814914
ENDIF
STR R1, [R0]
LDR R0, =BCFG0
LDR R1, =0x1000ffef
STR R1, [R0]
LDR R0, =BCFG1
LDR R1, =0x1000ffef
STR R1, [R0]
; LDR R0, =BCFG2
; LDR R1, =0x2000ffef
; STR R1, [R0]
; LDR R0, =BCFG3
; LDR R1, =0x2000ffef
; STR R1, [R0]
BL InitStack ;初始化堆栈 Initialize the stack
BL TargetResetInit ;目标板基本初始化 Initialize the target board
;跳转到c语言入口 Jump to the entry point of C program
B __main
改为:
ResetInit
;Initial the extenal bus controller
;初始化外部总线控制器,根据目标板决定配置
LDR R0, =PINSEL2
IF :DEF: EN_CRP
LDR R1, =0x0f814910
ELSE
LDR R1, =0x0f814914
ENDIF
STR R1, [R0]
; 定义总线速度控制字
BCFG_DEF EQU 0x10000400
IDCY EQU (0x00<<0)
WST1 EQU (0x01<<5)
WST2 EQU (0x01<<11)
BCFG3_SET EQU (BCFG_DEF | IDCY | WST1 | WST2)
IDCYFS EQU (0x01<<0)
WST1FS EQU (0x03<<5)
WST2FS EQU (0x03<<11)
BCFG_FS EQU (BCFG_DEF | IDCYFS | WST1FS | WST2FS)
LDR R0, =BCFG0
LDR R1, =BCFG_FS
STR R1, [R0]
LDR R0, =BCFG1
LDR R1, =BCFG_FS
STR R1, [R0]
LDR R0, =BCFG2
LDR R1, =0x1000ffef
STR R1, [R0]
LDR R0, =BCFG3
LDR R1, =BCFG3_SET
STR R1, [R0]
BL InitStack ;初始化堆栈 Initialize the stack
BL TargetResetInit ;目标板基本初始化 Initialize the target board
;跳转到c语言入口 Jump to the entry point of C program
B __main
这样就完成了总线的更改。(程序具体的含义可参照配套教材)
3、驱动程序的移植
在GUI的层次调用中,所有的API函数都是最后调用了针对屏的画点函数。因此在进行驱动程序的移植的过程中只需要编写针对次液晶屏的画点和初始化函数即可(个人任务,如何大家有不同意见可以提出来)。用户自己的驱动程序在gui文件夹下的LCDDriver下的LCDDummy.c文件。在这个文件中有2个函数分别为:void LCD_L0_SetPixelIndex(int x, int y, int PixelIndex)和unsigned int LCD_L0_GetPixelIndex(int x, int y),而在这2个函数中可以分别看到
/* Write into hardware ... Adapt to your system */
{
/* ... */
}
和
/* Read from hardware ... Adapt to your system */
{
PixelIndex = 0;/* ... */
}
这段注释的意思就是要求用户添加自己的驱动程序。在下面的LCD_L0_Init函数中将LCD_INIT_CONTROLLER()改为用户自己的LCD初始化函数。
开发板上的驱动程序在配套的光盘中提供了。我们需要使用的是其中的2个函数,一个画点函数和一个初始化函数。LCD_L0_SetPixelIndex和LCD_L0_GetPixelIndex以及LCD_L0_Init函数需要修改的部分如下:
void LCD_L0_SetPixelIndex(int x, int y, int PixelIndex)
{
#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
GUI_Point(x, y, PixelIndex);
}
unsigned int LCD_L0_GetPixelIndex(int x, int y) {
LCD_PIXELINDEX PixelIndex;
#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 = 0;
TftSetWrite(x,y);
PixelIndex = TftRcvDat();
return PixelIndex;
}
int LCD_L0_Init(void) {
TftInit();
return 0;
}
4、时间函数的修改
从网上下载的GUI源码文件中有个Sample文件夹,在它下面有个GUI_X文件夹,在这个文件夹下有3个GUI_X*文件。分别为:GUI_X.c、GUI_X_embOS.c、GUI_X_ucOS.c这3个文件分别对应无操作系统embOS和ucOS。我们采用的是ucOS,所以采用第三个文件使用。这个文件内容入下:
#include "uCOS_II.h"
#include "GUI.H"
#include "stdio.H"
int GUI_X_GetTime(void) {
return OSTimeGet();
}
void GUI_X_Delay(int Period) {
OSTimeDly(Period);
}
void GUI_X_ExecIdle(void) {
OS_X_Delay(1);
}
static OS_EVENT * DispSem;
U32 GUI_X_GetTaskId(void) { return ((U32)(OSTCBCur->OSTCBPrio)); }
void GUI_X_InitOS(void) { DispSem = OSSemCreate(1); }
void GUI_X_Unlock(void) { OSSemPost(DispSem); }
void GUI_X_Lock(void) {
INT8U err;
OSSemPend(DispSem, 0, &err);
}
void GUI_X_Init(void) {}
改为:
#include "GUI.h"
#include "GUI_X.h"
#include "config.h"
int GUI_X_GetTime(void) {
return OSTimeGet();
}
void GUI_X_Delay(int ms) {
OSTimeDly(ms);
}
void GUI_X_Init(void) {}
void GUI_X_ExecIdle(void) {}
void GUI_X_Log(const char *s) {}
void GUI_X_Warn(const char *s) {}
void GUI_X_ErrorOut(const char *s) {}
OS_EVENT * DispSem;
U32 GUI_X_GetTaskId(void) { return ((U32)(OSTCBCur->OSTCBPrio)); }
void GUI_X_InitOS(void) { DispSem = OSSemCreate(1); }
void GUI_X_Unlock(void) { OSSemPost(DispSem); }
void GUI_X_Lock(void) {
INT8U err;
OSSemPend(DispSem, 0, &err);
}
如果出现编译错误,提示说函数没有被定义,那么只需要将函数定义一个就行,写个空函数就可以。
如果在编译过程中出现错误,那么按照错误信息进行修改即可。至此,移植+操作系统以初步可用。