📄 5.txt
字号:
wricmd( 0x10 | (xdot >> 4 ));
wricmd(0xe0);
for(i=0;i<16;i++) //显示上半个汉字
{
wridata(hzdata[i]);
}
wricmd(0xee);
wricmd( 0xb0+cursor.y+1);
wricmd(xdot & 0x0f);
wricmd( 0x10 | (xdot >> 4 ));
wricmd(0xe0);
for(;i<32;i++) //显示下半个汉字
{
wridata(hzdata[i]);
}
wricmd(0xee);
}
*****************************************/
这个程序的作用就是在当前光标位置显示一个16*16 汉字或者全角字符。入口参数ch1表示该汉字的区码,入口参数ch2表示位码。
说到这里可能有一些朋友不理解了。下面我来讲一下。前面已经介绍了汉字库的一些知识,虽然汉字库种类繁多,但都是按照区位的顺序排列的。前一个字节为该汉字的区号,后一个字节为该字的位号。每一个区记录94个汉字,位号则为该字在该区中的位置。因此,汉字在汉字库中的具体位置计算公式为:94*(区号-1)+位号-1。减1是因为数组是以0为开始而区号位号是以1为开始的。这仅为以汉字为单位该汉字在汉字库中的位置,那么,如何得到以字节为单位得到该汉字在汉字库中的位置呢?只需乘上一个汉字字模占用的字节数即可,即:(94*(区号-1)+位号-1)*一个汉字字模占用字节数,而按每种汉字库的汉字大小不同又会得到不同的结果。以16*16点阵字库为例,计算公式则为:(94*(区号-1)+(位号-1))*32。汉字库文该从该位置起的32字节信息即记录了该字的字模信息。
Ok,明白了这些,这个程序就很好理解了,其实质是和我们分析的上一个显示ASC字符的程序是差不多的,首先除了定义,就是寻址汉字在flash中的物理位置。
由于在中文环境下,输入的是汉字的内码,我们必须将之转换成区位码,算出偏移量,从字库中找到对应的汉字,将其字模显示即可。内码转换成区位码方法如下:
qh=c1-0xa0 wh=c2-0xa0
其区位码就是:
qw=qh*0xff+wh
该汉字在字库中离起点的位置是:
offset=(94*(qh-1)+(wh-1))*32L??????????????
其他步骤和上一个函数几乎一模一样,就不多废话了~。
/*****************************************
void setcursor(uchar x, uchar y)
{
if ( x<= LCD_MAX_X )
cursor.x= x;
else
cursor.x= LCD_MAX_X;
if ( y<= LCD_MAX_Y )
cursor.y= y;
else
cursor.y= LCD_MAX_Y-1;
}
*****************************************/
再看接下来的这个程序。这个程序的作用是设置光标位置,以8×8点阵为一个光标单位,入口参数表示x方向和y方向光标位置。LCD_MAX_X和LCD_MAX_Y的含义和计算公式在刚开始的时候我们就已经说过了。至于这里为什么是LCD_MAX_Y-1,前面已经说了一个字符或者汉字都应该由两个page来提供数据,现在我需要在7,8页显示东西,那么我应该是把纵坐标点设置到7页吧?呵呵,其实点破就很简单了。
/*****************************************
void lcdstring( uchar *pst)
{
while ( *pst != 0 )
{
if ( *pst < 0x80 ) //小于0x80是字符
{
if (*pst==0x0a) setcursor(0, cursor.y+2); //处理回车换行
else if (*pst== 0x0d) setcursor(0, cursor.y );
else
{
show_asc(*pst); //显示ASC字符
cursor.x++;
if (( cursor.x > LCD_MAX_X )&& (*(pst+1)!=0x0a)){cursor.x=0;cursor.y=cursor.y+2;}
}
pst++; //下一个要显示的字符
}
else //大于0x80是汉字
{
if ( cursor.x>= LCD_MAX_X )
{
show_asc(0x20); //一行的尾部只有半个汉字位置的处理,加一个空格,在下一行开始显示
cursor.x=0;cursor.y=cursor.y+2;
if (cursor.y> LCD_MAX_Y) cursor.y=0; //
}
show_hz(*pst, *(pst+1)); //显示一个汉字
cursor.x+=2;
pst+=2;
if ((cursor.x> LCD_MAX_X)&& (*(pst+1)!=0x0a)){cursor.x=0;cursor.y=cursor.y+2;}
}
if ( cursor.y> LCD_MAX_Y ){ cursor.x=0;cursor.y=0;return;}
}
}
*****************************************/
这个程序呢,也就是我们这篇文章介绍的内容的中心程序!地位重要吧。那么他的作用是什么呢?就是在当前光标位置显示字符串拉。入口参数就是要显示的字符串。更关键的是同时也显示汉字!。什么?你还是没有理解到这个东西的好处?这样说吧,只要你的程序中包含我们所介绍的这些程序,那么在应用程序中,我们如果想让lcd显示“风”,那么我们就直接lcdstring(“风”)就行了。哈哈,这么神奇的功能,实现起来其实是很简单的拉。下面我门就一起来分析分析这个函数。
首先是字符处理函数。前面的while,if语句中的内容都很好理解,大家看程序注释就行了,这里我要说的是if (*pst==0x0a) setcursor(0, cursor.y+2); 这句是处理回车换行,为什么?因为0x0a在asc码表中就是表示换行的,而接下来的0x0d是表示回车的,还有后来汉字显示需要用的0x20表示space。呵呵,因为我当时看的时候半天没有找到asc码表,为了避免让大家也都去找,这里直接说出来了。为什么是cursor.y+2呢?相信大家已经知道答案了。什么?你不知道?ohyeah,请看上一页~
这里有必要再讲讲cursor.x++;这句。为什么是cursor.x自增一?横坐标一个字符不是占用8个点么?千万不要忘了,横坐标的点是用xdot表示的。计算公式是什么呢?xdot=cursor.x*8;。明白了吧?
接下来就是汉字处理部分。其流程和前一部分完全一样,只不过cursor.x和pst都是自增2,原因当然是因为汉字是由区码和位码决定的,因此占用的字节数是字符的两倍~呵呵,你看看显示汉字的语句不是show_hz(*pst, *(pst+1))么?
到这里,我们的学习历程就基本结束了。整个程序的精华已经给大家介绍完了。当然最后还剩两个“在当前光标以十进制方式在液晶上显示一个字节的值”和“在当前光标显示一个ASC字符”两个函数,不过非常简单,这里只是作为附录附在后面,有兴趣的朋友可以试试自己分析一下。
这只是许多种lcd控制器其中一种的使用方法。但是不要怕,我这几天又看了看其他的驱动控制器,原理其实是一样的,只不过是实现功能的程序可能不同,所以最关键的还是要理解思想。思想理解了,学别的类似东西也就相通了。
希望看到这个文章各位都能获得一些知识和心得。如果能够帮助你,将是我莫大的荣幸。
附录:
//**********************************************
//在当前光标以十进制方式在液晶上显示一个字节的值
//入口:要显示的值
lcddigit(uchar ch)
{
uchar i[4];
i[0]=(0x30+ch/100);
i[1]=(0x30+(ch%100)/10);
i[2]=(0x30+ch%10);
i[3]=0; //添加结束符号
lcdstring(i);
}
//***********************************
//在当前光标显示一个ASC字符
//入口:要显示的字符
lcdchar(uchar ch)
{
uchar i[2];
i[0]=ch;
i[1]=0; //添加结束符号
lcdstring(i);
}
--------------------------------------------------------------------------------
copyright by 风雷
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -