本帖最后由 haha_haha 于 2014-6-25 11:40 编辑
很多人在用TFT屏做显示时,遇到一个汉字显示问题,到底是做放个字库显示还是汉字取模显示呢?
一、 做字库前的分析 当拿到项目要求后,如果其中一段,看到有汉字显示的要求时,就不得不考虑汉字的问题了。 如果使用字库,根据使用字数多少,可有如下划分: A、用量很多。基本要用到全部汉字。此时要考虑自己手中存储资源,是否有足够的空间放这些字模(即,内部,外部FALSH存储)。 1、如果空间充足,可以做字库到FLASH中(有例程SD卡做字库,字库大小,根据取模大小不同,有几百K到几十M不等),把SD卡的字库文件读出来,存储到FALSH(W26Q16)中。 2、空间少,可以外买字库芯片(当然啦,产品成本要增加)。 B、用量很少,可以自己取模(比如,二三十个汉字,用字库太浪费FLASH了),那么下面写的流程,即为单个取模流程。
二、汉字取模 第一步:总结要用到的所有汉字,比如只有三个字:你好!; 第二步:打开取字模软件。例如:LCD点阵提取工具;
第三步:取字模。
注意上面提示:右键也可以选择字体。
以上面这个字体大小为例,点击确定。
注意:在左下脚,结束文字输入请按CTRL+ENTER组合键。
取模生成的字,如上图所示。下面我们使其换成代表汉字的代码(如果此处无法理解,google查一下“点阵”,很快都能明白,汉字的显示是一个一个点组合成的)。
左边选框,有一个取模方式,选C51格式,会输出上图字模数据。
拷贝生成的字模区,我们生成的字体“你”,算是完成了。
三、 软件的分析 我假设,屏驱动已好,你也已经知道如何打点了。
在写程序之前,我们把上面三个字的取模数据,放到字库文件中,截图如下:
要清楚,放的位置,在Font_lib.H中。
放入上面字模数据后,如何调用他们呢,我们在main.c主程序中加放这一句话 WriteString(10,150,"你好!",Red); 这句话的意思:在X轴10,Y轴150的地方作为起始点,打出字样“你好!”,字体色为Red红色。如下图
下面我们进入程序分析: 大致流程为, 第一步:找到汉字头部; 第二步:然后在对应的取字模库中取出字库数据; 第三步:取出相应的汉字,然后一个点一个点打印出来。 程序如下:找到汉字头部 /***************************************************************************** ** 函数名称: findHzIndex ** 功能描述: 查找汉字在自定义字库中的索引 hz 指向汉字(机内码)的指针 ** 作 者: FXL ** 日 期: 2010年12月06日 *****************************************************************************/ 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 ** 日 期: 2010年12月06日 *****************************************************************************/ 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 ** 日 期: 2010年12月06日 *****************************************************************************/ 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)
|