编译工具:MDK4.20
开发板:安富莱v2版开发板
调试器:JLink v8盗版
移植篇
相信大家有移植经验的都知道,移植确实是一件非常墨迹的事情,怎么说呢,代码都是别人的,风格也是别人的,文件结构,定义之类都是别人的,看别人的东西是种进步,但是,也是一个痛苦的过程,因为有时候资料确实很少,而且有时候还是E文的,专业名词一大堆,我们根本没有办法想象工作量是多么的巨大.
不过事情都是这样,你不懂他的时候他就像是巨山,但是一旦你理解他的时候,你才会感觉到原来他是那么的简单(从我的经验上来看,至少应该是这样的).
好吧,闲话少说,我们就来开始我们的移植之旅把.
首先,我们需要准备的东西有uCGUI3.90,这个版本是大家现在用的比较多的,效率也比较高,别人都是这么评论的,至于其他版本的,我没有接触很多,所以不能过多评论.
uCGUI有三个文件夹,一个是tool,这个文件夹是用来使用一些uCgui的上位机程序,基本都是字体和模板查看之类的.在sample文件夹下面是已经别人帮你写好了很多有用的东西,像跟操作系统有关的GUI_X或者一些模板(后面我们会用到的自己定义的Demo),或者是gui配置.后面再一一详细叙说这个文件夹的功能.在Start文件夹里面,这是我们最主要的文件夹.里面就包含了uCGUI的源代码,uCGUI的作者把源代码放进vc里面进行编译了(当然,这是用标准C语言写的程序,所以我们可以放在任何C语言平台下编译而不会担心兼容性问题,这个uCGUI在这方面做的算是完美了),所以,我们可以在vc平台下写界面,然后再把代码拷进我们的下位机编译器进行编译,这样子效率就会非常高了.(像51那时候写界面就是疯狂的一次一次的烧,真是纠结..).
然后这里放的就是uCGUI的源代码了,在GUI文件夹下面.
这则是每个文件夹的功能(参考uCGUI中文手册,ucgui.com翻译).
大概看一下就可以了,这个跟我们移植的关系不大,关键点是带*的可以不包含进去(待会配置会讲到.).然后其他的都要包含进去.
接着我们要把我们的文件包含进我们已经搭建好的工程,这里说明下我们的工程要求.
一般来说,我们要画一个图形,最基本的就是从点开始,从点到线,从点到面...,所以在已经建好的工程里面你要能点亮你的屏幕,能点出最基本的点,能填充出最基本矩阵(这是uCGUI最包含的函数),反正我移植的时候涉及到的包括三个函数,LCD_Init();LCD_Draw_Point(x,y,color),LCD_Fillcircuit(x1,x2,y1,y2).这三个函数是必须的,后面也会说明如何把这三个函数进行填充.
当我们把文件复制进去的时候,再加上我们一开始已经创建好的工程的时候,文件结构差不多就是这个样子了,截图如下
user包括,main函数就是我们初始化和函数调用,绘图用的文件,另外那几个文件相信大家都明白了把,tft_lcd.c就是你在,没有移植uCGUI的情况下,纯液晶屏驱动,这里建议把液晶屏的API和最底层驱动(API就是画圆啊,画椭圆啊,清除屏幕之类的,底层驱动就是驱动液晶屏的管脚运作,fsmc初始化,时钟配置之类的),不过我这里也是集成在一起了,比较懒,大家别学.
其他文件夹我都包含进去了,在没包含进去的时候,编译是可以通过的,但是,那么多文件包含进去,有些配置还是没有设定好的.所以会有错误,蛮编译一下.没事的.
这里我们需要修改的文件只有这几个:,,,这是ucgui开放给我们的用户层的文件,在ucgui中,lcdDrive文件夹要自己加进去,GUI_X.c也是,另外三个文件都是包含了,在GUIConf.h中
- 1 #ifndef GUICONF_H
- 2 #define GUICONF_H
- 3
- 4 #define GUI_OS (0) // 这里指的是对操作系统的支持,因为我们这里只有单纯的移植uCGUI,
- 5 // 所以,要把这个关闭,不然后面会有很多东西编译进去
- 6 // 不然到时候编译的时候会发生很多你无法修改的错误
- 7 #define GUI_SUPPORT_TOUCH (0) // 这里则是对触摸屏的支持,触摸屏我是能做,但是没有用,
- 8 //所以省去麻烦,把触摸屏关掉,相信移植好之后,要支持触摸屏大家都会有门路了
- 9 #define GUI_SUPPORT_UNICODE (1) // UNICODE编码支持,如果大家只是单纯的想用英文显示,而不移植中文字库进去,
- 10 //这个是可以关掉的,因为UNICODE是向下支持的,所以开不开无所谓
- 11 // 反正都是能够正常显示的
- 12 #define GUI_DEFAULT_FONT &GUI_Font6*8 // 这里是设定默认字体的,我们可以在要写什么字的时候把该字号的字体.
- 13 //c包含进我们的主函数里面,所以这里不用改
- 14 #define GUI_ALLOC_SIZE 5000 // 这里讲的是动态内存机制
- 15 // 这里rgb接口模式的可能会有用到,uCGUI就是在我们的ram开辟一块空间,
- //然后uCGUI把运算好的每个点都放进我们主控ram里面的空间
- 16 // 所以,这里就相当于把写进液晶gram里面的操作变成了写进主控ram里面,
- //那么大家可能就会问了,干嘛这么多次一举,直接写进去不就可以了
- 17
- 18 /*原理: 一般来说,在大的屏幕上面(4.0以上吧,印象中),都是没有控制器,(像我的液晶屏就是spfd5420,当然,
- 19 不同的屏幕的液晶主控都是不一样的,但是寄存器操作都是差不多的,
- 20 所以有些初始化配置还是能互用的.)所以呢,这时候我们要用到的就只有RGB接口了,
- 21 RGB要求我们要不断的刷新屏幕,刷新率越高,效果就越好,因为一般这种用来做动态的,uCGUI就是属于静态类型的
- 22 像如果我们要用STM32主控做视频应用的时候,就是动态的,我们需要不断的刷新屏幕,但是当我们主控一边运算,
- 23 一边往液晶接口送数据的时候,会有明显刷屏的感觉(运算->画点->运算->画点....,这个运算
- 24 ->运算.......画点->画点->画点...是不一样的,因为对屏幕一直画点,填充,而中间不用插入运算,
- 25 刷一个屏幕时间时间倍速差别是非常巨大的,后面大家也会见识到这种差别.),所以,用GUI申请的空间里面
- 26 边运算,边填充,填充完再一次性运出去(这里可以通过DMA控制FSMC总线,不断的从外置SRAM往GRAM自动搬运数据,
- 27 这是不用主控去插手的,所以,主控大部分时间是负责运算,其他时间可以空闲出来,
- 28 让DMA自己去忙活),同理,因为dma跟cpu的分工,所以,这里同样的把画点,画点,运算,运算不完全的分开了,
- 29 屏幕刷新速度非常之可观(DMA的速度相比大家还是非常了解的,它就是为速度而生的.),*/
- 30
- 31 //#define GUI_ALLOC_SIZE 1024*1024
- /* Size of dynamic memory ... For WM and memory devices*/
- 32
- 33 /*********************************************************************
- 34 *
- 35 * Configuration of available packages
- 36 */
- 37
- 38 #define GUI_WINSUPPORT 1 // 这个是窗口支持,一般开始开着的
- 39 #define GUI_SUPPORT_MEMDEV 1 // 内存控制,开
- 40 #define GUI_SUPPORT_AA 0 // 抗锯齿,为了性能着想,还是关了比较好
- 41
- 42 #endif /* Avoid multiple inclusion */
复制代码
GUITouchConf.h是有关于触摸屏配置的,这里我们就略过了.
- 1 #ifndef LCDCONF_H
- 2 #define LCDCONF_H
- 3
- 4 /*********************************************************************
- 5 *
- 6 * General configuration of LCD
- 7 *
- 8 **********************************************************************
- 9 */
- 10
- 11 /*
- 12 * 这个定义的是你x轴的长度,像我这里的屏幕长为400个像素
- 13 */
- 14 #define LCD_XSIZE (400)
- 15
- 16 /*
- 17 * 这里这是屏幕的宽
- 18 */
- 19 #define LCD_YSIZE (240) /* Y轴长度 */
- 20
- 21 /*
- 22 * 这里是屏幕的颜色有多少个位
- 23 */
- 24 #define LCD_BITSPERPIXEL (16) /* 定义数据长度为16bit*/
- 25
- 26 /*
- 27 * 控制器类型,如果你里面有包含这些判断变量,这个最好改成你认识的
- 28 */
- 29 #define LCD_CONTROLLER 9325 /* 定义控制器类型 */
- 30
- 31
- 32 #endif /* LCDCONF_H */
复制代码
配置层的东西我们都已经搞定了,接下来我们要修改的是uCGUI开放给我们的用户层的东西,GUI_X.c可以直接拷进去,这个是用户层和系统层的关联文件,一些demo也会用到这个文件的时间函数或者延迟函数,所以这个文件拷进去放着就可以了.
- 1 #include "GUI.h"
- 2 #include "GUI_X.h"
- 3
- 4 /*********************************************************************
- 5 *
- 6 * Global data
- 7 */
- 8 volatile int OS_TimeMS;
- 9
- 10 /*********************************************************************
- 11 *
- 12 * Timing:
- 13 * GUI_X_GetTime()
- 14 * GUI_X_Delay(int)
- 15
- 16 Some timing dependent routines require a GetTime
- 17 and delay function. Default time unit (tick), normally is
- 18 1 ms.
- 19 译:一些需要时间的相关函数需要用到gettime和延迟.
- 20 默认时间单位为1ms.
- 21 */
- 22
- 23 int GUI_X_GetTime(void) {
- 24 return 0;
- 25 }
- 26
- 27 void GUI_X_Delay(int ms)
- 28 {
- 29 }
- 30
- 31 /*********************************************************************
- 32 *
- 33 * GUI_X_Init()
- 34 *
- 35 * Note:
- 36 * GUI_X_Init() is called from GUI_Init is a possibility to init
- 37 * some hardware which needs to be up and running before the GUI.
- 38 * If not required, leave this routine blank.
- 39 *
- 40 * 译:GUI_X_Init()是在gui_init()调用前,gui启动或者运行前准备.
- 41 * 如果不是必须的,可以把这个函数留空白.
- 42 */
- 43
- 44 void GUI_X_Init(void)
- 45 {
- 46
- 47 }
- 48
- 49
- 50
- 51 /*********************************************************************
- 52 *
- 53 * GUI_X_ExecIdle
- 54 *
- 55 * Note:
- 56 * Called if WM is in idle state
- 57 * 译:视窗管理器空闲时候调用
- 58 */
- 59
- 60 void GUI_X_ExecIdle(void) {}
- 61
- 62 /*********************************************************************
- 63 *
- 64 * Logging: OS dependent
- 65
- 66 Note:
- 67 Logging is used in higher debug levels only. The typical target
- 68 build does not use logging and does therefor not require any of
- 69 the logging routines below. For a release build without logging
- 70 the routines below may be eliminated to save some space.
- 71 (If the linker is not function aware and eliminates unreferenced
- 72 functions automatically)
- 73 译:系统日志层应用程序
- 74
- 75 */
- 76
- 77 void GUI_X_Log (const char *s) {}
- 78 void GUI_X_Warn (const char *s) {}
- 79 void GUI_X_ErrorOut(const char *s) {}
复制代码
在uCGUI和底层驱动的接口文件时LCDDriver.c,大家打开文件夹可以看到这几个文件:lcdwin.c,lcdnull.c,lcdDummy.c,这三个文件你随便修改哪个都行,一开始我是直接修改lcdnull.c的,不过一开始没经验,一直不能正常调用我的uCGUI函数,所以,我的队友告诉我,要修改另外一个(lcdwin.c),这次才反应过来,理论上,修改lcdnull.c也是可以的,就是一些细节性的东西可以要多注意点.下面我讲解下怎么修改lcdwin.c这个文件.
源文件我先贴出来:
这个文件可能有点大,500多行,都是密密麻麻的代码,不过,我们要想使我们的uCgui能够使用,要修改的函数其实也就每几句.
我先给大家讲解下这里面函数的关系:
- #if LCD_BITSPERPIXEL <= 8
- #define PIXELINDEX U8
- #else
- #define PIXELINDEX WORD
- #endif
复制代码
这里我们定义的是16位的像素点(在前面那三个配置文件里面),定义为word.
- #define SETPIXEL(x, y, c) LCDSIM_SetPixelIndex(x, y, c, LCD_DISPLAY_INDEX)
- #endif
- #define XORPIXEL(x, y) _XorPixel(x,y)
复制代码
这里定义的是显示点的函数,我们需要把所有LCDSIM_SetPixelIndex(x, y, c, LCD_DISPLAY_INDEX),都换成你的画点函数,比如我这里使用的是
LCD_L0_SetPixelIndex(x轴坐标,y轴坐标,该点颜色);然后呢,就是修改LCD_L0_FillRect(int x0, int y0, int x1, int y1);这个是填充矩形函数,
你可以直接把函数里面的东西清空,然后写上自己在底层硬件驱动的api,我的函数优化得体无完肤了,基本没有办法再拷贝过来,所以待会讲这函数的时候,直接跳过去.
最后最重要的要修改的就是LCD_L0_Init(void);这函数里面可以直接填充你的初始化函数,好了,剩下基本就不需要修改了,其他的修改就留给优化了.
下面我给大家详细讲解下每个函数的用途
- 1 /*********************************************************************
- 2 *
- 3 * LCD_L0_SetPixelIndex
- 4 */
- 5 void LCD_L0_SetPixelIndex(int x, int y, int PixelIndex) {
- 6 /* 设定指定点颜色值 */
- 7 }
- 8
- 9 /*********************************************************************
- 10 *
- 11 * LCD_L0_GetPixelIndex
- 12 */
- 13 unsigned int LCD_L0_GetPixelIndex(int x, int y) {
- 14 /* 取得某点像素颜色值,并返回 */
- 15 }
- 16
- 17 /*********************************************************************
- 18 *
- 19 * LCD_L0_XorPixel
- 20 */
- 21 void LCD_L0_XorPixel(int x, int y) {
- 22 /* 反转像素函数 */
- 23 }
- 24
- 25 /*********************************************************************
- 26 *
- 27 * LCD_L0_DrawHLine
- 28 */
- 29 void LCD_L0_DrawHLine(int x0, int y, int x1) {
- 30 /* 绘制水平线函数 */
- 31 }
- 32
- 33 /*********************************************************************
- 34 *
- 35 * LCD_L0_DrawVLine
- 36 */
- 37 void LCD_L0_DrawVLine(int x, int y0, int y1) {
- 38 /* 绘制垂直线函数 */
- 39 }
- 40
- 41 /*********************************************************************
- 42 *
- 43 * LCD_L0_FillRect
- 44 */
- 45 void LCD_L0_FillRect(int x0, int y0, int x1, int y1) {
- 46 /* 填充矩阵函数 */
- 47 }
- 48
- 49 /*********************************************************************
- 50 *
- 51 * LCD_L0_DrawBitmap
- 52 */
- 53 void LCD_L0_DrawBitmap(int x0, int y0,
- 54 int xsize, int ysize,
- 55 int BitsPerPixel,
- 56 int BytesPerLine,
- 57 const U8 GUI_UNI_PTR * pData, int Diff,
- 58 const LCD_PIXELINDEX* pTrans)
- 59 {
- 60 /* 画位图函数 */
- 61 }
- 62
- 63 /*********************************************************************
- 64 *
- 65 * LCD_L0_SetOrg
- 66 */
- 67 void LCD_L0_SetOrg(int x, int y) {
- 68 /* 该函数保留 */
- 69 }
- 70
- 71 /*********************************************************************
- 72 *
- 73 * LCD_On / LCD_Off
- 74 */
- 75 void LCD_On (void) {
- 76 /* 开启LCD */
- 77 }
- 78 void LCD_Off(void) {
- 79 /* 关闭LCD */
- 80 }
- 81
- 82 /*********************************************************************
- 83 *
- 84 * LCD_L0_Init
- 85 */
- 86 int LCD_L0_Init(void) {
- 87 /* LCD初始化 */
- 88 }
- 89
- 90 /*********************************************************************
- 91 *
- 92 * LCD_L0_SetLUTEntry
- 93 */
- 94 void LCD_L0_SetLUTEntry(U8 Pos, LCD_COLOR Color) {
- 95 /* 修改 LCD 控制器的 LUT 的中的单个条目 */
- 96 }
- 97
- 98 #else
- 99
- 100 void LCDNull_c(void);
- 101 void LCDNull_c(void) {} /* 请保持这个函数为空 */
- 102
- 103 #endif
复制代码
移植讲到这边差不多就结束了,因为是凭着自己的感觉写的。
0