钻石会员
  
主题
帖子
积分10261
阅读权限50
注册时间2012-5-17
最后登录1970-1-1
在线时间 小时
|

楼主 |
发表于 2013-8-19 21:04
|
显示全部楼层
汉字在液晶上的显示原理与前面显示字符的是一样的。汉字在液晶上的显示其实就是一些点的显示与不显示,这就相当于我们的笔一样,有笔经过的地方就画出来,没经过的地方就不画。所以要显示汉字,我们首先要知道汉字的点阵数据,这些数据可以由专门的软件来生成。只要知道了一个汉字点阵的生成方法,那么我们在程序里面就可以把这个点阵数据解析成一个汉字。
知道显示了一个汉字,就可以推及整个汉字库了。汉字在电脑里面存储不是以点阵数据的形式存储的(否则那占用的空间就太大了),而是以内码的形式存储的,就是GB2312/GBK等这几种的一种(最常用的是哪个我也不清楚,但是可以肯定是我们装的简体XP,汉字一般都能用GBK码或GB2312码解析),每个汉字对应着一个内码,在知道了内码之后再去字库里面查找这个汉字的点阵数据,然后在液晶上显示出来。这个过程我们是看不到,但是计算机是要去执行的。
单片机要显示汉字也与此类似:汉字内码(GBK/GB2312)->查找点阵库->解析->显示。
所以只要我们有了整个汉字库的点阵,就可以把电脑上的文本信息在单片机上显示出来了。这里我们要解决的最大问题就是制作一个与汉字内码对的上号的汉字点阵库。而且要方便单片机的查找。每个GBK码由2个字节组成,第一个字节为0X81~0XFE,第二个字节分为两部分,一是0X40~0X7E,二是0X80~0XFE。其中与GB2312相同的区域,字完全相同。
我们把第一个字节代表的意义称为区,那么GBK里面总共有126个区(0XFE-0X81+1),每个区内有190个汉字(0XFE-0X80+0X7E-0X40+2),总共就有126*190=23940个汉字。我们的点阵库只要按照这个编码规则从0X8140开始,逐一建立,每个区的点阵大小为每个汉字所用的字节数*190。这样,我们就可以得到在这个字库里面定位汉字的方法:
在stm32中可以这样调用
当GBKL<0X7F时:Hp=((GBKH-0x81)*190+GBKL-0X40)*(size*2);
当GBKL>0X80时:Hp=((GBKH-0x81)*190+GBKL-0X41)*(size*2);
其中GBKH、GBKL分别代表GBK的第一个字节和第二个字节(也就是高位和低位),size*2代表汉字字体的大小 比如16*16点阵的字体则为16*2=32 个字节,Hp则为对应汉字点阵数据在字库里面的起始地址。
这样我们只要得到了汉字的GBK码,就可以显示这个汉字了。从而实现汉字在液晶上的显示。
不过在51中只支持8位乘法,且乘法结果不允许超过16位,所以在计算地址的时候可以使用循环加法实现乘法用来计算偏移地址!
以下为我之前写的2.8彩屏中读写SPI FLASH 调用中文字库作为汉字显示的程序,可以正常调用显示,大家可以参考下!
unsigned char data flashGB_16[32];
unsigned char X1,Y1;
void Read_test(unsigned long temp) //从指定地址读SPI_flash数据i个并保存到数据缓存区
{
unsigned char i;
SPI_SCK=1;
SPI_CS=0; //使能器件
SPI_WriteByte(0x03); //写读FLASH命令
SPI_Write_add(temp); //写flash地址
for(i=0;i<255;i++) //读数据
{
flashGB_16=SPI_ReadByte();
}
SPI_CS=1;
}
void Display_hzk1(u8 hz_h,u8 hz_l, uint16 color,uint16 backcolor)//hz_h中文字符高8位 hz_l低8位 color 字体的颜色 backcolor 背景颜色
{
u8 i, j,k,msk;
unsigned long temp32,temp16;
temp32=0;
temp16=0;
if(hz_l<0x7f) temp16=(hz_h-0x81)*190+hz_l-0X40;
else if(hz_l>0x80) temp16=(hz_h-0x81)*190+hz_l-0X41;
for(k=0;k<32;k++)
{
temp32+=temp16;
}
SPI_Write_en();
Read_test(temp32);
for(i = 0;i < 16;i++) //字模大小 16*16
{
msk = flashGB_16[i*2]; //codeGB_16[temp] 当前字符数据组位置 Msk联合体数据i指向组中位置
for(j = 0;j < 8;j++)
{
if((msk & 0x80)) Point(X1 + j, Y1 + i, color); //如果最高位为1则写入字符颜色形成字符
else if(backcolor) Point(X1 + j, Y1 + i, backcolor); //如果最高位为0则写入底色形成空白区域
msk <<= 1; //移位一次,依次写入一行8个点数据
}
msk = flashGB_16[i*2+1];
for(j = 0;j < 8;j++)
{
if((msk & 0x80)) Point(X1 + 8+j, Y1 + i, color);
else if(backcolor) Point(X1 + 8+j, Y1 + i, backcolor);
msk <<= 1;
}
}
X1 += 16;
if(X1 == 240)
{
Y1 += 16;
X1 = 0;
if(Y1 == 240)
Y1 = 0;
}
}
void display_hz(u8 *buf, u8 x, u8 y, uint16 color, uint16 backcolor)
{
u8 temp_h=0;
u8 temp_l=1;
X1 = x;
Y1 = y;
while (buf[temp_h])
{
Display_hzk1(buf[temp_h],buf[temp_l] ,color, backcolor);
temp_h +=2;
temp_l=temp_h+1;
}
}
void main ()
{
LCD初始化...
用户程序...
display_16x16hzs("中文显示测试!!!",40, 100,0xf800, 0x3f00);//字符,X坐标,Y坐标,字颜色,背景颜色
用户程序...
}
|
|