硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2478|回复: 9
收起左侧

[emWin] 基于安富莱emWin2.0 GB2312全字库教程和实例在我的SPI接口屏上的移植不成功

[复制链接]

68

主题

472

回帖

681

积分

金牌会员

积分
681
发表于 2018-12-12 11:49:16 | 显示全部楼层 |阅读模式
我对老式裸奔下的GB2312汉字显示很熟悉,N年前用19264液晶,自己做的各种等宽字体字库,现在改用SPI接口的TFT了,目前已经通过485接口把自己做的字库BIN文件下发到W25Q128上,并且裸奔的情况下已经能够用自己写的函数显示半角字符和全角字符和汉字了,之后成功移植uC/OS-II + emWin了,能在TFT上显示emWin自带的ASCII字符,下一步准备把GB2312全字库移植到emWin下,参考的是安富莱emWin2.0 GB2312全字库移植教程,下面是裸奔情况下自己写的显示半角和全角字符的函数,测试没有任何问题:
/*
********************************************************************************
* .读出1个16*16字符的点阵数据(包括全角和半角)
* .pChar - 传入的字符指针,比如"a","啊"
* .说明:读出的点阵数据固定存储到数组uCharDotArray[]中
********************************************************************************
*/
void ReadChar16X(char *pChar)
{
    u32 addr;

    if(pChar[0] <= 0x80)                                                        //半角字符
    {
        addr = 4096 + (pChar[0] - 0x20)*16L;
        W25Q_ReadData(addr, uCharDotArray, 16);
    }
    else                                                                        //全角字符
    {
        if(pChar[0] <= 0xa9)
        {
            addr = 4096 + 1520 + ((pChar[0]-0xa1)*94 + (pChar[1]-0xa1))*32L;
        }
        else
        {
            addr = 4096 + 1520 + ((pChar[0]-0xa7)*94 + (pChar[1]-0xa1))*32L;
        }

        W25Q_ReadData(addr, uCharDotArray, 32);   
    }
}


/*
********************************************************************************
* .在(x,y)处显示一个16X字符
*
* .pChar  - 目标字符
*  x      - 起点x坐标
*  y      - 起点y坐标
*  fColor - 前景色
********************************************************************************
*/
void ShowChar16X_1P77(char *pChar, u16 x, u16 y, u16 fColor)
{
    u8  m;
    u16 i, j;

    ReadChar16X(pChar);

    LCD1P77_SelectWindow(0,LCD1P77_WIDTH-1,0,LCD1P77_HEIGHT-1);

    if(pChar[0] <= 0x80)                                                        //半角字符
    {
        LCD1P77_SelectWindow(x, x+8, y, y+16);

        for(i=0; i<16; i++)
        {
            m = 0x80;

            for(j=0; j<8; j++)
            {
                if(uCharDotArray[i] & m)
                {
                    LCD1P77_DrawPixel(x+j, y+i, fColor);
                }

                m >>= 1;
            }
        }
    }
    else                                                                        //全角字符
    {
        LCD1P77_SelectWindow(x, x+16, y, y+16);

        for(i=0; i<16; i++)
        {
            //汉字左半部分
            m = 0x80;

            for(j=0; j<8; j++)
            {
                if(uCharDotArray[i] & m)
                {
                    LCD1P77_DrawPixel(x+j, y+i, fColor);
                }

                m >>= 1;
            }

            //汉字右半部分
            m = 0x80;

            for(j=0; j<8; j++)
            {
                if(uCharDotArray[i+16] & m)
                {
                    LCD1P77_DrawPixel(x+8+j, y+i, fColor);
                }

                m >>= 1;
            }
        }
    }
}


现在想把上面显示汉字的函数移植到emWin下,参考安富莱移植GB2312全字库的例程,GUI_UC_EncodeNone.c文件原封不动的加入到工程里
GUI_Font16.c文件里的内容基本没有改动,该文件里的所有内容贴在下面:
#include "GUI.h"
#include "GUI_Type.h"

extern void GUIPROP_X_DispChar(U16P c);
extern int  GUIPROP_X_GetCharDistX(U16P c);

GUI_CONST_STORAGE GUI_CHARINFO GUI_FontHZ16_CharInfo[2] =  
{     
    { 8,   8,  1, (void *)"A16"},      
    {16,  16,  2, (void *)"H16"},           
};

GUI_CONST_STORAGE GUI_FONT_PROP GUI_FontHZ16_PropHZ =
{
    0xA1A1,  
    0xFEFE,  
    &GUI_FontHZ16_CharInfo[1],
    (void *)0,  
};

GUI_CONST_STORAGE GUI_FONT_PROP GUI_FontHZ16_PropASC =
{
    0x0000,  
    0x007F,  
    &GUI_FontHZ16_CharInfo[0],
    (void GUI_CONST_STORAGE *)&GUI_FontHZ16_PropHZ,  
};

GUI_CONST_STORAGE  GUI_FONT GUI_FontHZ16 =  
{
    GUI_FONTTYPE_PROP_USER,
    16,  
    16,  
    1,   
    1,   
    (void GUI_CONST_STORAGE *)&GUI_FontHZ16_PropASC,
};

GUI_CONST_STORAGE  GUI_FONT GUI_FontHZ16x2 =  
{
    GUI_FONTTYPE_PROP_USER,
    16,  
    16,  
    2,   
    2,   
    (void GUI_CONST_STORAGE *)&GUI_FontHZ16_PropASC
};


GUICharPEx.c文件里的内容做了比较大的改动,下面贴出该文件的完整内容:
#include "GUI.h"
#include "GUI_Type.h"
#include "GUI_Private.h"
#include "string.h"
#include "stm32f4xx.h"

//extern GUI_SADDR GUI_CONTEXT * GUI_pContext;

extern u8   uCharDotArray[72];                                                  //存储16*16或者24*24点阵数据
extern void W25Q_ReadData(u32 address, u8 *pHead, u16 len);
extern void ShowChar16X_1P77(char *pChar, u16 x, u16 y, u16 fColor);

void GUI_GetDataFromMemory(const GUI_FONT_PROP GUI_UNI_PTR *pProp, U16P c);
void GUIPROP_X_DispChar(U16P c);
int  GUIPROP_X_GetCharDistX(U16P c);

/*
*********************************************************************************************************
*        函 数 名: GUI_GetDataFromMemory
*        功能说明: 读取点阵数据
*        形    参: pProp  GUI_FONT_PROP类型结构
*             c      字符
*        返 回 值: 无
*********************************************************************************************************
*/
void GUI_GetDataFromMemory(const GUI_FONT_PROP GUI_UNI_PTR *pProp, U16P c)
{
    U32 addr;
    U8  pChar[2];

    char *font = (char *)pProp->paCharInfo->pData;

    pChar[0] = (u8)(c >> 8);
    pChar[1] = (u8)(c);
       
    //半角字符
    if(c <= 0x80)                                                               
    {
        //6*12
        if(strncmp("A12", font, 3) == 0)
        {
        }
        //8*16
        else if(strncmp("A16", font, 3) == 0)
        {
            addr = 4096 + (pChar[0] - 0x20)*16L;

            //读取点阵数据
            W25Q_ReadData(addr, uCharDotArray, 16);
        }
        //12*24
        else if(strncmp("A24", font, 3) == 0)
        {
        }
        //16*32
        else if(strncmp("A32", font, 3) == 0)
        {
        }
    }
    //全角字符
    else                                                                           
    {      
        //12*12
        if(strncmp("H12", font, 3) == 0)
        {
        }
        //16*16
        else if(strncmp("H16", font, 3) == 0)
        {
            if(pChar[0] <= 0xa9)
            {
                addr = 4096 + 1520 + ((pChar[0]-0xa1)*94 + (pChar[1]-0xa1))*32L;
            }
            else
            {
                addr = 4096 + 1520 + ((pChar[0]-0xa7)*94 + (pChar[1]-0xa1))*32L;
            }

            //读取点阵数据
            W25Q_ReadData(addr, uCharDotArray, 32);
        }
        //24*24
        else if(strncmp("H24", font, 3) == 0)
        {
        }
        //32*32
        else if(strncmp("H32", font, 3) == 0)
        {
        }
    }
}

/*
*********************************************************************************************************
*        函 数 名: GUIPROP_X_DispChar
*        功能说明: 显示字符
*        形    参: c 显示的字符
*        返 回 值: 无
*********************************************************************************************************
*/
void GUIPROP_X_DispChar(U16P c)
{
    char pChar[2];
    GUI_DRAWMODE OldDrawMode;
    GUI_DRAWMODE DrawMode = GUI_pContext->TextMode;
    const GUI_FONT_PROP GUI_UNI_PTR *pProp = GUI_pContext->pAFont->p.pProp;

    const GUI_CHARINFO GUI_UNI_PTR * pCharInfo = pProp->paCharInfo;

    pChar[0] = (u8)(c >> 8);
    pChar[1] = (u8)(c);

    OldDrawMode  = LCD_SetDrawMode(DrawMode);
    ShowChar16X_1P77(pChar, GUI_pContext->DispPosX, GUI_pContext->DispPosY, 0xffff);

    LCD_SetDrawMode(OldDrawMode);
    GUI_pContext->DispPosX += pCharInfo->XDist * GUI_pContext->pAFont->XMag;
}

/*
*********************************************************************************************************
*        函 数 名: GUIPROP_X_GetCharDistX
*        功能说明: 获取字符的X轴间距
*        形    参: c  字符
*        返 回 值: 无
*********************************************************************************************************
*/
int GUIPROP_X_GetCharDistX(U16P c)
{
    const GUI_FONT_PROP GUI_UNI_PTR * pProp = GUI_pContext->pAFont->p.pProp;  
    for (; pProp; pProp = pProp->pNext)                                         
    {
        if ((c >= pProp->First) && (c <= pProp->Last))break;
    }
    return (pProp) ? (pProp->paCharInfo)->XSize * GUI_pContext->pAFont->XMag : 0;
}

在该文件里,实际上GUI_GetDataFromMemory()函数我移植了,但是在GUIPROP_X_DispChar(U16P c)函数里根本就没调用这个函数,而直接调用了连读字模带显示的函数ShowChar16X_1P77()

上面移植OK了,然后就是调用,在调用显示的头文件里声明了外部字体 extern GUI_CONST_STORAGE  GUI_FONT GUI_FontHZ16;
然后在main()主函数里调用:
    GUI_Init();

    //横屏
    LCD1P77_WriteReg8(0x36);
    LCD1P77_WriteData8(0x78);

    GUI_SetBkColor(0x07E0);
    GUI_Clear();
    GUI_SetDefaultFont(&GUI_FontHZ16);  //1处
    //LCD1P77_ClearScreen(GREEN);
    GUI_DispStringAt("012", 00, 0);   //2处
    GUI_DispStringAt("祖国", 00, 0);   //3处

    ShowChar16X_1P77("5", 0, 0, 0xffff);  //4处
    ShowChar16X_1P77("张", 0, 16, 0xffff);  //5处

上面的代码,1处设置默认字体为前面前面创建的字体GUI_FontHZ16,执行2处代码之后,能正确显示字符“012”,执行到3处的时候,汉字“祖国”并没有显示出来,执行到4和5处的时候,能用自己写的裸奔函数显示出“5”和“张”,这说明1处修改默认字体的动作并没有成功,回头再调试,执行3处代码的时候,发现并没有运行到GUIPROP_X_DispChar()函数里,也就是说emWin压根儿就没搭理自定义的字体函数,硬汉和各位GUI高手能不能帮我分析下原因,XBF和SIF字体方式我很不习惯,还是习惯老式的GB2312方式
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115778
QQ
发表于 2018-12-12 12:01:50 | 显示全部楼层
可以这样搞,先把我提供的那个移植并显示下,在这里有详细说明。在成功的基础上移植你的字库,这样就方便了。

http://www.armbbs.cn/forum.php?m ... &extra=page%3D1

看25和26章
QQ截图20181212120218.jpg

回复

使用道具 举报

68

主题

472

回帖

681

积分

金牌会员

积分
681
 楼主| 发表于 2018-12-13 10:08:14 | 显示全部楼层
昨晚又仔细对比了下源码,发现
GUI_Clear();
GUI_SetDefaultFont(&GUI_FontHZ16);  //1处
1处有问题,安富莱的示例代码用的是GUI_SetFont(),修改之后汉字是出来了,但是显示出来的不是想要的字,应该是读点阵数据的偏移地址算错了,另外用函数GUI_DispStringAt();连续显示2个以上汉字的时候,发现3个汉字显示的重叠了,应该是显示完一个汉字以后,更新GUI_pContext->DispPosX坐标出现了问题,就这两个问题我再继续检查下源码,另外读汉字点阵数据的时候,计算偏移地址是否跟GUI_Font16.c里如下两个函数有关
GUI_CONST_STORAGE GUI_FONT_PROP GUI_FontHZ16_PropHZ =
{
    0xA1A1,  
    0xFEFE,  
    &GUI_FontHZ16_CharInfo[1],
    (void *)0,  
};

GUI_CONST_STORAGE GUI_FONT_PROP GUI_FontHZ16_PropASC =
{
    0x0000,  
    0x007F,  
    &GUI_FontHZ16_CharInfo[0],
    (void GUI_CONST_STORAGE *)&GUI_FontHZ16_PropHZ,  
};
全角A1A1 FEFE,半角0000 007F,因为我自己做的字库,点阵的排列顺序是95个半角字符+846个全角字符+6768个汉字,因此全角字符和汉字的寻址顺序和安富莱的字库文件寻址顺序肯定是不同的,那么这两个地方是否需要修改呢?
回复

使用道具 举报

9

主题

140

回帖

187

积分

初级会员

积分
187
QQ
发表于 2018-12-13 10:56:37 | 显示全部楼层
http://www.armbbs.cn/forum.php?m ... id=87428&extra=
我做的emwin字体工具,用我的工具移植全字库非学简单,只需要实现一个读取函数,从给出的偏移地址,读出指定大小字节即可完成,支持不等宽字体,还支持抗锯齿,有兴趣可了解一下。
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115778
QQ
发表于 2018-12-14 02:53:40 | 显示全部楼层
taobaofarmer 发表于 2018-12-13 10:08
昨晚又仔细对比了下源码,发现
GUI_Clear();
GUI_SetDefaultFont(&GUI_FontHZ16);  //1处

你的字符地址跟你的公式匹配就行
QQ截图20181214025305.jpg
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115778
QQ
发表于 2018-12-14 02:54:25 | 显示全部楼层
allyzc 发表于 2018-12-13 10:56
http://www.armbbs.cn/forum.php?mod=viewthread&tid=87428&extra=
我做的emwin字体工具,用我的工具移 ...

好工具
回复

使用道具 举报

68

主题

472

回帖

681

积分

金牌会员

积分
681
 楼主| 发表于 2018-12-14 11:09:33 | 显示全部楼层
问题全部解决了,我说下解决的细节
“另外用函数GUI_DispStringAt();连续显示2个以上汉字的时候,发现3个汉字显示的重叠了,应该是显示完一个汉字以后,更新GUI_pContext->DispPosX坐标出现了问题,就这两个问题我再继续检查下源码”
上面的问题,是我上次发布的,这个问题的原因是安富莱GUI_Font16.c这个文件的源码是有问题的,下面贴出安富莱原装的代码:
GUI_CONST_STORAGE  GUI_FONT_PROP GUI_FontHZ16_PropASC= {
      0x0000,  
      0x007F,  
      &GUI_FontHZ16_CharInfo[0],
      (void GUI_CONST_STORAGE *)&GUI_FontHZ16_PropHZ,  //1处
};
GUI_CONST_STORAGE  GUI_FONT GUI_FontHZ16 =  
{
          GUI_FONTTYPE_PROP_USER,
      16,  
      16,  
      1,   
      1,   
      (void GUI_CONST_STORAGE *)&GUI_FontHZ16_PropASC,  //2处
};
看上面的1处和2处,显然是有问题的,但不知道这样的代码为何在安富莱的板子里运行没问题,然后我做了下修改如下:
GUI_CONST_STORAGE GUI_FONT_PROP GUI_FontHZ16_PropASC =
{
    0x0000,  
    0x007F,  
    &GUI_FontHZ16_CharInfo[0],
    (void GUI_CONST_STORAGE *)&GUI_FontHZ16_PropASC,  
};

GUI_CONST_STORAGE  GUI_FONT GUI_FontHZ16 =  
{
    GUI_FONTTYPE_PROP_USER,
    16,  
    16,  
    1,   
    1,   
    (void GUI_CONST_STORAGE *)&GUI_FontHZ16_PropHZ,
};
修改后,汉字重叠的问题没有了,但是还是有一个问题就是显示出来的汉字不是我想要的那个,初步怀疑是读点阵的时候偏移地址算错了,然后我又修改了GUIPROP_X_DispChar(U16P c)函数,代码如下:
void GUIPROP_X_DispChar(U16P c)
{
   
    //GUI_DRAWMODE OldDrawMode;
    //GUI_DRAWMODE DrawMode = GUI_pContext->TextMode;
   
    const GUI_FONT_PROP GUI_UNI_PTR *pProp     = GUI_pContext->pAFont->p.pProp;
   
    char *font = (char *)pProp->paCharInfo->pData;
    const GUI_CHARINFO  GUI_UNI_PTR *pCharInfo = pProp->paCharInfo;
        
    //OldDrawMode  = LCD_SetDrawMode(DrawMode);
    //GUI_GetDataFromMemory(pProp, c);
    //12*12
    if(strncmp("H12", font, 3) == 0)
    {
    }
    //16*16
    else if(strncmp("H16", font, 3) == 0)
    {
        ShowChar16X_1P77((char *)(&c), GUI_pContext->DispPosX, GUI_pContext->DispPosY, GUI_pContext->Color);
    }
    //LCD_SetDrawMode(OldDrawMode);
    GUI_pContext->DispPosX += pCharInfo->XDist * GUI_pContext->pAFont->XMag;
}
主要修改的地方是我把GUI_GetDataFromMemory()函数去掉了,把识别字模尺寸和读点阵的功能全部合并到GUIPROP_X_DispChar(U16P c)函数里,一下子汉字正确的显示出来了,这说明,如果先调用GUI_GetDataFromMemory()函数,把点阵数据读到自己定义的一个数组里,然后再调用 ShowChar16X_1P77()函数把点阵显示出来,就会造成之前的现象,如果把两个动作合并到一个函数里就OK,问题解决了,但原因查不出来,应该是不可能查出来了,反正现在好使了就行,另外感觉安富莱的代码冗余太多,在演示一个特定功能的例程里,其它无关的代码太多,不够精炼
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115778
QQ
发表于 2018-12-14 11:13:38 | 显示全部楼层
taobaofarmer 发表于 2018-12-14 11:09
问题全部解决了,我说下解决的细节
“另外用函数GUI_DispStringAt();连续显示2个以上汉字的时候,发现3 ...


很多地方不要省略,后面测试控件的显示字体,会有一些神奇的问题,切要注意。
回复

使用道具 举报

68

主题

472

回帖

681

积分

金牌会员

积分
681
 楼主| 发表于 2018-12-14 12:23:14 | 显示全部楼层
我现在还没用到控件呢,现在只解决了GUI_DispStringAt()函数显示的问题,多谢硬汉的提醒
回复

使用道具 举报

29

主题

514

回帖

606

积分

金牌会员

积分
606
QQ
发表于 2018-12-17 09:03:24 | 显示全部楼层
顶起来。
我之前玩字体是一些编码概念混淆,“UTF-8编码”, “16位编码”。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-5-17 17:15 , Processed in 0.368012 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表