玩转12864液晶显示图片,画点,画任意直线
通过上一篇的实验,相信大家都掌握了显示字符的基本用法。 下面我们来看一下12864液晶更高级的用法。 首先是它的绘图功能。
让我们先来显示一整副的图片吧,也就是128x64大小。
在使用绘图功能时,先要打开扩充指令集,然后再打开绘图功能。接着就是送数据显示了。这里我们首先要弄明白ST7920的显示坐标关系。其显示坐标如下。
从图中可以看出,X方向共有8个字(16个字节)Y方向共有0~31 行 分为上下两个屏。 弄懂了之后我们就可以依照此坐标来显示一整屏的图片了。 随便用一个图片的提取转换软件,讲一副126X64大小的图片转换成字节数据,总共字节大小为128*64/8 = 1024个字节。
下面我们来看看这个显示整屏图像的函数
void v_Lcd12864DrawPicture_f( unsigned char code *pPicture ) {
unsigned char i, j, k ;
for( i = 0 ; i < 2 ; i++ )//分上下两屏写
{
for( j = 0 ; j < 32 ; j++ )//行 {
v_Lcd12864SendCmd_f( 0x80 + j ) ;//写Y坐标(第几行上写) if( i == 0 ) //写X坐标 (判断在那一屏上) {
v_Lcd12864SendCmd_f( 0x80 ) ; } else {
v_Lcd12864SendCmd_f( 0x88 ) ; }
for( k = 0 ; k < 16 ; k++ ) //写一整行数据(一行共16个字节,合八个字符) {
v_Lcd12864SendData_f( *pPicture++ ) ; } } }
v_Lcd12864SendCmd_f( 0x30 ) ;//基本功能设置 }
看看效果图片如下:显示一个人的图像
下面来看看如何在任意一个位置显示或者是擦除一个点
对于12864这种二值显示屏来说,其显示状态无外乎显示和不显示一个点这两种状态。而在任意位置画点,是我们随心所欲的画线,画圆,画矩形的等GUI函数的基础。 为了让这个位置有一个参考点,我们有必要定义一个坐标系 在这里,我定义的坐标系如下
0,0------------------------------------127,0 | | | | | |
| | 0,63----------------------------------127,63
0,0代表屏幕的左上角,127,63代表屏幕的右下角。 对于屏幕上面任意一个点,如果我们想要点亮它,必须先读出此点的状态,然后再修改该点,最后送出去,即 读----修改----写。按照这个步骤,然后再运用C语言中的位操作运算符 可以很方便的完成画点的函数。
由于画点函数涉及到读ST7920内部RAM的操作,因此,我们必须先要完成这个读数据的函数
具体实现过程如下:
unsigned char u8_Lcd12864ReadByte_f( void ) {
unsigned char byReturnValue ; v_Lcd12864CheckBusy_f() ;
io_LCD12864_DATAPORT = 0xff ; SET_DATA SET_READ CLR_EN SET_EN
byReturnValue = io_LCD12864_DATAPORT ; CLR_EN
return byReturnValue ; }
然后是画点的函数,其实现过程如下:
void v_Lcd12864DrawPoint_f( unsigned char X, unsigned char Y, unsigned char Color ) {
unsigned char Row , Tier , Tier_bit ; unsigned char ReadOldH, ReadOldL ; v_Lcd12864SendCmd_f( 0x34 ) ; v_Lcd12864SendCmd_f( 0x36 ) ; Tier = X >> 4 ; Tier_bit = X & 0x0f ; if( Y < 32 ) {
Row = Y ; } else {
Row = Y - 32 ; Tier += 8 ; }
v_Lcd12864SendCmd_f( Row + 0x80 ) ;
v_Lcd12864SendCmd_f( Tier + 0x80 ) ; u8_Lcd12864ReadByte_f() ;
ReadOldH = u8_Lcd12864ReadByte_f() ; ReadOldL = u8_Lcd12864ReadByte_f() ; v_Lcd12864SendCmd_f( Row + 0x80 ) ; v_Lcd12864SendCmd_f( Tier + 0x80 ) ; if( Tier_bit < 8 ) {
switch( Color) {
case 0 : ReadOldH &=( ~( 0x01 << ( 7 - Tier_bit ))) ; break ; case 1 : ReadOldH |= ( 0x01 << ( 7 - Tier_bit )) ; break ; case 2 : ReadOldH ^= ( 0x01 << ( 7 - Tier_bit )) ; break ; default : break ; }
v_Lcd12864SendData_f( ReadOldH ) ; v_Lcd12864SendData_f( ReadOldL ) ; } else {
switch(Color) {
case 0 : ReadOldL &= (~( 0x01 << ( 15 - Tier_bit ))) ; break ; case 1 : ReadOldL |= ( 0x01 << ( 15 - Tier_bit )) ; break ; case 2 : ReadOldL ^= ( 0x01 << ( 15 - Tier_bit )) ; break ; default : break ; }
v_Lcd12864SendData_f( ReadOldH ) ; v_Lcd12864SendData_f( ReadOldL ) ; }
v_Lcd12864SendCmd_f( 0x30 ) ; }
有了画点的函数之后,一切似乎都变得简单了,因为点是一切复杂图形的最基本的组成单位。 下面我们就在这个画点函数的基础上,实现画水平线和垂直线的两个函数。 画水平线:
void v_Lcd12864DrawLineX_f( unsigned char X0, unsigned char X1, unsigned char Y, unsigned char Color ) { unsigned char Temp ; if( X0 > X1 ) {
Temp = X1 ; X1 = X0 ; X0 = Temp ; }
for( ; X0 <= X1 ; X0++ )
v_Lcd12864DrawPoint_f( X0, Y, Color ) ; }
画垂直线:
void v_Lcd12864DrawLineY_f( unsigned char X, unsigned char Y0, unsigned char Y1, unsigned char Color ) {
unsigned char Temp ; if( Y0 > Y1 ) {
Temp = Y1 ; Y1 = Y0 ; Y0 = Temp ; }
for(; Y0 <= Y1 ; Y0++)
v_Lcd12864DrawPoint_f( X, Y0, Color) ; }
下面我们就用以上两个画线函数,在液晶屏上面画一个表格出来 v_Lcd12864DrawLineX_f( 0, 127 , 0, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 7, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 15, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 23, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 31, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 39, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 47, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 55, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 0, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 15, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 31, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 47, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 63, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 79, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 95, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 111, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 127, 0 , 63, 1 ) ; 看看显示效果