请问如何用C语言实现汉字,和Unicode编码的转换?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请问如何用C语言实现汉字,和Unicode编码的转换?相关的知识,希望对你有一定的参考价值。

参考技术A 字转换:wctomb、mbtowc,wc 指 Wide charactor,mb 指 Multi-byte。\\r\\n字符串转换:wcstombs、mbstowcs,wcs 和 mbs 的 s 指 string。\\r\\n\\r\\n这 4 个函数是 C 标准函数库函数中的。如果只是在 Windows 平台下编程,可直接调用 Windows API 函数 WideCharToMultiByte 和 MultiByteToWideChar 实现。但是如果调用标准库函数的话,在 Linux 下也是有效的。调用标准库函数,首先必须包含 locale.h 并调用 setlocale(LC_ALL, "") 后才能正确转换。Windows 下的 Multi-byte 是 ANSI 编码的,Wide charactor 是 Unicode (UTF-16) 编码,而 Linux 下的 Multi-byte 是 UTF-8 编码的,Wide charactor 是 Unicode (UTF-32) 编码。\\r\\n\\r\\n#include \\r\\n#include \\r\\n#include \\r\\n\\r\\nint main(void)\\r\\n\\r\\n char str[12];\\r\\n wchar_t wstr[] = 0x52B3, 0x788C, 0 ;\\r\\n setlocale(LC_ALL, "");\\r\\n wcstombs(str, wstr, sizeof(str)/sizeof(char));\\r\\n printf("%s", str);\\r\\n return 0;\\r\\n

第3版emWin教程第28章 emWin6.x的C文件格式的汉字生成和实现(Unicode编码)

教程不断更新中: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 使用FontCvt生成C文件格式全字库的方法

28.4 C文件格式汉字的使用方法

28.4.1   MDK编译器中使用C文件格式汉字的方法

28.4.2   IAR编译器中使用C文件格式汉字的方法

28.5 生成的是Unicode编码字体,而使用时为什么是UTF-8

28.6 MDK4.X,MDK5.X和IAR的UTF-8编码问题

28.6.1   MDK4.X的UTF-8说明

28.6.2   MDK5.X的UTF-8说明

28.6.3   IAR的UTF-8说明

28.6.4   编码问题总结

28.7 实验例程说明(RTOS)

28.8 实验例程说明(裸机)

28.9 总结


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)

实验目的:

  1. 学习emWin的C文件格式汉字的使用方法,Unicode编码。
  2. 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编码(裸机)

实验目的:

  1. 学习emWin的C文件格式汉字的使用方法,Unicode编码。
  2. 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编码的问题时,望初学者务必将其掌握,有了本章节的基础,后面几个章节的汉字显示操作起来将更加的得心应手。

以上是关于请问如何用C语言实现汉字,和Unicode编码的转换?的主要内容,如果未能解决你的问题,请参考以下文章

自己编写的中文PHP网页,如何在Unicode(UTF-8)编码下能正常显示汉字而不是乱码?

第3版emWin教程第28章 emWin6.x的C文件格式的汉字生成和实现(Unicode编码)

UTF8原理是啥?如何用C编写UTF8的转换代码?

求c语言高手!!!如何用if判断输入的汉字

请问如何用C语言实现“生产者与消费者问题”?(最好附上完整的C语言源代码)

如何在JS中中文字符串如何比较