您的位置:首页 > 其它

LCD-中文显示-超级菜鸟版

2011-01-12 23:05 246 查看
液晶是什么?字模是什么?GBK是什么?gram是什么?HZK16是什么?bin是什么?汉字内码是什么?UNICODE又是什么?..

液晶真是小东西大学问,我是地道的门外汉,一块液晶,一个开发板,显示一个中文字,连个例也没有,好在有网络,从一篇文章里遇到一堆听都没听过的专业词汇,然后在从查找这些词汇的过程中遇到更多的词汇,真是张见识了。

感觉接触一个新事物,难度不在它本身的技术有多复杂,再高深的技术都是靠千千万万个逻辑组建起来的,只要静下心来理,总是能理出点头绪的。倒是一点概念都没有的时候最惶惑。而这个阶段的超级菜鸟也是举步维艰的,很多资料帖子都看不懂(不是似懂非懂,是一点都不懂~~),而一般人又没时间给超级菜鸟把一个个基础的概念解释清楚,更郁闷的是,市面上,海一般的教程资料又不一定合用。最终求助无门,要么望而怯步,放弃,要么硬啃。好在只要是有逻辑的东西,都是能啃的,虽然不好消化,但是绝对比别人告诉自己来得深刻,而且能培养探索新事物的能力。(当然,有时时间紧迫,不容许慢慢消化,还是赶紧求助好心高人的好。)

据说,液晶带中文字库能显示中文,那不带中文字库怎么显示啊?字库又长什么样呢?

static u8 GBK16[32];
unsigned char *Read_One_GBK16(unsigned char *ch)
{
unsigned int temp1;
unsigned char temp2;
unsigned char *p;
p=&GBK16[0];
temp1=*ch;
temp2=*(ch+1); //有个快典网http://bm.kdd.cc/ 能查,查到“歌”字GBK码为:0XB8E8,正好两个字节。
// if(temp1<0x81||temp2<0x40)return 1;//不合法的汉字
temp1-=0xa0; //计算汉字区码 //不懂
temp2-=0xa0; //计算汉字位码
temp1=((INT32U)(94*(temp1-1)+(temp2-1)))*32; //计算汉字在字库中的偏移地址
// sector_offset = temp1/(512/32);//算出要读哪个扇区 933
// byte_offset = (temp1%(512/32))*32;//算出要读扇区的哪个字节 //更不懂了
f_open(&fii,"sys/HZK16.bin", FA_OPEN_EXISTING | FA_READ); //f_open打开了一个“HZK16.bin”的文件啥东东~

f_lseek(&fii,temp1);
f_read(&fii, GBK16, 32, &br);
f_close(&fii);
// GBK_Buffer=buffer;
return p;
}

“Read_One_GBK16”--“读一个GBK”同类的还有unsigned char *Read_One_GBK32(unsigned char *ch),

unsigned char *Read_One_GBK12(unsigned char *ch),

WCHAR *GBKTOUnicode(unsigned char *ch,啥是GBK啊?

百科说:“GBK: 汉字国标扩展码,基本上采用了原来GB2312-80所有的汉字及码位,并涵盖了原Unicode中所有的汉字20902,总共收录了883个符号, 21003个汉字及提供了1894个造字码位。 Microsoft简体版中文Windows 95就是以GBK为内码,又由于GBK同时也涵盖了Unicode所有CJK汉字,所以也可以和Unicode做一一对应。”

( 是不是可以理解为GBK是汉字在库中的一个编号?)

bin:百科说:“ bin (binary)其中文意思既是:二进制,二进制文件,其用途依系统或应用而定 。

  也就是说,一般来讲是机器代码,汇编语言编译后的结果,(DOS下汇编语言编译后与.com文件相类似),用debug、WINHEX,U_EDIT等软件打开(通常不一定能看得懂是些什么除非精通汇编语言)

  所有的文件, 无论后缀名是什么, 一律分为两种格式. text 和 binary.

  一种文件格式binary的缩写。一个后缀名为.bin的文件, 只是想表明它是binary格式.,但并不表明它与某种应用程序有必然的联系性”

(下了一个WINHEX,的确能打开^^,原来每个字对应的就是一堆数组,用网上下载的字模生成工具,生成也是一样的)

网友说:“以指定的方式建立字库 字库分3类
(1) 常用可见ASCII字 0-9, A-Z及a-z,各种符号*#?()等 数字字库0-9 ,这是XY长度为6*8点的
(2) 半角字符 0-9,A-Z 也是我们常用的数字和英文字符显示方式,占半个汉字大小,是8*16点。半角字符,就是指占汉字一一半大小
(3) 汉字字库常用HZK16(6763个汉字) 显然这是16*16的, 标准的全角字符
一般应用不建议采用第(1)项来显示数字与字母,一是字体太小,二是不便于和汉字混排,不好对齐。”



那这样就明了了,没有字库的话只要用工具(比如PCtoLCD2002.exe)把具体的字的“字模”(就是点点排成的数组),给函数,就不用上面的函数读库里的GBK了。(工具要选好,不然摸半天都摸不出来)

},/*"歌"字,16*16*/

u8 song[]= {0x01,0x00,0x5D,0x78,0x55,0x48,0x55,0x48,0x5D,0x7A,0x41,0x01,0x7F,0xFE,0x45,0x02,
0x09,0x04,0x30,0x18,0xD7,0xE0,0x10,0x10,0x14,0x0C,0x18,0x07,0x10,0x02,0x00,0x00}

void Lcd_WriteChinese(u8 x,u8 y,u16 x_offset,u16 y_offset,u16 CharColor,u16 CharBackColor,u8 *ChineseCode,u8 mode)
{
u8 ByteCounter,BitCounter;
u8 *ChinesePointer;
Lcd_SetBox(x*16,y*16,16,16,x_offset,y_offset);
Lcd_WR_Start();
ChinesePointer=Read_One_GBK16(ChineseCode); //这里用改为:ChinesePointer=&song[0];就可以用了。

for(ByteCounter=0; ByteCounter<32; ByteCounter++)

//这里连续写入了32个字节,那扫描应该是横扫了,而不是下面说的先上半个后下半个,生成字模的时候要注意。
{
for(BitCounter=0;BitCounter<8;BitCounter++)
{
if((*ChinesePointer & (0x80 >> BitCounter)) == 0x00)
{
Set_Rs;
if(!mode)
{
GPIOx->ODR = CharBackColor;//DataToWrite(CharBackColor);
Clr_nWr;
Set_nWr;
}
}
else
{
Set_Rs;
GPIOx->ODR =CharColor; //DataToWrite(CharColor);
Clr_nWr;
Set_nWr;
}
}
ChinesePointer++;
}
Set_Cs;
}

还有个问题,就是数组的存储方式,寄存器存储方式,液晶的扫描方式,怎一个乱字了得~~

以下来自http://www.ourdev.cn的huasoft网友的帖子:





取出汉字字库向LCD写屏的方式
液晶NOKIA5110的X,Y概念及写屏方式:
液晶5110由84点*48点组成。 可以看到,最多显示的半角字符是10*6个, 最多显示的汉字是5*3个

液晶5110的规格书上是这样描述它的写入坐标概念的,首先,每次写入命令是写一个竖着的8个bit即一个字节,这是它的一个最基本的写入元单元。(写入时先写高位,这一点对掌握整体概念不重要,先不讨论)。以这样的元单元为计数,屏幕整个被分成了84*6 个这样的元单元。

NOKIA5110的LCD的XY坐标概念




写入一个汉字“一”,字模如下
/*-- 文字: 一 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
写入过程的函数一般是这样的:
LCD_set_XY(row*8, page);// 列,页
for(i=0; i<16;i++)
{
LCD_write_byte(pgm_read_byte(hanzi+c*32+i),1);
}

LCD_set_XY(row*8, page+1);// 列,页
for(i=16; i<32;i++)
{
LCD_write_byte(pgm_read_byte(hanzi+c*32+i),1);
}
写入示意图如下:




NOKIA5110LCD写入汉字一的过程

好了,现在问题来了,HZK16和 我们在5110LCD上用的字库是不同的组织方式,一个先行后列, 一个先上半部后下半部。如何转换?

(我就显示一个字,直接用工具改字模更方便~这里学习下前辈改扫描方式的程序)

-----------------------------------------------------------
为了让NOKIA5110直接用hzk16字库形式而不需要转换, 我们直接把hzk16转成适合Nokia5110的扫描方式,
关键代码段
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//2.将标准hzk16.bin的16*16的先行后列字模转换成NOKIA5110屏用的先刷汉字上半部分16列,再刷下半部分16列的方式(见文档)
//add hzk16fornokia5110.bin write routine here
FILE *HZK1 = 0, *HZK2 = 0;
unsigned long offset1 = 0, offset2 =0;

if((HZK1=fopen("hzk16.bin", "rb")) == NULL)
{
printf("Can't Open hzk16.bin/n");
getchar();
return 0;
}
if((HZK2=fopen("hzk16fornokia5110.bin", "wb")) == NULL)
{
printf("Can't Open hzk16fornokia5110.bin/n");
getchar();
return 0;
}

offset1=0;

unsigned char mat1[2][16],mat2[2][16];
//int i,j,k,m;
while( !feof(HZK1) )
{
fseek(HZK1, offset1, SEEK_SET);
fread(mat1, 32, 1, HZK1);

//mat1-->mat2
for(i=0;i<2;i++)
{
for(j=0;j<8;j++)
{
for(k=0;k<8;k++) //bit
{
//mat2[0][j].bit[k]= mat1[0][j*2].bit[7-k];
if( bit_isset(mat1[i][k*2],(7-j))==1 )
{
bit_set(mat2[i][j],k);
}
else
{
bit_clr(mat2[i][j],k);
}
}
}

for(j=0;j<8;j++)
{
for(k=0;k<8;k++) //bit
{

//mat2[0][j+8].bit[k]= mat1[0][j*2+1].bit[7-k];
if( bit_isset(mat1[i][k*2+1],(7-j))==1)
{
bit_set(mat2[i][j+8],k);
}
else
{
bit_clr(mat2[i][j+8],k);
}
}
}

}//for(i=0;i<2;i++)

//write mat2
printf("write offset: %ld/n",offset1);
fseek(HZK2, offset1, SEEK_SET);
fwrite(mat2,32,1,HZK2);
offset1+=32;
}//while

printf("I find the feof()!=0!/n");

fclose(HZK1);
fclose(HZK2);
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

在函数里Lcd_WriteChinese用到Lcd_SetBox(x*16,y*16,16,16,x_offset,y_offset) ,内容如下,

void Lcd_SetBox(u8 xStart,u16 yStart,u8 xLong,u16 yLong,u16 x_offset,u16 y_offset)
{

#if ID_AM==000
Lcd_SetCursor(xStart+xLong-1+x_offset,yStart+yLong-1+y_offset);

#elif ID_AM==001
Lcd_SetCursor(xStart+xLong-1+x_offset,yStart+yLong-1+y_offset);

#elif ID_AM==010
Lcd_SetCursor(xStart+x_offset,yStart+yLong-1+y_offset);

#elif ID_AM==011
Lcd_SetCursor(xStart+x_offset,yStart+yLong-1+y_offset);

#elif ID_AM==100
Lcd_SetCursor(xStart+xLong-1+x_offset,yStart+y_offset);

#elif ID_AM==101
Lcd_SetCursor(xStart+xLong-1+x_offset,yStart+y_offset);

#elif ID_AM==110
Lcd_SetCursor(xStart+x_offset,yStart+y_offset);

#elif ID_AM==111
Lcd_SetCursor(xStart+x_offset,yStart+y_offset);

#endif

LCD_WR_REG(0x0050,xStart+x_offset);//水平 GRAM起始位置
LCD_WR_REG(0x0051,xStart+xLong-1+x_offset);//水平GRAM终止位置
LCD_WR_REG(0x0052,yStart+y_offset);//垂直GRAM起始位置
LCD_WR_REG(0x0053,yStart+yLong-1+y_offset);//垂直GRAM终止位置
}

void Lcd_SetCursor(u8 x,u16 y)
{
LCD_WR_REG(0x20,x);
LCD_WR_REG(0x21,y);
}

函数名:Lcd块选函数
功能:选定Lcd上指定的矩形区域

应该是控制显示区域和定位的吧,现在汉字已经可以显示了,但是,是从右到左,而且x轴y轴混了,改了一下也没成功,咋整啊~~

好像位图显示也是镜像的,什么原因呢?~~

可以把字库和位图放在sd卡里,液晶从里面读不?跟gram有什么关系啊?(gram是什么~)

ILI9325是什么?跟用软件从屏中读出来的DeviceCode有什么关系呢?

液晶定时变暗,然后关闭,看屏的时候再用按键唤醒,跟手机屏幕一样,能么?

好像触摸屏这块儿也挺庞大的~

问题多多啊,菜鸟的道路很艰辛,但也很充实,菜并快乐着~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: