查看: 10489|回复: 35

汉字显示1—取模方式(学习笔记)

  [复制链接]
  • TA的每日心情
    奋斗
    2014-7-24 09:24
  • 签到天数: 38 天

    连续签到: 1 天

    [LV.5]常住居民I

    发表于 2014-6-25 11:10:15 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 haha_haha 于 2014-6-25 11:40 编辑

    很多人在用TFT屏做显示时,遇到一个汉字显示问题,到底是做放个字库显示还是汉字取模显示呢?

    一、 做字库前的分析
    当拿到项目要求后,如果其中一段,看到有汉字显示的要求时,就不得不考虑汉字的问题了。
    如果使用字库,根据使用字数多少,可有如下划分:
    A、用量很多。基本要用到全部汉字。此时要考虑自己手中存储资源,是否有足够的空间放这些字模(即,内部,外部FALSH存储)。
    1、如果空间充足,可以做字库到FLASH中(有例程SD卡做字库,字库大小,根据取模大小不同,有几百K到几十M不等),把SD卡的字库文件读出来,存储到FALSHW26Q16)中。
    2、空间少,可以外买字库芯片(当然啦,产品成本要增加)。
    B、用量很少,可以自己取模(比如,二三十个汉字,用字库太浪费FLASH了),那么下面写的流程,即为单个取模流程。

    二、汉字取模
    第一步:总结要用到的所有汉字,比如只有三个字:你好!;
    第二步:打开取字模软件。例如:LCD点阵提取工具;
    图片1.png

    第三步:取字模。
    图片2.png

    图片3.png
    注意上面提示:右键也可以选择字体。

    图片4.png
    以上面这个字体大小为例,点击确定。

    图片5.png
    注意:在左下脚,结束文字输入请按CTRL+ENTER组合键。

    取模生成的字,如上图所示。下面我们使其换成代表汉字的代码(如果此处无法理解,google查一下“点阵”,很快都能明白,汉字的显示是一个一个点组合成的)。

    图片7.png
    左边选框,有一个取模方式,选C51格式,会输出上图字模数据。

    图片8.png
    拷贝生成的字模区,我们生成的字体“你”,算是完成了。

    三、 软件的分析
    我假设,屏驱动已好,你也已经知道如何打点了。

    在写程序之前,我们把上面三个字的取模数据,放到字库文件中,截图如下:
    图片9.png
    要清楚,放的位置,在Font_lib.H中。

    放入上面字模数据后,如何调用他们呢,我们在main.c主程序中加放这一句话
    WriteString(10,150,"你好!",Red);
    这句话的意思:在X10Y150的地方作为起始点,打出字样“你好!”,字体色为Red红色。如下图

    图片10.png

    下面我们进入程序分析:
    大致流程为,
    第一步:找到汉字头部;
    第二步:然后在对应的取字模库中取出字库数据;
    第三步:取出相应的汉字,然后一个点一个点打印出来。
    程序如下:找到汉字头部
    /*****************************************************************************
    ** 函数名称: findHzIndex
    ** 功能描述: 查找汉字在自定义字库中的索引
                                    hz 指向汉字(机内码)的指针
    ** 作   者: FXL
    ** 日   期: 20101206
    *****************************************************************************/
    u16 findHzIndex(u8 *hz)                     /* 在自定义汉字库在查找所要显示 */
                                                               /* 的汉字的位置 */
    {
        u16 i=0;

        FNT_GB16 *ptGb16 = (FNT_GB16 *)GBHZ_16;

        while(ptGb16.Index[0] > 0x80)
        {
            if ((*hz == ptGb16.Index[0]) && (*(hz+1) == ptGb16.Index[1]))
            {
                return i;
            }
             i++;
            if(i > (sizeof((FNT_GB16 *)GBHZ_16) / sizeof(FNT_GB16) - 1))  /* 搜索下标约束 */
            {
                break;
            }
        }
        return 0;
    }
    /*****************************************************************************
    ** 函数名称: WriteString
    ** 功能描述: 在指定位置开始显示一个字符串和一串汉字
                                    支持自动换行
    ** 作   者: FXL
    ** 日   期: 20101206
    *****************************************************************************/   
    void WriteString(u16 x0, u16 y0,u8 *pcStr, u16 color)
    {
        u16 usIndex;
        u16 usWidth = 0;
        FNT_GB16 *ptGb16 = 0;

        ptGb16 = (FNT_GB16 *)GBHZ_16;  
        while(1)
        {
            if(*pcStr == 0)
            {
                break;                          /* 字符串结束 */
            }      
        x0 = x0 + (usWidth);                  /* 调节字符串显示松紧度*/
        if(*pcStr > 0x80)                     /* 判断为汉字*/此处需要注意:判断汉字与这符的标志,0X80。为什么呢?这个和汉字的诞生有关,也可以通过查阅汉字内码,找到字符和汉字的不同点。
            {
                if((x0 + 16) > LCD_W)            /* 检查剩余空间是否足够 */
                {
                    x0 = 0;
                    y0 = y0 + 16;                /* 改变显示坐标 */
                     if(y0 > LCD_H)              /* 纵坐标超出 */
                    {
                          y0 = 0;
                    }
                }
                usIndex = findHzIndex(pcStr);      /*找到汉字对应头部*/
                usWidth = WriteOneHzChar((u8 *)&(ptGb16[usIndex].Msk[0]), x0, y0, color);
                                                /*显示字符*/(此处注意,传入的字体数据,以指针的形式,传递给下一个调用函数的)
                pcStr += 2;
            }
        else
       {                                   /* 判断为非汉字  */
          if (*pcStr == '\r')                   /* 换行   */
           {
               y0 = y0 + 16;                 /* 改变显示坐标 */
               if(y0 > LCD_H)               /* 纵坐标超出 */
               {
                   y0 = 0;
               }
               pcStr++;
               usWidth = 0;
               continue;
            }
           else if (*pcStr == '\n')               /* 对齐到起点*/
           {
                  x0 = 0;
                  pcStr++;
                  usWidth = 0;
                  continue;
           }
          else
          {
               if((x0 + 8) > LCD_W)          /* 检查剩余空间是否足够  */
               {
                                                     x0 = 0;
                  y0 = y0 + 16;             /* 改变显示坐标 */
                  if(y0 > LCD_H)           /* 纵坐标超出 */
                  {
                              y0 = 0;
                  }
               }
               usWidth = WriteOneASCII((u8 *)&ASCII_1608[(*pcStr - 0x20)][0], x0, y0, color); /* ASCII码表21H的值对应区位码3*/                                    
                    pcStr += 1;
                }
            }
        }                                                                                                            
    }

    在对应的取字模库中取出字库数据,并打印出来,是在下面这个函数中实现的。

    /*****************************************************************************
    ** 函数名称: WriteOneHzChar
    ** 功能描述: 显示一个指定大小的汉字
    ** 作   者: FXL
    ** 日   期: 20101206
    *****************************************************************************/
    u16 WriteOneHzChar(u8 *pucMsk, u16 x0, u16 y0, u16 color)
    {
          u16 i,j;
        u16 mod[16];          /* 当前字模 */(此处注意,这也就是建的一个暂存区,把我们刚刚取模件取出来的数据,放到这里面,然后一个点一个点对应打印)
        u16 *pusMsk;            /* 当前字库地址*/
          u16 y;

          pusMsk = (u16 *)pucMsk;
        for(i=0; i<16; i++)         /* 保存当前汉字点阵式字模*/
          {
            mod = *pusMsk++;  /* 取得当前字模,半字对齐访问   */
            mod = ((mod & 0xff00) >> 8) | ((mod & 0x00ff) << 8);/* 字模交换高低字节(为了显示需要)*/
          }
          y = y0;
        for(i=0; i<16; i++)                     /* 16行*/
          {
    #ifdef __DISPLAY_BUFFER        /* 使用显存显示  */
         for(j=0; j<16; j++)                 /* 16列  */
            {
                if((mod << j)& 0x8000)       /* 显示字模  */
                {
                      DispBuf[240*(y0+i) + x0+j] = color;
                }
            }
    #else                           /* 直接显示  */
          LCD_SetCursor(x0, y);            /* 设置写数据地址指针  */
          LCD_WriteRAM_Prepare();        /*开始写入GRAM        */   
          for(j=0; j<16; j++)                /* 16列      */
             {
                            if((mod << j) & 0x8000)     /* 显示字模  */
                 {
                                              LCD_WriteRAM(color);
                  }
             else
             {
                    LCD_WriteRAM(Black);   /* 用读方式跳过写空白点的像素   */
              }
            }
            y++;
    #endif
        }
      return (16);                           /* 返回16位列宽 */
    }


    最后效果图如下:
    图片11.png
    硬件平台:红龙103
    程序: 【15】LCD—红龙显示汉字测试.rar (1.28 MB, 下载次数: 66)
    图片6.png

    评分

    参与人数 1声望 +1 与非币 +2 收起 理由
    wbsouth + 1 + 2

    查看全部评分

    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2014-8-2 09:36
  • 签到天数: 45 天

    连续签到: 1 天

    [LV.5]常住居民I

    发表于 2014-6-25 11:45:00 | 显示全部楼层
    介绍的挺详细的
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2014-10-28 08:57
  • 签到天数: 3 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2014-6-25 14:02:43 | 显示全部楼层
    好资料!楼主无私噻!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2014-7-24 09:24
  • 签到天数: 38 天

    连续签到: 1 天

    [LV.5]常住居民I

     楼主| 发表于 2014-6-26 08:51:42 | 显示全部楼层
    自己支持一下!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    郁闷
    2014-7-1 10:15
  • 签到天数: 4 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2014-6-26 09:12:12 | 显示全部楼层
    步骤很详细,值得参考学习。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2016-11-16 11:50
  • 签到天数: 19 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    发表于 2014-6-27 10:02:24 | 显示全部楼层
    介绍字库的多,介绍字模的少!很适合初学者!顶楼主!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2018-7-19 09:51
  • 签到天数: 17 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    发表于 2014-6-27 10:20:34 | 显示全部楼层
    没看明白程序是怎么判断汉字与字符的
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2014-7-5 14:07
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2014-6-27 11:21:36 | 显示全部楼层
    楼主,那字库显示什么时候发啊?期待哦!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2014-7-24 09:24
  • 签到天数: 38 天

    连续签到: 1 天

    [LV.5]常住居民I

     楼主| 发表于 2014-6-27 11:58:21 | 显示全部楼层
    如果是汉字,最高bit位为1,ASCII码字符值都小于0x80,而汉字的字符是0X80以上的,看下图

    1212.jpg



    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2014-7-24 09:24
  • 签到天数: 38 天

    连续签到: 1 天

    [LV.5]常住居民I

     楼主| 发表于 2014-6-27 12:01:02 | 显示全部楼层
    冰雪 发表于 2014-6-27 11:21
    楼主,那字库显示什么时候发啊?期待哦!

    谢谢支持!   字库的还在筹备,我看有人发了,也可以参考这一个帖子
    https://www.cirmall.com/bbs/thread-34575-1-1.html

    我的或许发,或许不发,看字模效果。。。
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-11-25 03:55 , Processed in 0.201552 second(s), 35 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.