UCGUI添加外置字库到SD卡(附字库) http://www.openedv.com/posts/list/0/21784.htm 一步步解决UCGUI汉字字库 http://www.eepw.com.cn/article/182405.htm Ucgui汉字库的建立方法 引用网址:http://blog.sina.com.cn/s/blog_724d24bf0100vmgp.html
网址:http://www.openedv.com/posts/list/0/22436.htm Ucgui汉字库的建立方法 1. ucgui包括两种字体:①等宽字体:所有字体中的字都是相同的宽度,不能对哪一个字体单独设置一种宽度,在ucgui中的结构体是GUI_FONT_MONO;②均衡字体:字体中的字都有独立的宽度,字体中的每一个字都有一个单独的宽度,可以为每个字单独设定字体,它在UCGUI上的结构体是GUI_FONT_PROC; 2. ucgui中的等宽字体都是存储在一个数组中,由于每一个字体中的字都是相同的宽度,因此都存储在同一个数组中;但是对于均衡字体来说,由于字体中的每一个都是不同的字体因此每一个字单独存储在一个数组中,然后将每一个字符的宽高及字的点阵存为一个数组即字符信息,ucgui中字符信息的结构体是GUI_CHARINFO,所有的字符信息再存储在一个数组之中,成为字符集,包含每一个字符的信息(宽高及点阵); 3. 在等宽字体中,不仅所有的字符宽度相同,高度也是相同的,但是对于均衡字体来说,宽高都是可以不同的; 4. 在UCGUI中每种字体含的字符集不同,ucgui中有一节专门对ucgui的字体作了介绍; 5. 程序中直接输入汉字的实现,即在编程中将要显示在LCD的汉字直接在程序中写出。在UCGUI中介绍的用unicode编码进行输入的方法相当的繁琐,当需要输出入的汉字量非常大的时候,这个问题就更加的突出。经过分析ucgui的内核知道,程序中输入的unicode码其实就是字库中GUI_FONT_PROP定义的该字映像地址,在程序中直接输入字母后计算机获得的是汉字内码,所以只要将GUI_FONT_PROP中的映像地址改为字母的内码就行了,对于英文字母就是ASCII编码,而汉字就是汉字内码,下面简单介绍常用的16点阵汉字的编码: 在UC/GUI中F16_1hk.c文件中定义的GUI_FONT_PROP结构体对象,通过注释了解映像地址和字模数据存储地址的对应的关系。 GUI_FLASH const GUI_FONT_PROP GUI_Font16_1HK_Prop1 = { 0x3041, 0x3093, &GUI_Font16HK_CharInfo\[\0], (void GUI_FLASH*)&GUI_Font16_1HK_Prop2 }; 6. 建立汉字字库 在UC/GUI中动态地读取字模是无法实现的,即当程序运行时动态地从汉字库中读取所需要的字母的字模,因此只有把所有一级常用汉字的字模全部取出,按照UC/GUI中字库创建的标准去创建新的字库就可以了。下面以在F16_HZ_LEI.C中创建字体GUI_Font6_HZ为例来说明具体的步骤。 第一:声明全局字体结构体对象GUI_Font16_HZ,该声明必须在GUI.H文件中加以说明, extern const GUI_FONT GUI_Font16_HZ ; 第二:定义一个用于存放字模数据的数组。 GUI_FLASH const unsigned char acFont16HZSong_16_0001 = [……] (当然这样的定义就是我们之前所说的均衡字体的定义,每一个字符的点阵存于一个数组中) 第三:定义一个GUI_CHARINFO的结构体对象数组,用于说明每个字母的字模数据在程序段存储的方式。 GUI_FLASH const GUI_CHARINFO GUI_Font16_HZ_CharInfo/[3760\] = {{16,16,2,(void GUI_FLASH*)&acFont16HZ\[\0],……,16,16,2,(voidGUI_FLASH*)&acFont16HZ\[3759\]},} ; 第四:按汉字内码的高位来定义多个结构体GUI_FONT_Prop0={0xb0a1,0xb0fe,&GUI_Font_HZ_CharInfo\[0\],(void GUI_FLASH*)&GUI_Font_HZ_Prop1}; 第五:把创建的汉字库文件F16_HZ_LEI.C添加到UC/GUI的工程中,通过以下语句实现在LCD上显示汉字:GUI_SetFont(&GUI_Font16_HZ); GUI_DispStringAt(GUI_UC_START “西安邮电学院” GUI_UC_END,11,11); 7.通常情况下我们所使用的开发板的存储器都较小,并且我们在一篇文章中不可能使用所有的十六点阵或者十二点阵包含的所有汉字,那么此时我们就需要从这些点阵中挑选出我们需要使用的汉字。这种情况下汉字的机内码存储就不是连续的,有些时候下可能得为单独的一个汉字建立一个GUI_FONT_PROP结构,然后再将它们链成链表,这样做就可以直接使用以下两种方法: 比如我们此刻要在LCD上显示“世界你好”: 方法一、const unsigned char helloworld[] = "世界你好"; GUI_DispString((const char*)helloworld); 此时是编译器将汉字转换为机内码 方法二、 const unsigned char helloworld[]={0xca, 0xc0, 0xbd, 0xe7, 0xc4, 0xe3, 0xba, 0xc3, 0x00}; GUI_DispString((const char*)helloworld); 此时编译器利用数组中存储的汉字的机内码找到相应的汉字输出至LCD上。 如上两种比较, 结果是一样的,唯一不同的是, 第一种方法显示汉字时, 无须使用知道汉字的机内码, 而是由编译器来转换的, 但我要说的是, 其实两者本质是一样的, 只是对使用者来说有表面上的不同.比较以上的两种显示汉字时构造字符串的方法, 我们可以得到一个启示, 对于第二种, 我们可以采取自定义汉字机内码, 然后直接通过自定义机内码来显示汉字, 这一点我已经在"建立自定义小型汉字库说明"一文当中说明了, 现在我想说的是对于采用第一种方法显示汉字的建立自定义小型字库的方法。 #include "GUI.H" #ifndef GUI_FLASH #define GUI_FLASH #endif extern GUI_FLASH const GUI_FONT GUI_FontHZ12; //世 GUI_FLASH const unsigned char acFontHZ12_cac0[24] = { 0x04,0x40, 0x24,0x40, 0x24,0x40, 0x24,0x40, 0xff,0xf0, 0x24,0x40, 0x24,0x40, 0x24,0x40, 0x27,0xc0, 0x24,0x40, 0x20,0x00, 0x3f,0xf0 }; //界 GUI_FLASH const unsigned char acFontHZ12_bde7[24] = { 0x3f,0xc0, 0x24,0x40, 0x3f,0xc0, 0x24,0x40, 0x3f,0xc0, 0x04,0x00, 0x0b,0x00, 0x38,0xf0, 0xc9,0x20, 0x09,0x00, 0x11,0x00, 0x61,0x00 }; //你 GUI_FLASH const unsigned char acFontHZ12_c4e3[24] = { 0x12,0x00, 0x12,0x00, 0x27,0xf0, 0x24,0x20, 0x69,0x40, 0xa1,0x00, 0x25,0x40, 0x25,0x20, 0x29,0x10, 0x31,0x10, 0x25,0x00, 0x22,0x00 }; //好 GUI_FLASH const unsigned char acFontHZ12_bac3[24] = { 0x20,0x00, 0x27,0xe0, 0x20,0x40, 0xf8,0x80, 0x48,0x80, 0x48,0xa0, 0x57,0xf0, 0x50,0x80, 0x30,0x80, 0x28,0x80, 0x4a,0x80, 0x81,0x00 }; GUI_FLASH const GUI_CHARINFO GUI_FontHZ12_CharInfo[4] = { { 12, 12, 2, (void GUI_FLASH *)&acFontHZ12_cac0 }, { 12, 12, 2, (void GUI_FLASH *)&acFontHZ12_bde7 }, { 12, 12, 2, (void GUI_FLASH *)&acFontHZ12_c4e3 }, { 12, 12, 2, (void GUI_FLASH *)&acFontHZ12_bac3 } }; GUI_FLASH const GUI_FONT_PROP GUI_FontHZ12_Propa4= { 0xbac3, 0xbac4, &GUI_FontHZ12_CharInfo[3], 0 }; GUI_FLASH const GUI_FONT_PROP GUI_FontHZ12_Propa3= { 0xc4e3, 0xc4e4, &GUI_FontHZ12_CharInfo[2], (void *)&GUI_FontHZ12_Propa4 }; GUI_FLASH const GUI_FONT_PROP GUI_FontHZ12_Propa2= { 0xbde7, 0xbde8, &GUI_FontHZ12_CharInfo[1], (void *)&GUI_FontHZ12_Propa3 }; GUI_FLASH const GUI_FONT_PROP GUI_FontHZ12_Propa1= { 0xcac0, //在GUI_CHARINFO结构中定义的数组中的对应起始地址cac0 0xcac1, //在GUI_CHARINFO结构中定义的数组中的对应结束地址 &GUI_FontHZ12_CharInfo[0], //在GUI_CHARINFO结构中定义的数组的位置从0开始 (void *)&GUI_FontHZ12_Propa2 //下一数组的索引地址 }; GUI_FLASH const GUI_FONT GUI_FontHZ12 = { GUI_FONTTYPE_PROP_SJIS, 12, 12, 1, 1, (void GUI_FLASH *)&GUI_FontHZ12_Propa1 //下一数组的索引地址 }; 结语:在上述过程中介绍了LCD上汉字的显示方法,已经成功建立了12点阵和16点阵的汉字库。 移植UCGUI时,调用GUI_Delay();的解决办法! 最近在学习UCGUI一段时间了,终于成功移植了UCGUI里面的大部分源码,感觉移植代码量还是比较大的,不过倒是GUI_Delay();对于很多菜鸟可能会搞不懂,下面就说一下关于按照原子论坛里的教程成功移植UCGUI3.90后,会发现GUI_Delay();这个函数一调用程序就会卡在这个函数里面,修改一下底层函数,即使没加入操作系统,只移植了UCGUI也可以调用GUI_Delay(); 解析GUI_Delay()函数: 使用GUI_Delay()函数时,对于其延时时间不确定,明明设置为最小值1,延时时间仍旧太长,不能达到需求。遂决定研究明白其实现机理。 第一使用操作系统uc/os时: uC/OS-II使用OSTimeDly()函数实现延时,其单位是OS_TICKS,即延时多少个系统节拍。GUI使用GUI_Delay()函数延时,同时也实现显示刷新;基于同一个平台,估计也会调用OSTimeDly()函数以实现基本的延时功能。 下面分析GUI_Delay()函数功能 void GUI_Delay(int Period) { int EndTime = GUI_GetTime()+Period; int tRem; /* remaining Time */ GUI_ASSERT_NO_LOCK(); while (tRem = EndTime- GUI_GetTime(), tRem>0) { GUI_Exec(); GUI_X_Delay((tRem >5) ? 5 : tRem); } } 首先EndTime变量获得延时结束时间; 使用一个while循环,在结束时间之前循环调用GUI_Exec()函数和GUI_X_Delay()函数; 前者是GUI的刷新函数,保证在延时过程中不会停止GUI任务处理。后者就是我们要分析的延时函数GUI_X_Delay了。 参数用三目变量,每次送给延时的参数最大是5; 跟踪GUI_X_Delay()函数,在GUI_X_uCOS.C文件中实现。 void GUI_X_Delay (int period) { INT32U ticks; ticks = (period * 1000) / OS_TICKS_PER_SEC; OSTimeDly((INT16U)ticks); } 可以看到,在GUI_X_Delay()函数中调用了系统延时函数OSTimeDly(),就像前面我们说过的,OSTimeDly()函数的延时时间是系统节拍,如果要改变GUI_Delay()函数的延时时间,就需要从此着手。 再看看延时时间的取值:OS_TICKS_PER_SEC在OS_CFG.H中设置为100,即每秒产生100个系统节拍。ticks变量在这里被扩展了10倍。即GUI_Delay()函数传递一个延时参数1,而实际的延时时间就是10个节拍即100毫秒。在这个延时时间之内,调用GUI_Delay()函数的任务就不能执行,使得响应速度慢。为保持源程序的风格一致,这里改period的倍数为100,使GUI_Delay()函数的延时时间和OSTimeDly()函数时间单位一致,提高了响应速度增强其易用性。 第二,只移植了UCGUI时;也可以使用GUI_Delay();延时函数,不过要修改相关的底层函数: 按照网上的教程成功移植UCGUI3.90后,会发现GUI_Delay();这个函数一调用程序就会卡在这个函数里面, 找到:c文件: GUI_X.C ********************************************************************************************************* * uC/GUI * Universal graphic software for embedded applications * * (c) Copyright 2002, Micrium Inc., Weston, FL * (c) Copyright 2002, SEGGER Microcontroller Systeme GmbH * * 礐/GUI is protected by international copyright laws. Knowledge of the * source code may not be used to write a similar product. This file may * only be used in accordance with a license and should not be redistributed * in any way. We appreciate your understanding and fairness. * ---------------------------------------------------------------------- File : GUI_X.C Purpose : Config / System dependent externals for GUI ---------------------------END-OF-HEADER------------------------------ */ #include "GUI.h" #include "GUI_X.h" /********************************************************************* * * Global data */ volatile int OS_TimeMS; /********************************************************************* * * Timing: * GUI_X_GetTime() * GUI_X_Delay(int) Some timing dependent routines require a GetTime and delay function. Default time unit (tick), normally is 1 ms. */ int GUI_X_GetTime(void) { return OS_TimeMS; } void GUI_X_Delay(int ms) { int tEnd = OS_TimeMS + ms; while ((tEnd - OS_TimeMS) > 0); } /********************************************************************* * * GUI_X_Init() * * Note: * GUI_X_Init() is called from GUI_Init is a possibility to init * some hardware which needs to be up and running before the GUI. * If not required, leave this routine blank. */ void GUI_X_Init(void) {} /********************************************************************* * * GUI_X_ExecIdle * * Note: * Called if WM is in idle state */ void GUI_X_ExecIdle(void) {} /********************************************************************* * * Logging: OS dependent Note: Logging is used in higher debug levels only. The typical target build does not use logging and does therefor not require any of the logging routines below. For a release build without logging the routines below may be eliminated to save some space. (If the linker is not function aware and eliminates unreferenced functions automatically) 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); } 修改volatile int OS_TimeMS; 可以使用STM32的系统嘀嗒定时器systick();设置好作为GUI_Delay()的时钟节拍,然后让滴答定时器作为volatile int OS_TimeMS;的时钟,就可以调UCGU的延时函数了。 或者直接调用原子哥delay_ms();加入到GUI_Delay()也可以延时的。 |