35回答

1收藏

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

 

STMCU STMCU 12134 人阅读 | 35 人回复 | 2014-06-25

本帖最后由 haha_haha 于 2014-6-25 11:40 编辑

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

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

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


第三步:取字模。



注意上面提示:右键也可以选择字体。


以上面这个字体大小为例,点击确定。


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

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


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


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

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

在写程序之前,我们把上面三个字的取模数据,放到字库文件中,截图如下:

要清楚,放的位置,在Font_lib.H中。

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



下面我们进入程序分析:
大致流程为,
第一步:找到汉字头部;
第二步:然后在对应的取字模库中取出字库数据;
第三步:取出相应的汉字,然后一个点一个点打印出来。
程序如下:找到汉字头部
/*****************************************************************************
** 函数名称: 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位列宽 */
}


最后效果图如下:

硬件平台:红龙103
程序:
【15】LCD—红龙显示汉字测试.rar (1.28 MB, 下载次数: 66)

我会分享更多资料,请先顶贴支持!

图片6.png (28.61 KB, 下载次数: 112)

图片6.png

评分

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

查看全部评分

红龙407 红龙103
http://openmcu.taobao.com
分享到:
回复

使用道具 举报

回答|共 35 个

倒序浏览

沙发

jeanson-363338

发表于 2014-6-25 11:45:00 | 只看该作者

介绍的挺详细的
板凳

小-北

发表于 2014-6-25 14:02:43 | 只看该作者

好资料!楼主无私噻!
地板

wbwest

发表于 2014-6-26 08:51:42 | 只看该作者

自己支持一下!
红龙407 红龙103
http://openmcu.taobao.com
5#

wbsouth

发表于 2014-6-26 09:12:12 | 只看该作者

步骤很详细,值得参考学习。
TI玉兔LM3S9B96开发板,金龙STM32F107开发板
http://shop36995246.taobao.com/
6#

fengxianglu

发表于 2014-6-27 10:02:24 | 只看该作者

介绍字库的多,介绍字模的少!很适合初学者!顶楼主!
7#

shanji

发表于 2014-6-27 10:20:34 | 只看该作者

没看明白程序是怎么判断汉字与字符的
8#

冰雪

发表于 2014-6-27 11:21:36 | 只看该作者

楼主,那字库显示什么时候发啊?期待哦!
9#

wbwest

发表于 2014-6-27 11:58:21 | 只看该作者

如果是汉字,最高bit位为1,ASCII码字符值都小于0x80,而汉字的字符是0X80以上的,看下图





红龙407 红龙103
http://openmcu.taobao.com
10#

wbwest

发表于 2014-6-27 12:01:02 | 只看该作者

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

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

我的或许发,或许不发,看字模效果。。。
红龙407 红龙103
http://openmcu.taobao.com
您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

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