教程不断更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429
第28章 emWin6.x的C文件格式的汉字生成和实现(Unicode编码)
本章节主要为大家讲解官方的字体生成软件FontCvt的使用方法,使用此软件可以生成C文件格式的汉字全字库,也可以生成C文件格式的小字库,所谓小字库就是需要显示什么汉字就仅生成这些汉字。
FontCvt全称Font Converter。
28.1 初学者重要提示
28.2 使用FontCvt生成字库C文件的方法
28.3 C文件格式汉字的使用方法
28..4生成的是Unicode编码字体,而使用时为什么是UTF-8
28.5 MDK4.X,MDK5.X和IAR的UTF-8编码问题
28.6 实验例程说明(RTOS)
28.7 实验例程说明(裸机)
28.8 总结
28.1 初学者重要提示
1、 emWin官方提供的字体生成软件FontCvt不支持GB编码,所以只能使用FontCvt支持的Unicode编码。
2、 字体小工具需要使用此贴提供的,其它大部分是Demo版本:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=107218 。
3、 教程中让大家将要显示汉字的C文件转换为UTF-8编码,指的是将这个汉字所在的C文件转换为UTF-8编码,这点要切记,详情请看28.4小节的说明。
另外特别注意MDK5编译错误missing closing quote,解决办法看本章教程第28.6.2小节。
4、 FontCvt的使用方法在emWin手册中有讲解,这个只有英文版手册进行了详细说明:
28.2 使用FontCvt生成C文件格式小字库的方法
所谓小字库就是需要显示什么汉字就仅生成什么汉字,下面为大家讲解如何生成C文件格式的小字库。这里以生成“安富莱电子”五个字为例进行说明。
- 第1步:在电脑桌面右击鼠标->新建->文本文档,即新建一个txt文本。
创建了文本文档后,输入“安富莱电子”五个字:
然后点击菜单选项文件->另存为:
弹出如下窗口:
(注:Win10选择的是UTF-16 LE)
此时桌面上就会生成一个名字为FontSong16的文本文档。
- 第2步:打开字体生成软件FontCvt,选择字体类型Standard,编码选择16bit Unicode
点击OK后,弹出如下窗口:
再点击确定后弹出FontCvt界面变成如下效果:
- 第3步:点击EDIT->Disable all characters
禁止所有字符后,字符区就全部变成灰色的了:
- 第4步:点击Edit->Read pattern file
- 第5步:加载文件FontSong16.txt
点击打开后,FontCvt软件的字符显示区中“安富莱电子”五个字的背景已经变成白色,下面是其中一个“莱”字的显示效果:
- 第6步:最后一步,点击File->Save As
弹出如下窗口:
至此就生成了我们所需要的16点阵字体。以同样的方法,我们再以此生成以下几种字体:
1. 字体类型Standard,16bit Unicode编码,32点阵,宋体,生成的文件名为FontSong32.c。
2. 字体类型Standard,16bit Unicode编码,72点阵,宋体,生成的文件名为FontSong72.c。
3. 字体类型Standard,16bit Unicode编码,144点阵,宋体,生成的文件名为FontSong144.c。
4. 字体类型Antialiased 4bpp(4倍抗锯齿),16bit Unicode编码,144点阵,宋体,生成的文件名为FontSongA144.c。
5. 字体类型Extended framed(扩展模式,带边框),16bit Unicode编码,144点阵,宋体,生成的文件名为FontSongExF144.c。
6. 字体类型Extended antialiased 4bpp(扩展模式,4倍抗锯齿),16bit Unicode编码,144点阵,宋体,生成的文件名为FontSongExA144.c。
通过小软件FontCvt,共生成了7种字体文件:
有了这几个文件就可以进行相应字体的汉字显示了,由于仅生成了“安富莱电子”这五个字,所以仅支持这五个字的显示。接下来讲解这7种字体文件如何使用。
28.3 使用FontCvt生成C文件格式全字库的方法
由于FontCvt生成C文件格式的全字库比较大,放在内部Flash非常占空间,所以基本不使用,不过生成方法要简单说明下。
- 第1步:打开字体生成软件FontCvt,选择字体类型Standard,编码选择16bit Unicode
点击OK后,弹出如下窗口:
再点击确定后弹出FontCvt界面变成如下效果:
- 第2步:点击File->Save As
弹出如下窗口:
此时,桌面上就生成了一个名为FontSong16.c的文件,实际在MDK工程中测试,此文件要占用1147060字节,即1MB多,所以实际项目中不推荐。
28.4 C文件格式汉字的使用方法
下面讲解28.2小节生成的7种字体C文件的使用方法,这里将MDK和IAR分别进行说明:
28.4.1 MDK编译器中使用C文件格式汉字的方法
- 第1步:将生成的7种字体文件添加到MDK工程目录里面,本章节配套的例子是将其放在User->fonts文件夹下
- 第2步:将生成的7种字体文件添加到MDK工程中
- 第3步:调用函数GUI_UC_SetEncodeUTF8()来使能UTF-8编码,这一步是必须的,切不可以忘了。
- 第4步:此时就可以使用这7种字体了,打开这7个字体文件,每个文件的开头都有一个extern的字体声明。
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong16;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong32;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong72;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong144;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSongA144;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSongExA144;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSongExF144;
如果用户要在哪个源码文件里面使用这些字体,就把这些字体声明放在相应源文件的开头就行。使用方法,跟使用emWin自带的ASCII和ISO 8859-1字体基本是一样的,唯一区别的地方是:调用FontCvt生成的字体时要加上取地址操作&。下面举一个完整的例子,代码在本章节配套例子的MainTask.c文件里面(对于初学者来说,对话框,按钮控件和文本控件还没有讲到,这里只是举个例子,会使用这些新生成的字体即可,后面会讲到这些控件):
#include "MainTask.h" #include "includes.h" /* ********************************************************************************************************* * 调用外部字体声明,这个就是第4步中所说的问题 ********************************************************************************************************* */ extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong16; extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong32; extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong72; extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong144; extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSongA144; extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSongExA144; extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSongExF144; /* ********************************************************************************************************* * 对话框资源列表 ********************************************************************************************************* */ static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = { { FRAMEWIN_CreateIndirect, "armfly", 0, 0, 0, 800,480,FRAMEWIN_CF_MOVEABLE,0}, { BUTTON_CreateIndirect, "安富莱我们我们", GUI_ID_BUTTON0, 350,20,420,150,0,0}, { TEXT_CreateIndirect, "安富莱电子", GUI_ID_TEXT0, 5, 10, 300, 33, 0,0}, { TEXT_CreateIndirect, "安富莱电子", GUI_ID_TEXT1, 5, 40,250, 50, 0,0}, { TEXT_CreateIndirect, "安富莱", GUI_ID_TEXT2, 5, 100,360, 90, 0,0}, { TEXT_CreateIndirect, "富", GUI_ID_TEXT3, 5, 220,144, 144, 0,0}, { TEXT_CreateIndirect, "富", GUI_ID_TEXT4, 205, 230,144, 144, 0,0}, { TEXT_CreateIndirect, "富", GUI_ID_TEXT5, 405, 230,144, 144, 0,0}, { TEXT_CreateIndirect, "富", GUI_ID_TEXT6, 605, 230,144, 144, 0,0} }; /* ********************************************************************************************************* * 函 数 名: PaintDialog * 功能说明: 对话框重绘函数 * 形 参:pMsg 消息指针 * 返 回 值: 无 ********************************************************************************************************* */ void PaintDialog(WM_MESSAGE * pMsg) { // WM_HWIN hWin = pMsg->hWin; } /* ********************************************************************************************************* * 函 数 名: 对话框初始化 * 功能说明: 对话框初始化 * 形 参: pMsg 消息指针 * 返 回 值: 无 ********************************************************************************************************* */ void InitDialog(WM_MESSAGE * pMsg) { WM_HWIN hWin = pMsg->hWin; // // 配置FrameWin // FRAMEWIN_SetFont(hWin,&GUI_Font32B_ASCII); FRAMEWIN_SetTextAlign(hWin,GUI_TA_VCENTER|GUI_TA_CENTER); FRAMEWIN_AddCloseButton(hWin, FRAMEWIN_BUTTON_RIGHT, 0); FRAMEWIN_AddMaxButton(hWin, FRAMEWIN_BUTTON_RIGHT, 1); FRAMEWIN_AddMinButton(hWin, FRAMEWIN_BUTTON_RIGHT, 2); FRAMEWIN_SetTitleHeight(hWin,35); /* 外部的7种字体在文件控件TEXT和按钮控件BUTTON中都使用了,具体调用方法如下, 跟使用emWin自带的字体是一样的。*/ // // 按钮的字体是4倍抗锯齿,144点阵 // BUTTON_SetFont(WM_GetDialogItem(hWin,GUI_ID_BUTTON0),&GUI_FontFontSongA144); // // 分别用16点阵,32点阵和72点阵字体显示 安富莱电子 五个字。 // TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT0), GUI_RED); TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT0),&GUI_FontFontSong16); TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT1), GUI_GREEN); TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT1),&GUI_FontFontSong32); TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT2), GUI_BLUE); TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT2),&GUI_FontFontSong72); // // 分别用144点阵汉字,144点阵的扩展模式且4倍抗锯齿汉字,144点阵的4倍抗锯齿汉字和 // 144点阵的扩展模式且带边框汉字。 // TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT3),&GUI_FontFontSong144); TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT4),&GUI_FontFontSongExA144); TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT5),&GUI_FontFontSongA144); TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT6),&GUI_FontFontSongExF144); } /* ********************************************************************************************************* * 函 数 名: _cbCallback * 功能说明: 对话框回调函数 * 形 参: pMsg 消息指针 * 返 回 值: 无 ********************************************************************************************************* */ static void _cbCallback(WM_MESSAGE * pMsg) { int NCode, Id; WM_HWIN hWin = pMsg->hWin; switch (pMsg->MsgId) { case WM_PAINT: PaintDialog(pMsg); break; case WM_INIT_DIALOG: InitDialog(pMsg); break; case WM_KEY: switch (((WM_KEY_INFO*)(pMsg->Data.p))->Key) { case GUI_KEY_ESCAPE: GUI_EndDialog(hWin, 1); break; case GUI_KEY_ENTER: GUI_EndDialog(hWin, 0); break; } break; case WM_NOTIFY_PARENT: Id = WM_GetId(pMsg->hWinSrc); NCode = pMsg->Data.v; switch (Id) { case GUI_ID_OK: if(NCode==WM_NOTIFICATION_RELEASED) GUI_EndDialog(hWin, 0); break; case GUI_ID_CANCEL: if(NCode==WM_NOTIFICATION_RELEASED) GUI_EndDialog(hWin, 0); break; } break; default: WM_DefaultProc(pMsg); } } /* ********************************************************************************************************* * 函 数 名: MainTask * 功能说明: GUI主函数 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void MainTask(void) { /* 初始化 */ GUI_Init(); WM_MULTIBUF_Enable(1); /* 使能UTF-8编码,这个是第3步中所说的问题,不必限制一定要放在这个位置,使用外部字体之前调用了即可 */ GUI_UC_SetEncodeUTF8(); /* 调用此函数会自动的刷新桌面窗口 */ WM_SetDesktopColor(GUI_WHITE); /* 创建对话框 */ GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), &_cbCallback, 0, 0, 0); while(1) { GUI_Delay(10); } }
通过上面的代码就实现了这7种字体的显示,具体效果可以看实验例程说明。
- 第5步:这个是最重要的一步,很多初学者显示汉字失败就是因为这一步了。
修改汉字显示所在的源文件,即MainTask.c文件为UTF-8编码,并不是修改FontCvt生成的C文件为UTF-8编码,因为FontCvt软件生成的C文件已经是UTF-8编码了。也就是说哪个文件用到这种汉字显示了,哪个文件就修改编码类型为UTF-8,只有这样,MDK才可以将这些汉字的编码识别出来,要不识别出来的汉字编码与FontCvt生成字体的编码类型不匹配,从而无法正确显示。
修改编码类型也比较容易,使用电脑自带的记事本即可,将MainTask.C文件用记事本打开:
点击文件->另存为
弹出如下窗口:
点击保存后,会弹出如下窗口:
重新切换回MDK工程,也会弹出一个窗口:
这样MainTask.c文件就变成UTF-8编码了。此时就可以全编译工程并下载例子到开发板进行测试了。
28.4.2 IAR编译器中使用C文件格式汉字的方法
- 第1步:将生成的7种字体文件添加到IAR工程目录里面,本章节配套的例子是将其放在User->fonts文件夹下
- 第2步:将生成的7种字体文件添加到IAR工程中
- 第3步:调用函数GUI_UC_SetEncodeUTF8()来使能UTF-8编码,这一步是必须的,切不可以忘了。
- 第4步:此时就可以使用这7种字体了,打开这7个字体文件,每个文件的开头都有一个extern的字体声明。
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong16;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong32;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong72;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong144;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSongA144;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSongExA144;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSongExF144;
如果用户要在哪个源码文件里面使用这些字体,就把这些字体声明放在相应源文件的开头就行。使用方法,跟使用emWin自带的ASCII和ISO 8859-1字体基本是一样的,唯一区别的地方是:调用FontCvt生成的字体时要加上取地址操作&。下面举一个完整的例子,代码在本章节配套例子的MainTask.c文件里面(对于初学者来说,对话框,按钮控件和文本控件还没有讲到,这里只是举个例子,会使用这些新生成的字体即可,后面会讲到这些控件):
#include "MainTask.h" #include "includes.h" /* ********************************************************************************************************* * 调用外部字体声明,这个就是第4步中所说的问题 ********************************************************************************************************* */ extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong16; extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong32; extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong72; extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSong144; extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSongA144; extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSongExA144; extern GUI_CONST_STORAGE GUI_FONT GUI_FontFontSongExF144; /* ********************************************************************************************************* * 对话框资源列表 ********************************************************************************************************* */ static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = { { FRAMEWIN_CreateIndirect, "armfly", 0, 0, 0, 800,480,FRAMEWIN_CF_MOVEABLE,0}, { BUTTON_CreateIndirect, "安富莱我们我们", GUI_ID_BUTTON0, 350,20,420,150,0,0}, { TEXT_CreateIndirect, "安富莱电子", GUI_ID_TEXT0, 5, 10, 300, 33, 0,0}, { TEXT_CreateIndirect, "安富莱电子", GUI_ID_TEXT1, 5, 40,250, 50, 0,0}, { TEXT_CreateIndirect, "安富莱", GUI_ID_TEXT2, 5, 100,360, 90, 0,0}, { TEXT_CreateIndirect, "富", GUI_ID_TEXT3, 5, 220,144, 144, 0,0}, { TEXT_CreateIndirect, "富", GUI_ID_TEXT4, 205, 230,144, 144, 0,0}, { TEXT_CreateIndirect, "富", GUI_ID_TEXT5, 405, 230,144, 144, 0,0}, { TEXT_CreateIndirect, "富", GUI_ID_TEXT6, 605, 230,144, 144, 0,0} }; /* ********************************************************************************************************* * 函 数 名: PaintDialog * 功能说明: 对话框重绘函数 * 形 参:pMsg 消息指针 * 返 回 值: 无 ********************************************************************************************************* */ void PaintDialog(WM_MESSAGE * pMsg) { // WM_HWIN hWin = pMsg->hWin; } /* ********************************************************************************************************* * 函 数 名: 对话框初始化 * 功能说明: 对话框初始化 * 形 参: pMsg 消息指针 * 返 回 值: 无 ********************************************************************************************************* */ void InitDialog(WM_MESSAGE * pMsg) { WM_HWIN hWin = pMsg->hWin; // // 配置FrameWin // FRAMEWIN_SetFont(hWin,&GUI_Font32B_ASCII); FRAMEWIN_SetTextAlign(hWin,GUI_TA_VCENTER|GUI_TA_CENTER); FRAMEWIN_AddCloseButton(hWin, FRAMEWIN_BUTTON_RIGHT, 0); FRAMEWIN_AddMaxButton(hWin, FRAMEWIN_BUTTON_RIGHT, 1); FRAMEWIN_AddMinButton(hWin, FRAMEWIN_BUTTON_RIGHT, 2); FRAMEWIN_SetTitleHeight(hWin,35); /* 外部的7种字体在文件控件TEXT和按钮控件BUTTON中都使用了,具体调用方法如下, 跟使用emWin自带的字体是一样的。*/ // // 按钮的字体是4倍抗锯齿,144点阵 // BUTTON_SetFont(WM_GetDialogItem(hWin,GUI_ID_BUTTON0),&GUI_FontFontSongA144); // // 分别用16点阵,32点阵和72点阵字体显示 安富莱电子 五个字。 // TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT0), GUI_RED); TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT0),&GUI_FontFontSong16); TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT1), GUI_GREEN); TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT1),&GUI_FontFontSong32); TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT2), GUI_BLUE); TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT2),&GUI_FontFontSong72); // // 分别用144点阵汉字,144点阵的扩展模式且4倍抗锯齿汉字,144点阵的4倍抗锯齿汉字和 // 144点阵的扩展模式且带边框汉字。 // TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT3),&GUI_FontFontSong144); TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT4),&GUI_FontFontSongExA144); TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT5),&GUI_FontFontSongA144); TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT6),&GUI_FontFontSongExF144); } /* ********************************************************************************************************* * 函 数 名: _cbCallback * 功能说明: 对话框回调函数 * 形 参: pMsg 消息指针 * 返 回 值: 无 ********************************************************************************************************* */ static void _cbCallback(WM_MESSAGE * pMsg) { int NCode, Id; WM_HWIN hWin = pMsg->hWin; switch (pMsg->MsgId) { case WM_PAINT: PaintDialog(pMsg); break; case WM_INIT_DIALOG: InitDialog(pMsg); break; case WM_KEY: switch (((WM_KEY_INFO*)(pMsg->Data.p))->Key) { case GUI_KEY_ESCAPE: GUI_EndDialog(hWin, 1); break; case GUI_KEY_ENTER: GUI_EndDialog(hWin, 0); break; } break; case WM_NOTIFY_PARENT: Id = WM_GetId(pMsg->hWinSrc); NCode = pMsg->Data.v; switch (Id) { case GUI_ID_OK: if(NCode==WM_NOTIFICATION_RELEASED) GUI_EndDialog(hWin, 0); break; case GUI_ID_CANCEL: if(NCode==WM_NOTIFICATION_RELEASED) GUI_EndDialog(hWin, 0); break; } break; default: WM_DefaultProc(pMsg); } } /* ********************************************************************************************************* * 函 数 名: MainTask * 功能说明: GUI主函数 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void MainTask(void) { /* 初始化 */ GUI_Init(); WM_MULTIBUF_Enable(1); /* 使能UTF-8编码,这个是第3步中所说的问题,不必限制一定要放在这个位置,使用外部字体之前调用了即可 */ GUI_UC_SetEncodeUTF8(); /* 调用此函数会自动的刷新桌面窗口 */ WM_SetDesktopColor(GUI_WHITE); /* 创建对话框 */ GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), &_cbCallback, 0, 0, 0); while(1) { GUI_Delay(10); } }
通过上面的代码就实现了这7种字体的显示,具体效果可以看实验例程说明。
- 第5步:这个是最重要的一步,很多初学者显示汉字失败就是因为这一步了。
修改汉字显示所在的源文件,即MainTask.c文件为UTF-8编码,并不是修改FontCvt生成的C文件为UTF-8编码,因为FontCvt软件生成的C文件已经是UTF-8编码了。也就是说哪个文件用到这种汉字显示了,哪个文件就修改编码类型为UTF-8,只有这样,IAR将这些汉字的编码识别出来,要不识别出来的汉字编码与FontCvt生成字体的编码类型不匹配,从而无法正确显示。
修改编码类型也比较容易,使用IAR的话,不要使用记事本来修改了(为什么不可以使用,在28.5小节有讲解),IAR编辑器支持编码类型的修改。
IAR编码方面的小知识:
默认情况下,IAR创建的工程都是System编码,也就是你的电脑系统是什么编码类型,使用IAR创建的.C和.H文件就是什么编码类型,一般大陆都是用的GBK编码,查看电脑系统编码类型可以通过:单击开始->所有程序->附件->命令提示符,打开命令提示符,输入chcp,然后点击键盘的回车键。
这里的936就是代表GBK编码。而IAR的编码设置在这里,点击菜单Tools->Options,弹出如下窗口
默认的编码类型是System。
在IAR编译器中如何查看.C和.H文件的编码类型,又如何修改呢?查看编码类型可以任意打开一个文件,然后查看右下角。
这里打开的就是一个中文简体,GB2312编码,GBK向下是完全兼容GB2312的。修改单个.C和.H文件的编码类型也比较简单,这里我们需要修改MainTask.c文件的编码类型为UTF-8,直接在MainTask.c文件里面右击鼠标,选择Character Encoding->Convert to UTF-8。
设置后就可以看到右下角已经修改为UTF-8了。
此时就可以全编译工程并下载例子到开发板进行测试了。
28.5 生成的是Unicode编码字体,而使用时为什么是UTF-8
初学者容易有这样的疑问,FontCvt软件生成的是Unicode编码的汉字,为什么emWin使用的时候不直接使用,还要多一次转换,即我们操作的时候是用的UTF-8编码字体,emWin的库函数会将这个编码转换成Unicode编码,然后从Unicode编码的字符集中获取相应的点阵数据。
补充点小知识,方便大家理解:
- Unicode编码
各个国家都有一套自己的编码标准,但谁也不懂谁的编码,谁也不支持别人的编码。基于此,国际组织决定着手解决这个问题,即重新弄一套包括了地球上所有文化、所有字母和符号的编码。将其命名为"UniversalMultiple-Octet Coded Character Set“(通用多八位编码字符集),简称 UCS, 俗称Unicode。Unicode有两种编码UCS-2和UCS-4,其中UCS-2用两个字节编码,UCS-4用4个字节编码。
- UTF-8编码
事实证明,对可以用ASCⅡ表示的字符使用UNICODE并不高效,因为UNICODE比ASCⅡ占用大一倍的空间,而对ASCⅡ来说高字节的0对他毫无用处。为了解决这个问题,就出现了一些中间格式的字符集,他们被称为通用转换格式,即UTF(Universal Transformation Format)。目前存在的UTF格式有:UTF-7,UTF-7.5,UTF-8,UTF-16以及 UTF-32。
那么问题来了,emWin中为什么不直接使用Unicode编码,而要使用UTF-8。
1. MDK和IAR的编辑器都不支持Unicode编码,仅支持UTF-8,笔者认为,这个是最主要的原因。
2. UTF-8编码相对于Unicode编码的优势。
(1) UTF-8表示与ASCII字符表示是一样的,只占一个字节,解决了Unicode浪费空间的情况。
(2) 与CPU字节顺序无关, 可以在不同平台之间交流。
(3) 容错能力高, 任何一个字节损坏后, 最多只会导致一个编码码位损失, 不会连锁错误。
28.6 MDK4.X,MDK5.X和IAR的UTF-8编码问题
对于初学者来说,下面的问题是必看的,初次看可能不太理解,实际用这三个编译器操作了本章节配套的例子就有深刻的体会了。
28.6.1 MDK4.X的UTF-8说明
MDK4.74是MDK4系列里面的最后一个版本了。
一直以来都是将汉字显示所在的源文件使用记事本另存为UTF-8编码类型,特别注意,记事本另存的是UTF-8 带 BOM。且用户修改了这个文件的任何地方,MDK都会自动将这个文件存储为UTF-8编码无BOM。实际用Notepad++另存为UTF-8带BOM或者不带BOM,使用MDK4.74都可以正确显示汉字的。
28.6.2 MDK5.X的UTF-8说明
对于MDK5.X来说,也可以使用记事本将汉字显示所在的源文件另存为UTF-8编码类型,此时MDK5.21a是可以正确编译的。但是,用户一旦修改了这个文件的任何地方,直接编译或者保存后编译,MDK都会将这个文件存储为UTF-8编码无BOM,而MDK5.X无法像MDK4.X那样带BOM或者不带BOM都能够识别,所以编译会出错。解决方法:options->c/c++->Misc controls 填写“--locale=english”
28.6.3 IAR的UTF-8说明
对于IAR来说,他仅支持UTF-8无BOM,修改的时候不要使用记事本,直接在汉字显示所在的源文件右击选择即可(在28.4.2小节已经讲解),或者用Notepad++选择UTF-8无BOM。
28.6.4 编码问题总结
- IAR仅支持UTF-8编码无BOM文件的汉字显示,带BOM的话,编译不通过。
- MDK4.X对于UTF-8带BOM或者不带BOM都支持,但会将带BOM文件修改为不带BOM,两种编码形式显示汉字都不受影响。
- MDK5.X对于UTF-8带BOM或者不带BOM都支持,不过需要大家按照28.6.2小结的说明修改。
名词解释:BOM
BOM(Byte Order Mark),字节顺序标记,出现在文本文件头部,Unicode编码标准中用于标识文件是采用哪种格式的编码。UTF-8 不需要 BOM 来表明字节顺序,但可以用 BOM 来表明编码方式。字符 "Zero Width No-Break Space" 的 UTF-8 编码是 EF BB BF。所以如果接收者收到以 EF BB BF 开头的字节流,就知道这是 UTF-8编码了。Windows 就是使用 BOM 来标记文本文件的编码方式的。
WINDOWS自带的记事本等软件,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM)。它是一串隐藏的字符,用于让记事本等编辑器识别这个文件是否以UTF-8编码。
28.7 实验例程说明(RTOS)
配套例子:
V7-532_emWin6.x实验_C文件格式的汉字生成和实现,Unicode编码(RTOS)
实验目的:
- 学习emWin的C文件格式汉字的使用方法,Unicode编码。
- emWin功能的实现在MainTask.c文件里面。
实验内容:
1、K1按键按下,串口或者RTT打印任务执行情况(串口波特率115200,数据位8,奇偶校验位无,停止位1)。
2、(1) 凡是用到printf函数的全部通过函数App_Printf实现。
(2) App_Printf函数做了信号量的互斥操作,解决资源共享问题。
3、默认上电是通过串口打印信息,如果使用RTT打印信息:
MDK AC5,MDK AC6或IAR通过使能bsp.h文件中的宏定义为1即可
#define Enable_RTTViewer 1
4、各个任务实现的功能如下:
App Task Start 任务 :启动任务,这里用作BSP驱动包处理。
App Task MspPro任务 :消息处理,这里用作LED闪烁。
App Task UserIF 任务 :按键消息处理。
App Task COM 任务 :暂未使用。
App Task GUI 任务 :GUI任务。
μCOS-III任务调试信息(按K1按键,串口打印):
RTT 打印信息方式:
程序设计:
- 任务栈大小分配:
μCOS-III任务栈大小在app_cfg.h文件中配置:
#define APP_CFG_TASK_START_STK_SIZE 512u
#define APP_CFG_TASK_MsgPro_STK_SIZE 2048u
#define APP_CFG_TASK_COM_STK_SIZE 512u
#define APP_CFG_TASK_USER_IF_STK_SIZE 512u
#define APP_CFG_TASK_GUI_STK_SIZE 2048u
任务栈大小的单位是4字节,那么每个任务的栈大小如下:
App Task Start 任务 :2048字节。
App Task MspPro任务 :8192字节。
App Task UserIF 任务 :2048字节。
App Task COM 任务 :2048字节。
App Task GUI 任务 :8192字节。
- 系统栈大小分配:
μCOS-III的系统栈大小在os_cfg_app.h文件中配置:
#define OS_CFG_ISR_STK_SIZE 512u
系统栈大小的单位是4字节,那么这里就是配置系统栈大小为2KB
emWin动态内存配置:
GUIConf.c文件中的配置如下:
#define EX_SRAM 1/*1 used extern sram, 0 used internal sram */ #if EX_SRAM #define GUI_NUMBYTES (1024*1024*24) #else #define GUI_NUMBYTES (100*1024) #endif
通过宏定义来配置使用内部SRAM还是外部的SDRAM做为emWin的动态内存,当配置:
#define EX_SRAM 1 表示使用外部SDRAM作为emWin动态内存,大小24MB。
#define EX_SRAM 0 表示使用内部SRAM作为emWin动态内存,大小100KB。
默认情况下,本教程配套的所有emWin例子都是用外部SDRAM作为emWin动态内存。
emWin界面显示效果:
800*480分辨率界面效果。
28.8 实验例程说明(裸机)
配套例子:
V7-531_emWin6.x实验_C文件格式的汉字生成和实现,Unicode编码(裸机)
实验目的:
- 学习emWin的C文件格式汉字的使用方法,Unicode编码。
- emWin功能的实现在MainTask.c文件里面。
emWin界面显示效果:
800*480分辨率界面效果。
emWin动态内存配置:
GUIConf.c文件中的配置如下:
#define EX_SRAM 1/*1 used extern sram, 0 used internal sram */ #if EX_SRAM #define GUI_NUMBYTES (1024*1024*24) #else #define GUI_NUMBYTES (100*1024) #endif
通过宏定义来配置使用内部SRAM还是外部的SDRAM做为emWin的动态内存,当配置:
#define EX_SRAM 1 表示使用外部SDRAM作为emWin动态内存,大小24MB。
#define EX_SRAM 0 表示使用内部SRAM作为emWin动态内存,大小100KB。
默认情况下,本教程配套的所有emWin例子都是用外部SDRAM作为emWin动态内存。
28.9 总结
本章节讲解的内容较多,特别是涉及到UTF-8编码的问题时,望初学者务必将其掌握,有了本章节的基础,后面几个章节的汉字显示操作起来将更加的得心应手。