2013 9 24
按照qq meteor群共享里面的移植ucosgui移植文档,移植,就可以了,不同的是,这个文档,移植的是不带ucosii系统的,是在裸系统上移植的,所以把不同之处记录下来:
1,按照文档所述,把底层驱动的一些函数都写好,之后按照要求LCDDummy。c文件中的需要改的地方,改掉,注意添加你自己写的驱动文件的头文件。如#include "LCD9341_Driver.h" //LCD驱动头文件
2.把一切配置文件,LCDConf.h GUIConf.h按自己要求改掉,
3.要添加GUI_X_uCOS。c文件的时候和GUI_X。c文件,因为带操作系统,如果两者都要加,这时候编译的时候,会发现,两个源文件出现重定义的链接错误,这时候保留前者GUI_X_uCOS。c的定义,把GUI_X。c重复的函数屏蔽掉。(网上说,可以不用 GUI_X。c ,把缺少的函数补在GUI_X_uCOS。c后面就可以,自己可以试试。)
4.编译的时候最后会出现,内存不够的报错,那么要改配置文件GUIConf.h的内存大小那个配置
5,还会出现这个情况void GUI_X_ExecIdle (void)
{
OS_X_Delay(1);
}
改为:
void GUI_X_ExecIdle (void)
{
OSTimeDly(1);
}
告诉OS_X_Delay没有定义,把设计到的这个函数换成 OSTimeDly(1)就可以了,因为我们带了操作系统
6.在main文件中,调用gui的api函数时,添加这个头文件即可#include "GUI.H"
在MDK环境下将3.90版本的UCGUI移植到STM32下了,为了方便大家,特写此移植方法,大家可以借鉴(有错误之处,望大家指点出来共同讨论!)
移植步骤:
第一步:首先,得把你的TFT底层驱动写好,既在裸机下,可以正常显示。
第二步:加入UCGUI程序包。
第三步:配置LCDConf.h GUIConf.h GUITouchConf.h(由于我的液晶不带触摸功能,此配置在此不讲。)
配置LCDConf.h文件如下:
#ifndef LCDCONF_H
#define LCDCONF_H
#define LCD_XSIZE (160) //配置TFT的水平分辨率
#define LCD_YSIZE (128) //配置TFT的垂直分辨率
#define LCD_CONTROLLER (54124) //TFT控制器的名称
#define LCD_BITSPERPIXEL (16) //每个像素的位数
#define LCD_FIXEDPALETTE (565) //调色板格式
#define LCD_SWAP_RB (0) //红蓝反色交换
#define LCD_INIT_CONTROLLER() TFT_Init() ; //此处需要定义的是你的TFT初始化函数
#endif /* LCDCONF_H */
配置GUIConf.h文件如下:
#ifndef GUICONF_H
#define GUICONF_H
#define GUI_OS (1) //多任务
#define GUI_SUPPORT_TOUCH (0) //触摸
#define GUI_SUPPORT_UNICODE (1) //Unicode支持
#define GUI_DEFAULT_FONT &GUI_Font6x8 //GUI默认字体
#define GUI_ALLOC_SIZE 5000 //动态内存的大小
#define GUI_WINSUPPORT 1 //窗口控件支持
#define GUI_SUPPORT_MEMDEV 1 //支持内存设备
#define GUI_SUPPORT_AA 1 /* Anti aliasing available */
#endif /* Avoid multiple inclusion */
第四步:最关键的一步。那就是让GUI能够找到你的LCD驱动。修改LCDDriver。
在编写你的TFT底层驱动程序的时候,一定不能忘记编写这两个函数:设置一个像素和获取一个像素的颜色,因为后面很多UCGUI和你的TFT驱动关联起来需要这两个函数为前提。以我的TFT为例:
void LCD_SetPixel(unsigned short x, unsigned short y, unsigned short color)
{
….
…
}
unsigned short LCD_GetPixel(unsigned short x, unsigned short y)
{
…
…
}
这两个函数写好,并测试可以正常显示后,接下来需要修改TFT与UCGUI关联的函数(在一个C文件下(我的是ili9320_ucgui.c),建议大家在移植GCGUI之前最好下载个别人移植好的例程,对着修改这样难度降低很多):
int LCD_L0_Init(void)
{
TFT_Init();
return 0;
}
这个函数,是GCGUI初始化TFT需要调用的,里面的函数就是你TFT底层驱动的初始化函数。
void LCD_L0_SetPixelIndex(int x, int y, int PixelIndex)
{
LCD_SetPixel(x,y,PixelIndex);
}
unsigned int LCD_L0_GetPixelIndex(int x, int y)
{
return LCD_GetPixel(x,y);
}
上面两个函数是其他函数的最基本元素,其他函数比如画线、点、圆都需要调用改函数。里面的LCD_SetPixel(x,y,PixelIndex)、LCD_GetPixel(x,y);就是你TFT底层驱动设置像素和获取像素的两个函数。
紧接着把该ili9320_ucgui.c文件下其他函数修改一下(凡是遇到设置像素和获取像素的地方用以上两个函数代替。)
接着,修改另一个C文件(ili9320_api.c)这里修改很简单,仅仅也是将设置像素和获取像素的函数替换掉自己定义的即可。
二、移植过程
先来看看解压后都有些什么东西: 核心的东西包括Config和GUI两个文件夹,这里面是ucgui的所有源码和配置文件。ConvertColor包含彩色转换函数,ConvertMono包含灰度到彩色转换的函数,Core包含核心程序,Font是字体文件,LCDDriver包含多种控制器驱动,Widget是窗口控件库,WM是窗口库,提供复杂的功能。其他文件夹包含一些应用范例以及一些有用的工具,留待慢慢探索。
1、config文件的移植:
Config文件夹是ucgui的配置文件夹,里面有3个文件:
GUIConf.h:gui的基本属性配置文件,有很多开关可以配置,具体可以参考ucgui的用户手册,这里只需配置几个必要的参数如下:
#ifndef GUICONF_H
#define GUICONF_H
#define GUI_OS (1)
#define GUI_SUPPORT_TOUCH (1)
#define GUI_SUPPORT_MOUSE (0)
#define GUI_SUPPORT_UNICODE (1)
#define GUI_DEFAULT_FONT &GUI_Font6x8
#define GUI_ALLOC_SIZE 12500
#define GUI_WINSUPPORT 1
#define GUI_SUPPORT_MEMDEV 0
#define GUI_SUPPORT_AA 0
#endif
LCDConf.h:LCD控制器的硬件配置文件,这个文件与硬件直接相关,一般是根据你所使用的LCD的类型和所用的LCD控制器的类型来配置。我的配置是一块友晶公司的800*480的触摸屏,支持18位色,不过我只使用16位,RGB565色彩模式,足矣。LCD控制器就是写的一个硬件模块,挂在avalon总线上,负责读取显示缓冲区中的数据,然后按照该LCD的时序输出显示到LCD上。显示缓冲区直接开辟在系统内存中,系统使用一块512K SRAM作为系统内存,CPU可以直接对其进行16位读写访问。通过仔细阅读ucgui的用户手册,可以知道,在我这种硬件配置条件下,可以选择LCDLin.c这个驱动文件,那么对应了LCD_CONTROLLER 配置为1300。在实际配置时,LCD大小为400*240,这是因为在硬件工程的pixbuffer模块中对分辨率进行了硬扩。
#include <system.h> #include <altera_avalon_pio_regs.h>
#define LCD_XSIZE (400) #define LCD_YSIZE (240)
#define LCD_BITSPERPIXEL (16) #define LCD_CONTROLLER 1300
#define LCD_ENDIAN_BIG 0 #define LCD_FIXEDPALETTE 565 #define LCD_SWAP_RB 1 #define LCD_VRAM_ADR SRAM_BASE #define LCD_BUSWIDTH 16 #define LCD_OPTIMIZE 1
#define LCD_READ_MEM(Off) IORD_16DIRECT(LCD_VRAM_ADR,(Off<<1)) #define LCD_WRITE_MEM(Off,data) IOWR_16DIRECT(LCD_VRAM_ADR,(Off<<1),data)
#define LCD_INIT_CONTROLLER()
在这里,最重要的就是LCD_READ_MEM(Off),LCD_WRITE_MEM(Off,data)的定义,当时在LCD驱动文件上花了很大时间,仔细研究了LCDLin.c文件后,发现很多都是针对特定的LCD控制器写的,我们根本用不到,由于LCD控制器中已经对LCD屏进行了初始化,所以在这里LCD_INIT_CONTROLLER()也不必定义。
GUITouchConf.h:触摸屏的配置文件。
//#define GUI_TOUCH_AD_LEFT 100 //#define GUI_TOUCH_AD_RIGHT 4000 #define GUI_TOUCH_SWAP_XY 1 #define GUI_TOUCH_MIRROR_X 0 #define GUI_TOUCH_MIRROR_Y 1
这里要根据特定的触摸屏来定义,主要修改GUI\Core\GUI_TOUCH_DriverAnalog.c文件,在后面将会继续讲述。至此,config文件移植完毕。
2、LCD device驱动的移植
三、运行第一个程序:hello_gui
下面,我们就让刚移植好的gui到实际的系统上去运行一下。
1、配置好FPGA的硬件;
2、打开nios II IDE,以hello_world工程为模版建立一个新的工程hello_gui;
3、将ucgui的Config和GUI两个文件夹(包含有我们刚刚修改过的几个文件)复制到工程目录下;
5、修改hello_world.c的内容为:
#include "GUI.H"
#include <system.h>
void main(void) {
GUI_Init();
GUI_SetBkColor(GUI_BLUE);
GUI_Clear();
GUI_SetColor(GUI_RED);
GUI_DispString("Hello world!");
while(1);
}
6、在system library选项中选择RTOS为MicroC/OS-II;
这时如果编译工程,会出现一些未定义错误,类似于GUI_X_未定义等等,原来是缺少GUI_X.c文件,这个文件定义了gui与rtos的接口,以及debug错误报告等函数,于是我们需要添加这个文件。经过寻找,在Sample文件夹中发现了GUI_X这个文件夹,打开一看,里面有我们所需要的GUI_X.c文件,由于我们使用了MicroC/OS-II操作系统,所以我们使用其中的GUI_X_uCOS.c文件,将这个文件copy到工程目录下,并在文件结尾添加下面这几行:
void GUI_X_Log (const char *s) { GUI_USE_PARA(s); }
void GUI_X_Warn (const char *s) { GUI_USE_PARA(s); }
void GUI_X_ErrorOut(const char *s) { GUI_USE_PARA(s); }
并将其中的:
void GUI_X_ExecIdle (void)
{
OS_X_Delay(1);
}
改为:
void GUI_X_ExecIdle (void)
{
OSTimeDly(1);
}
方可编译通过。
7、Debug as hardware,这样,就可以看见结果了。我的结果是LCD上用篮底红字显示出了“hello world!”字样。表示ucgui3.98在Nios II上初步移植成功!
http://www.openedv.com/posts/list/20610.htm
ucGUI入门——ucGUI-ucOS-STM32-TFT触摸屏
2011-09-14 11:58:41| 分类: ucGUI|字号 订阅
该篇以入门的角度介绍 GUI的移植过程,不作深入研究,只求以最快速度应用起来。
选用芯片STM32F103VET6(512Flash/64KRAM),开发平台IAR540,系统包括TFT彩屏(ILI9325),电阻式触摸屏(AD7843),使用 OS操作系统, GUI3.90系统。ILI9325配置及操作系统的移植在之前的文章中有介绍,在此就不详细说明了。
在完全不明白文件含义和内存够大时,可把文件全部放入项目中,另外加入配置Config和GUI_X两个文件夹,如图:
Config里的文件在\Start\Config可找到,GUI_X里的文件可以\Sample\GUI_X找到。
把文件加入项目后就可以开始进行配置了,在头文件里加入"GUI.h” ,在项目option里加入编译时包含文件的路径,这些就不细说了,讲讲具体的配置过程。
(一)GUIConf.h——GUI基本配置
#define GUI_OS (1) /* 支持系统*/ #define GUI_SUPPORT_TO H (1) /*支持触摸屏 */ #define GUI_SUPPORT_UNICODE (1) /* 支持ASCII/UNICODE 字符 */
#define GUI_DEFAULT_FONT &GUI_Font6x8 /* 默认字体*/ #define GUI_ALLOC_SIZE 5000 /* 动态存储器大小*/ #define GUI_WINSUPPORT 1 /* 是否使用窗体控制*/ #define GUI_SUPPORT_MEMDEV 1 /* 是否使用存储设备*/ #define GUI_SUPPORT_AA 1
(二)配置LCD
(1)LCDConf.h
#define LCD_XSIZE (240) /* LCD宽 */ #define LCD_YSIZE (320) /* LCD高*/
#define LCD_BITSPERPIXEL (16) /* 位数 8位/16位 */
#define LCD_CONTROLLER 9325 #define LCD_SWAP_RB 1 // 红蓝反色
(2)ILI9325_ gui.c——GUI和ILI9325.c的函数接口 #define BKCOLOR LCD_BKCOLORINDEX #define COLOR LCD_COLORINDEX
#if (LCD_CONTROLLER == 9325)
int LCD_L0_Init(void) { TFT_Init(); return 0; }
void LCD_L0_SetPixelIndex(int x, int y, int PixelIndex) { // 设定指定点颜色 TFT_PaintPoint(x,y,COLOR); }
unsigned int LCD_L0_GetPixelIndex(int x, int y) { // 获取指定点颜色 return TFT_GetPoint(x,y); }
void LCD_L0_XorPixel(int x, int y) { LCD_PIXELINDEX Index = TFT_GetPoint(x,y); TFT_PaintPoint(x,y,LCD_NUM_COLORS-1-Index); }
void LCD_L0_DrawHLine (int x0, int y, int x1) { TFT_PaintLine(x0,y,x1,y,LCD_COLORINDEX); }
void LCD_L0_DrawVLine (int x, int y0, int y1) { TFT_PaintLine(x,y0,x,y1,LCD_COLORINDEX); }
void LCD_L0_FillRect(int x0, int y0, int x1, int y1) { #if !LCD_SWAP_XY for (; y0 <= y1; y0++) { LCD_L0_DrawHLine(x0,y0, x1); } #else for (; x0 <= x1; x0++) { LCD_L0_DrawVLine(x0,y0, y1); } #endif }
………………………………(以下省略)
(三)GUI_X_OS.c——配置操作系统
这个文件从Sample中拷过来基本都不用修改,只改了一下延时的函数。 void GUI_X_ExecIdle (void) { OSTimeDly(50); // 原来是OS_X_Delay(1); }
(四)触摸屏配置
(1)GUITouchConf.h #define GUI_TOUCH_AD_LEFT 0 #define GUI_TOUCH_AD_RIGHT 240 #define GUI_TOUCH_AD_TOP 0 #define GUI_TOUCH_AD_BOTTOM 320 #define GUI_TOUCH_SWAP_XY 0 #define GUI_TOUCH_MIRROR_X 0 #define GUI_TOUCH_MIRROR_Y 0
(2)GUI_X_Touch.c——GUI和AD7843.c的接口函数
void GUI_TOUCH_X_ActivateX(void) { }
void GUI_TOUCH_X_ActivateY(void) { }
int GUI_TOUCH_X_MeasureX(void) { u16 X = 0; X = AD7843_X();
return (X); }
int GUI_TOUCH_X_MeasureY(void) { u16 Y = 0; Y = AD7843_Y();
return (Y); }
注意触摸屏的坐标需要校准,要把采集到的AD值转换成与LCD屏相对应的坐标。
底层驱动配置完后,就可以开始做上层应用了。
在\ GUI-V3-90a\ GUI390a\Sample\ gui394_sample里有很多例子,随便选一下C文件放入项目中。
在创建任务时创建两个任务
static void AppTaskCreate(void) { INT8U err;
OSTaskCreate(MainTask, (void *)0, &TASK1_STK[TASK1_STK_SIZE - 1], TASK1_PRIO); OSTaskNameSet(TASK1_ID, "Task1-MAIN", &err);
OSTaskCreate(Task_Key, (void *)0, &TASK_KEY_STK[TASK_KEY_STK_SIZE - 1], TASK_KEY_PRIO); OSTaskNameSet(TASK_KEY_ID, "Task-KEY", &err); }
MainTask函数在sample例子里,按键响应函数如下:
void Task_Key(void *pdata) { AD7843_Ini(); while(1) { OSTimeDlyHMSM(0,0,0,10); GUI_TO H_Exec(); } }
至此,就基本完成,可以编译调试了。
gui中触摸屏的移植
最近研究了一下ucGUI,功能还凑合,前面的功能挺简单,研究到触摸屏遇到了一点小困难。我创建了一个按钮,点击它老是没反应,折腾了近一天终于搞定。
简要介绍一下移植方法,首先在GUIConf.h中定义#define GUI_SUPPORT_TOUCH (1) 支持触摸屏。
然后是触摸屏的驱动程序(起码能读出AD转换后的X、Y值),有了驱动程序,然后加入GUI_X_Touch.c文件,并添加以下内容。
#include "GUI.h"
#include "GUI_X.h"
#include "dp_touch.h"
void GUI_TOUCH_X_ActivateX(void) {
}
void GUI_TOUCH_X_ActivateY(void) {
}
int GUI_TOUCH_X_MeasureX(void)
{
int xa[MAX_NUM],temp;
u8 i,j;
int tmx;
u8 xcount=0;
do
{
xa[xcount]=XPT2046_GetOneTouchX();
if((xa[xcount]>300)&&(xa[xcount]<4000))
xcount++;
else
break;
}while(xcount<MAX_NUM);//循环读数10次
if(xcount>=MAX_NUM)
{
xcount=0;
for(i=0;i<MAX_NUM-1;i++)
{
for(j=i+1;j<MAX_NUM;j++)
{
if(xa[i]>xa[j])
{
temp=xa[i];
xa[i]=xa[j];
xa[j]=temp;
}
}
}
tmx=(xa[3]+xa[4]+xa[5]+xa[6])/4;
}
return tmx;
}
//y坐标滤波
int GUI_TOUCH_X_MeasureY(void)
{
int ya[MAX_NUM],temp;
u8 i,j;
int tmy;
u8 ycount=0;
do
{
ya[ycount]=XPT2046_GetOneTouchY();
if((ya[ycount]>300)&&(ya[ycount]<4000))
ycount++;
else
break;
}while(ycount<MAX_NUM);//循环读数10次
if(ycount>=MAX_NUM)
{
ycount=0;
for(i=0;i<MAX_NUM-1;i++)
{
for(j=i+1;j<MAX_NUM;j++)
{
if(ya[i]>ya[j])
{
temp=ya[i];
ya[i]=ya[j];
ya[j]=temp;
}
}
}
tmy=(ya[3]+ya[4]+ya[5]+ya[6])/4;
}
return tmy;
}
void GUI_TOUCH_X_ActivateX(void)和void GUI_TOUCH_X_ActivateY(void)直接为空即可,
int GUI_TOUCH_X_MeasureX(void) 和int GUI_TOUCH_X_MeasureY(void)返回读取的X和Y值(其实是AD转换值),程序里滤了一下波。XPT2046_GetOneTouchX()和XPT2046_GetOneTouchY()是我自己编写的读坐标程序(未滤波)。
然后点击屏幕的左上角和右下角,记下坐标(AD转换值,具体方法自己发挥,我把值打印在屏幕上了),然后配置GUITouchConf.h,如下所示。
#ifndef GUITOUCH_CONF_H
#define GUITOUCH_CONF_H
#define GUI_TOUCH_AD_LEFT 3850
#define GUI_TOUCH_AD_RIGHT 310
#define GUI_TOUCH_AD_TOP 380
#define GUI_TOUCH_AD_BOTTOM 3840
#define GUI_TOUCH_SWAP_XY 0
#define GUI_TOUCH_MIRROR_X 0
#define GUI_TOUCH_MIRROR_Y 1//镜像,根据自己的屏幕确定
#endif
至此准备工作完成,一个简单的实例。暂时没使用操作系统,所以偶在定时器2中每隔10ms调用GUI_TOUCH_Exec();获得触摸屏坐标(ucGUI已根据GUITouchConf.h中的配置转换完成),主程序如下。
int main(void)
{
BUTTON_Handle hButton;//按钮句柄
GUI_PID_STATE Button_State; //输入设备状态
int temp=1;
SystemInit();//系统初始化
GUI_Init(); //液晶屏初始化
XPT2046_Config();//触摸屏初始化
SPI2_Config();//spi初始化
GUI_SetBkColor(GUI_BLUE);//设置背景色
GUI_Clear();
hButton=BUTTON_Create(10,20,40,20,GUI_ID_OK,WM_CF_SHOW);//创建一个按钮
BUTTON_SetText(hButton, "Click");
TIMER2_Config();//在定时器2中每隔10ms调用GUI_TOUCH_Exec();获得触摸屏坐标
NVIC_Config();
while(1)
{
TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);//关中断
GUI_TOUCH_GetState(&Button_State);//得到输入设备状态
GUI_TOUCH_StoreStateEx(&Button_State);//存储输入设备状态
GUI_DispDecAt(Button_State.x,10,50,4);//输入设备当前x坐标
GUI_DispDecAt(Button_State.y,10,80,4);//输入设备当前y坐标
GUI_DispDecAt(Button_State.Pressed,10,100,4);//是否按下
GUI_Exec();//执行回调函数重绘无效窗口(通常GUI_Delay()自动调用此函数)
if(GUI_GetKey()==GUI_ID_OK)//按钮按下
{
if(temp==1)
{
temp=0;
BUTTON_SetText(hButton,"yes");
}
else
{
temp=1;
BUTTON_SetText(hButton,"no");
}
}
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开中断
delay_ms(1000);
}
}
注释的比较详细了,具体就是显示一个按钮,按钮按下时上面的文字在“yes”和“no”之间进行切换。按钮下方显示按下位置的坐标和状态。