当前位置:文档之家› 12864液晶显示图片,画点,画任意直线

12864液晶显示图片,画点,画任意直线

12864液晶显示图片,画点,画任意直线
12864液晶显示图片,画点,画任意直线

玩转12864液晶(2)--显示图片,画点,画任意直线

本帖被红金龙吸味执行加亮操作(2009-07-04)

通过上一篇的实验,相信大家都掌握了显示字符的基本用法。

下面我们来看一下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++ ) //写一整行数据

{

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 ) ;

看看显示效果

怎么样,你的实现了吗?

只能画水平线和垂直线似乎太简单和单调点了。

要是能在任意两点间画一条直线就好了,那样我们就可以做很多事情了。

下面就让我们去实现它!

在这里我们采用Bresenham画线算法,关于这个算法,网上有很多资料,请大家以它为关键字到网上去搜索,在这里就不啰嗦了。

下面是算法的具体实现过程:

void v_Lcd12864DrawLine_f( unsigned char StartX, unsigned char StartY, unsigned char EndX, unsigned char EndY, unsigned char Color )

{

int t, distance; /*根据屏幕大小改变变量类型(如改为int型)*/

int x = 0 , y = 0 , delta_x, delta_y ;

char incx, incy ;

delta_x = EndX - StartX ;

delta_y = EndY - StartY ;

if( delta_x > 0 )

{

incx = 1;

}

else if( delta_x == 0 )

{

v_Lcd12864DrawLineY_f( StartX, StartY, EndY, Color ) ;

return ;

}

else

{

incx = -1 ;

}

if( delta_y > 0 )

{

incy = 1 ;

}

else if(delta_y == 0 )

{

v_Lcd12864DrawLineX_f( StartX, EndX, StartY, Color ) ;

return ;

}

else

{

incy = -1 ;

}

delta_x = ABS( delta_x );

delta_y = ABS( delta_y );

if( delta_x > delta_y )

{

distance = delta_x ;

}

else

{

distance = delta_y ;

}

v_Lcd12864DrawPoint_f( StartX, StartY, Color ) ;

/* Draw Line*/

for( t = 0 ; t <= distance+1 ; t++ )

{

v_Lcd12864DrawPoint_f( StartX, StartY, Color ) ;

x += delta_x ;

y += delta_y ;

if( x > distance )

{

x -= distance ;

StartX += incx ;

}

if( y > distance )

{

y -= distance ;

StartY += incy ;

}

}

}

老规矩,我们用这个函数随便画任意斜率的几条直线看看。

v_Lcd12864DrawLine_f( 0, 0, 127, 63, 1 ) ;

v_Lcd12864DrawLine_f( 0, 63, 127, 0 , 1 ) ;

v_Lcd12864DrawLine_f( 12, 0, 127, 63, 1 ) ;

v_Lcd12864DrawLine_f( 52, 63, 127, 0 , 1 ) ;

v_Lcd12864DrawLine_f( 32, 63, 98, 0, 1 ) ;

v_Lcd12864DrawLine_f( 67, 0, 127, 63 , 1 ) ;

下面是具体的效果图:

至此,12864的用法就告一段落了,这篇文章仅仅希望是起到一个抛砖引玉的作用,希望各位工程师和同学能够灵活的运用12864液晶屏,并把自己的经验拿出来一起交流学习。

本文来自: 电子工程师之家

相关主题
文本预览
相关文档 最新文档