液晶是什么?字模是什么?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-中文显示-超级菜鸟版_buffer

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

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

NOKIA5110的LCD的XY坐标概念

LCD-中文显示-超级菜鸟版_byte_02 
写入一个汉字“一”,字模如下
/*--  文字:  一  --*/
/*--  宋体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);
}
写入示意图如下:

LCD-中文显示-超级菜鸟版_汇编_03
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有什么关系呢?

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

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

 

问题多多啊,菜鸟的道路很艰辛,但也很充实,菜并快乐着~