摘要:基于的移植教程可以看这里二介绍是一种用于嵌入式应用的图形支持软件。适用于使用任何控制和的任何尺寸的物理和虚拟显示。一个层,称作驱动程序,包含了对的全部访问。并在主函数里加入下面的代码,测试移植是否成功。
keil: 5.25
MCU: STM32F103ZET6
UCGUI版本: 3.90(纯源码版本)
3.9.0是源码版本,可以看到全部源码,也方便学习;后续的版本都是提供lib库文件,不再提供源码了。
基于STM32的STemwin移植教程可以看这里: https://blog.csdn.net/xiaolong1126626497/article/details/117933355https://blog.csdn.net/xiaolong1126626497/article/details/117933355
µC/GUI 是一种用于嵌入式应用的图形支持软件。它被设计用于为任何使用一个图形 LCD的应用提供一个有效的不依赖于处理器和 LCD 控制器的图形用户接口。它能工作于单任务或多任务的系统环境下。 µC/GUI 适用于使用任何 LCD 控制和 CPU 的任何尺寸的物理和虚拟显示。它的设计是模块化的,由在不同的模块中的不同的层组成。一个层,称作 LCD 驱动程序,包含了对 LCD 的全部访问。 µC/GUI 适用于所有的 CPU,因为它 100%由的 ANSI 的 C 语言编写的。
µC/GUI 很适合大多数的使用黑色/白色和彩色 LCD 的应用程序。 它有一个很好的颜色管理器,允许它处理灰阶。 µC/GUI 也提供一个可扩展的 2D 图形库和一个视窗管理器,在使用一个最小的 RAM 时能支持显示窗口。
UCGUI官网地址:Micrium Software and Documentation - Silicon Labs
①.GUI/LCDDriver 文件夹中存放的是一些 LCD 驱动代码,如果你使用的 LCD 在
这里可以找到代码,可以直接通过 Config 中的 LCDConfig.h :
#define LCD_CONTROLLER -1 // -1:表示没有选择的 LCD 驱动,而是使用里边的样本程序进行修改。
uCGUI 中具体支持哪些 LCD 可以查询《uCGUI 用户手册》的第 22 章 LCD 驱动程序。里边详细的说明了,支持些什么控制器的 LCD。
②.在工程中只需加载需要的 LCD 驱动代码文件即可。如果设置为-1,则选择加载 LCDDummy.C 或 LCDTemplate.C 文件(不同的版本,此代码的文件名可能会不同)。
文件夹的主要内容如下:
Config ----------- 配置文件
GUI ----------- 源代码
GUI_X ---------- 操作系统接口函数定义文件
GUI 源代码文件:
1) AntiAlias: 抗锯齿显示效果支持。
2) ConvertColor: 彩色显示的色彩转换支持。
3) ConvertMono: (b/w)和灰度显示的色彩转换支持。
4) Core: 核心文件,提供了GUI基本的功能。
5) Font: 字库。
6) JPEG: 图片操作函数。
7) LCDDriver: LCD驱动支持。
8) MemDev: 内存设备支持。主要功能是防止在项目重叠时触摸屏的闪烁。
9) Widget: 窗体控件库。
10) WM: 窗口管理库。
注意:JPEG、MemDev、Widget、WM是可裁剪项,若要支持Widget(窗体控件),需要
WM(窗口管理器)的支持;使用控件时,需要将相应的头文件包含进去,比如我们需要使用按钮BUTTON,那么我们需要先包含BUTTON.h头文件,否则控件即使支持也不可用。
移植准备工作:
首先在KEIL工程目录下创建一个UCGUI的文件夹,用来存放移植需要用到的源码文件。
效果图:
将GUI_V3.9_官方源码/uCGUI3.90版源码/Start路径下的Config文件夹和GUI文件拷贝到刚才在KEIL工程目录下创建的UCGUI文件夹里。
效果图:
将GUI_V3.9_官方源码/uCGUI3.90版源码/Sample路径下的GUI_X文件夹拷贝到刚才在KEIL工程目录下创建的UCGUI文件夹里。(GUI_X文件夹是操作系统的接口)
效果图:
打开KEIL工程,添加UCGUI源代码。
根据 UCGUI/GUI 目录下的文件创建KEIL的工程目录,名字最好用源码默认的名字不要修改,以防止后面查找不方便。额外再添加创建一个UCGUI_Config目录,用来存放UCGUI的配置文件创建好的工程目录—效果图:
工程创建OK之后,将对应源文件添加到KEIL工程目录下,将对应的头文件加入工程。
效果图:
添加的源文件和头文件需要对照GUI文件夹逐个添加,不能漏掉文件。
源文件只添加.c 。其他文件一律不添加。
UCGUI_Config文件夹添加的文件如下所示:
UCGUI/GUI_X/GUI_X.c //OS系统接口UCGUI/Config/GUITouchConf.h //配置触摸屏UCGUI/Config/ GUIConf.h //配置GUIUCGUI/Config/ LCDConf.h //配置LCD显示屏参数
效果图:
修改LCD配置文件,打开LCDConf.h文件,替换下面的代码:
#ifndef LCDCONF_H#define 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) /*lcd 颜色深度*/#define LCD_CONTROLLER (-1) /*lcd 控制器的具体型号*/#define LCD_FIXEDPALETTE (565) /*RGB 颜色位数*/#define LCD_SWAP_RB (1) /*红蓝反色交换*/#define LCD_INIT_CONTROLLER() LCD9341_Init (); /*底层初始化函数,自己写的,而非源码自带,这一步非常重要*/#endif /* LCDCONF_H */
因为我们有LCD的驱动,不需要UCGUI的LCD驱动配置。
其中:LCD9341_Init (); 函数是我们自己工程的LCD初始化函数。我们的LCD初始化函数名字不能是LCD_Init(),因为UCGUI自带的LCD初始化函数也是这个名字,我们自己的工程里也不能出现LCD名字的结构体。不然,会出现重定义的错误。
修改UCGUI配置文件,打开GUIConf.h文件,修改成下面的代码:
#ifndef GUICONF_H#define GUICONF_H#define GUI_OS (0) /* 系统支持 */#define GUI_SUPPORT_TOUCH (0) /* 支持触摸屏 */#define GUI_SUPPORT_UNICODE (0) /* 支持混合ASCII / UNICODE字符串 */#define GUI_DEFAULT_FONT &GUI_Font6x8//#define GUI_ALLOC_SIZE 12500 /* Size of dynamic memory ... For WM and memory devices*/#define GUI_ALLOC_SIZE 1024*1024 /* Size of dynamic memory ... For WM and memory devices*/#define GUI_WINSUPPORT 0 /* 窗口管理器包可用 */#define GUI_SUPPORT_MEMDEV 0 /* 内存设备可用 */#define GUI_SUPPORT_AA 0 /* 抗锯齿可用 */#endif /* Avoid multiple inclusion */
初次移植,将不需要用到的配置全部关闭,等UCGU的基本操作熟悉之后再打开使用。
打开LCDDummy.c文件,添加UCGUI底层的画点函数和读点函数。
先在LCDDummy.c里加入LCD头文件。并且定义使用自己的LCD驱动。
添加画点函数
该函数在LCDDummy.c文件(大约382行)处。
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 */ { LCD_DrawPoint_color(x,y,PixelIndex); //添加画点函数 }}
添加读点函数
该函数在LCDDummy.c文件(大约407行)处。
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=LCD_ReadPoint(x,y); //添加读点函数 } return PixelIndex;}
文件修改完毕之后,回到主函数,添加#include "GUI.h"头文件。
并在主函数里加入下面的代码,测试GUI移植是否成功。
GUI_Init(); //GUI初始化GUI_SetBkColor(GUI_BLUE); //设置颜色GUI_Clear(); //清屏GUI_GotoXY(60,50); //设置字符显示的XY坐标GUI_DispString("Hello World!!"); //显示字符GUI_DrawCircle(100,200,50); //画圆
代码写完,编译工程,编译时间1-10分钟左右(电脑性能决定)。
效果图:
编译成功之后,将代码下载到开发板运行。
效果如图:
如果编译出现下面的错误:
../OBJ/KEY.axf: Error: L6218E: Undefined symbol exit (referred from jerror.o).
根据错误提示,打开jerror.c文件,找到error_exit函数,将该函数的最后一行代码exit(EXIT_FAILURE); 该为return 。改完,再次编译,错误解决。
效果图:
方法:
一般解决了上述的问题,移植一般都没有问题。出现了问题,可以查看错误信息,判断是什么错误,针对性解决。
加入触摸屏功能之前,要保证原本工程已经有正常的触摸屏驱动代码,能正确的转换触摸屏的X Y坐标值。
#define GUI_SUPPORT_TOUCH (1) /* 支持触摸屏 */#define GUI_ALLOC_SIZE 5000 //修改内存空间改大一点,防止编译不过
效果图:
#ifndef GUITOUCH_CONF_H#define GUITOUCH_CONF_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 //设置镜像X#define GUI_TOUCH_MIRROR_Y 0 //设置镜像Y#endif /* GUITOUCH_CONF_H */
效果图:
GUI_X_Touch.c在UCGUI/GUI_X路径下。
并修改获取X Y 坐标代码,加入触摸屏驱动头文件。
修改代码如下:
#include "GUI.h"#include "GUI_X.h"#include "touch.h" //头文件void GUI_TOUCH_X_ActivateX(void) {}void GUI_TOUCH_X_ActivateY(void) {}int GUI_TOUCH_X_MeasureX(void) { //添加获取触摸X坐标代码 Touch_check(); //扫描触摸屏 return TOUCH.x; //X坐标}int GUI_TOUCH_X_MeasureY(void) {//添加获取触摸Y坐标代码 Touch_check(); //扫描触摸屏 return TOUCH.y; //Y坐标}
效果图:
上边步骤完成之后,在主函数添加(自己工程的)触摸屏的初始化函数,触摸屏即可正常运行。
如果GUI没有加入系统,需要定义一个定时器去扫描触摸屏,在定时器的中断服务函数里加入GUI_TOUCH_Exec();函数。扫描的频率为:10毫秒一次
如果GUI加入了系统,可以创建一个多带带的任务,在任务里添加GUI_TOUCH_Exec();
本小节的的移植是基于UCOSII系统的移植
移植系统之前的准备工作:
打开GUIConf.h文件,修改当前GUI支持系统
#define GUI_OS (1) /* 系统支持 */
效果图:
添加相关头文件路径效果图:
效果图:
注意:加载源码的时候,不能将ucos_ii.c加入到工程。加入了ucos_ii.c文件会出现重定义。
”ucos_ii.c的代码作用是加载源文件,因为UCOSII其他源文件我们已手动加入到工程,已不需要ucos_ii.c的代码”。
初始化滴答时钟,开启滴答时钟中断,设置滴答时钟10毫秒中断一次。
(用任何一个硬件定时器都可以代替)
在滴答时钟中断服务函数里加入下面的代码:
(记得在滴答定时器中断函数的代码文件里引用UCOSII的头文件:#include "includes.h" )
/*滴答时钟中断服务函数*/void SysTick_Handler(void){ OSIntEnter(); //进入中断 OSTimeTick(); //调用ucos的时钟服务程序 OSIntExit(); //触发任务切换软中断}
效果图:
在进行上边的步骤,之后,编译工程,会出现如下的错误:
Build target "UCGUI移植"linking...../OBJ/KEY.axf: Error: L6218E: Undefined symbol GUI_X_GetTaskId (referred from guitask.o).../OBJ/KEY.axf: Error: L6218E: Undefined symbol GUI_X_InitOS (referred from guitask.o).../OBJ/KEY.axf: Error: L6218E: Undefined symbol GUI_X_Lock (referred from guitask.o).../OBJ/KEY.axf: Error: L6218E: Undefined symbol GUI_X_Unlock (referred from guitask.o).Not enough information to list image symbols.Finished: 1 information, 0 warning and 4 error messages."../OBJ/KEY.axf" - 4 Error(s), 0 Warning(s).Target not created
根据报错提示信息,打开GUITask.c 文件。GUITask.c有提示需要在GUI_X.c文件实现几个函数。
根据提示,继续打开GUI_X.C 。前边有提到,GUI_X.C文件主要是提供OS系统接口,配置/系统相关的外部环境。
效果图:
我们当前移植的OS是UCOSII系统,打开KEIL工程路径下的GUI_X文件夹:
效果图:
该目录下有6个与系统接口相关的文件,我们移植的是UCOS系统,其中GUI_X_uCOS.c文件是UCOSII系统的接口。我们将GUI_X_uCOS.c文件加入到工程
效果图:
将GUI_X.C文件的三个底层函数拷贝一份到GUI_X_uCOS.c文件
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); }
效果图:
完成上面的步骤之后,将GUI_X.c文件从工程中卸载掉,因为GUI_X_uCOS.c与GUI_X.c文件实现的函数有很多是相同的,不卸载GUI_X.c会出现重定义的错误。
接着修改GUI_X_uCOS.c文件,替换UCOS的延时函数。(大约在78行)。
void GUI_X_ExecIdle (void) { //OS_X_Delay(1); OSTimeDly(50); //UCOS延时函数}
效果图:
//开始任务void start_task(void *pdata){ OS_CPU_SR cpu_sr=0; pdata = pdata; OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断) OSTaskCreate(led0_task,(void *)0,(OS_STK*)&LED0_TASK_STK[LED0_STK_SIZE-1],LED0_TASK_PRIO); //创建的任务 OSTaskCreate(led1_task,(void *)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO); OSTaskSuspend(START_TASK_PRIO); //挂起起始任务. OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断)}//LED0任务void led0_task(void *pdata){ u8 i; u16 cnt=0; /*************************************** 画一个进度条控件 ****************************************/ hProgBar_1 = PROGBAR_Create(0, 0, 240, 40, WM_CF_SHOW); //设置进度条的大小坐标参数 PROGBAR_SetBarColor(hProgBar_1,0,GUI_GREEN); //参数(句柄,1(0)代表本函数是显示进度条覆盖的区域还未覆盖的区域,进度条覆盖的颜色) PROGBAR_SetBarColor(hProgBar_1,1,GUI_RED); //参数(句柄,1(0)代表本函数是显示进度条覆盖的区域还未覆盖的区域,进度条未覆盖的颜色) PROGBAR_SetValue(hProgBar_1,99); //参数(句柄 ,99是进度条显示的99%) while(1) { i=!i; LED2(i); LED3(i); PROGBAR_SetValue(hProgBar_1,cnt); //显示进度条1控件 的进度 OSTimeDlyHMSM(0,0,1,0); //将一个任务延时若干时间(设定时、 分、 秒、 毫秒) WM_Exec(); cnt++; if(cnt>=100) { cnt=0; } }}//LED1任务void led1_task(void *pdata){ u8 i; u16 cnt; hProgBar_2 = PROGBAR_Create(0, 80, 240, 40, WM_CF_SHOW); //设置进度条的大小坐标参数 PROGBAR_SetBarColor(hProgBar_2,0,GUI_GREEN); //参数(句柄,1(0)代表本函数是显示进度条覆盖的区域还未覆盖的区域,进度条覆盖的颜色) PROGBAR_SetBarColor(hProgBar_2,1,GUI_RED); //参数(句柄,1(0)代表本函数是显示进度条覆盖的区域还未覆盖的区域,进度条未覆盖的颜色) while(1) { //GUIDEMO_main(); //运行DEMO代码 i=!i; LED1(i); LED4(i); PROGBAR_SetValue(hProgBar_2,cnt); //显示进度条2控件 的进度 WM_Exec(); //显示生效 OSTimeDlyHMSM(0,0,0,500); //将一个任务延时若干时间(设定时、 分、 秒、 毫秒) cnt++; if(cnt>=100) { cnt=0; } }}
效果图:
将DEMO文件全部加入工程编译,最后运行DEMO代码。
//LED0任务void led0_task(void *pdata){ u8 i; while(1) { i=!i; LED2(i); LED3(i); GUI_TOUCH_Exec(); //监视和刷新触摸板 OSTimeDlyHMSM(0,0,0,10); //将一个任务延时若干时间(设定时、 分、 秒、 毫秒) }}//LED1任务void led1_task(void *pdata){ u8 i; while(1) { GUIDEMO_main(); //运行DEMO代码 i=!i; LED1(i); LED4(i); OSTimeDlyHMSM(0,0,0,10); //将一个任务延时若干时间(设定时、 分、 秒、 毫秒) }}
系统时间计算
如果跑UCOS系统可以设置UCOS工作频率高一些: #define OS_TICKS_PER_SEC 1000 //一秒的节拍时间。
节拍时间计算方式:滴答时钟中断时间 * 节拍次数 = 1秒
函数原型 | GUI_Init(); |
函数功能 | 初始化GUI的内部数据结构和变量,使用GUI任何功能之前必须调用本函数 |
函数参数 | |
返回值 |
函数原型 | GUI_GotoXY(int x, int y) |
函数功能 | 设置当前的XY坐标 |
函数参数 | X :横坐标 Y:纵坐标 |
返回值 | 成功返回0 |
相关函数 | GUI_GotoX() 设置当前X坐标 GUI_GotoY() 设置当前Y坐标 |
函数原型 | void GUI_SetBkColor(GUI_COLOR color) |
函数功能 | 设置LCD背景颜色 |
函数参数 | Color:颜色值 |
返回值 | 无 |
函数原型 | void GUI_SetColor(GUI_COLOR color) |
函数功能 | 设置LCD前景颜色 |
函数参数 | Color:颜色值 |
返回值 | 无 |
所属文件 | GUI_SetColor.c |
函数原型 | void GUI_DispString(const char GUI_UNI_PTR *s) |
函数功能 | 在当前坐标显示文本-字符串 |
函数参数 | *s :字符串指针 |
返回值 | 无 |
所属文件 | GUI_DispString.C |
示例:
GUI_DispString("Hello World!!"); //显示字符串 |
函数原型 | void GUI_DispStringAt(const char GUI_UNI_PTR *s, int x, int y) |
函数功能 | 在指定坐标显示文本-字符串 |
函数参数 | *s :字符串指针 X:横坐标 Y:纵坐标 |
返回值 | 无 |
所属文件 | GUI_DispStringAt.c |
示例:
GUI_DispStringAt("Hello World!!",0,100); //显示字符串 |
函 数 | 说 明 |
GUI_DispChar() | 在当前坐标显示单个字符 |
GUI_DispCharAt() | 在指定坐标显示单个字符 |
GUI_DispChars() | 按指定重复次数显示一个字符 |
GUI_DispChars() | 在当前坐标显示字符串 |
GUI_DispStringAt() | 在指定坐标显示字符串 |
GUI_DispStringAtCEOL() | 在指定坐标显示字符串,并清除到行末 |
GUI_DispStringInRect() | 在指定矩形区域内显示字符串 |
GUI_DispStringLen() | 在当前坐标显示指定字符数量的字符串 |
函数 | 功能 |
GUI_SetTextMode(); | 设置文本绘图模式 |
函数 | 功能 |
GUI_GetTextAlign() | 返回当前文本对齐模式 |
GUI_SetLBorder() | 设置换行后的左边界 |
GUI_ SetTextAlign() | 设置文本对齐模式 |
函数 | 功能 |
GUI_GotoX() | 设置当前X坐标 |
GUI_GotoXY() | 设置当前YX坐标 |
GUI_GotoY() | 设置当前Y坐标 |
函数 | 功能 |
GUI_GetDispPosX() | 返回当前X坐标 |
GUI_GetDispPosY() | 返回当前Y坐标 |
函数 | 功能 |
GUI_Clear() | 清除活动视窗(如果背景是活动视窗,则是清除整个屏幕) |
GUI_DispCEOL() | 清除从当前坐标到行末的显示内容 |
默认情形下,存储设备是被激活的。为了优化软件的性能,对存储设备的支持可以在配
置文件 GUIConf.h 中加入下面一行而关闭:
#define GUI_SUPPORT_MEMDEV 0
要是使用时,需要将宏开关打开:
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/120933.html
摘要:基于开发的软件包导师汪礼超学员崔林威摘要腾讯物联网操作系统是腾讯面向物联网领域开发的实时操作系统,具有低功耗,低资源占用,模块化,可裁剪等特性。图中断函数处理进行生成工程配置,按如下界面进行配置,最后点击,并点击。 ...
摘要:力矩控制模式电机在运行过程的电流,始终等于给定的值。设定电流为零,弹簧不被拉伸。比如机械臂从点运动到点,并限制挥舞过程中的最大速度和最大力矩。 目录 说明一、电机...
摘要:添加设备名和鉴权信息。记录如下数据二引脚连接和接电源接地和连接至配置的串口三代码编写串口配置单片机需配置两个串口,串口打印至串口助手,显示连接状态。串口用来发送信息至串口配置代码如下系列配置和系列配置不同点在于口上拉和推挽配置略有不同。 ...
摘要:已初始化的读写数据,程序中定义并且初始化的全局变量和静态变量位于此处。好了,初步移植要点讲完了,下一篇文章讲内核配置文件函数启动后如何进入鸿蒙轻量内核。 9月30日,OpenHarmony 3.0 LTS版本发布,新版介绍见OpenHarmony 3.0 发布:OpenHarmony 3.0...
摘要:大信刷抖音时,偶然蹦出了联盛德物联开发板这个广告。板子做的很精致,毫米厚的板子,平滑的板边缘,亮紫色和镀金的过孔透露着高档品质,同时收到售后支持的加好友,在售后支持指导下加入了联盛德官方的开发群里,开始了开发测试工作。 ...
阅读 2327·2021-11-22 14:56
阅读 1459·2021-09-24 09:47
阅读 903·2019-08-26 18:37
阅读 2817·2019-08-26 12:10
阅读 1521·2019-08-26 11:55
阅读 3138·2019-08-23 18:07
阅读 2293·2019-08-23 14:08
阅读 603·2019-08-23 12:12