找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 21745|回复: 19
收起左侧

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

  [复制链接]
ID:76244 发表于 2015-4-7 00:35 | 显示全部楼层 |阅读模式
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 ) ;

下面是具体的效果图:



评分

参与人数 1黑币 +8 收起 理由
zhaok2013 + 8 赞一个!

查看全部评分

回复

使用道具 举报

ID:76348 发表于 2015-4-7 16:47 | 显示全部楼层
观摩!!51黑有你更精彩!
回复

使用道具 举报

ID:77282 发表于 2015-5-16 21:19 | 显示全部楼层
这么高级的功能怎么没人顶呢!顶起来!
回复

使用道具 举报

ID:94867 发表于 2016-3-23 07:36 | 显示全部楼层
这个不错我先回复,
回复

使用道具 举报

ID:105313 发表于 2016-3-23 21:21 来自手机 | 显示全部楼层
谢谢分享
回复

使用道具 举报

ID:110507 发表于 2016-3-24 11:16 | 显示全部楼层
挺好的程序
回复

使用道具 举报

ID:135812 发表于 2016-8-2 17:36 | 显示全部楼层
我的撒撒手动阀手动阀楼上的啦啦啦啦
回复

使用道具 举报

ID:134810 发表于 2016-9-25 14:21 来自手机 | 显示全部楼层
想不到12864还可以画图,,用按键控制喏,很有意思
回复

使用道具 举报

ID:57620 发表于 2017-3-10 13:06 | 显示全部楼层
这个好,工程应用上非常有用。太感谢了
回复

使用道具 举报

ID:198716 发表于 2017-5-10 19:59 | 显示全部楼层
这个不错
回复

使用道具 举报

ID:290892 发表于 2018-7-12 20:44 | 显示全部楼层
非常感谢
回复

使用道具 举报

ID:373594 发表于 2018-7-22 00:25 | 显示全部楼层
delta_x = ABS( delta_x );   
    delta_y = ABS( delta_y );
对不起,原谅我是个菜鸡,这个ABS是个函数吗?那为什么没看到定义呢?
回复

使用道具 举报

ID:373594 发表于 2018-7-24 19:53 | 显示全部楼层
echowithme 发表于 2018-7-22 00:25
delta_x = ABS( delta_x );   
    delta_y = ABS( delta_y );
对不起,原谅我是个菜鸡,这个ABS是个函 ...

#include<math.h>

绝对值
回复

使用道具 举报

ID:481641 发表于 2019-4-12 16:39 | 显示全部楼层
有更全一点的代码吗
回复

使用道具 举报

ID:387410 发表于 2019-9-30 16:21 | 显示全部楼层
楼主优秀,用到看一下,谢谢
回复

使用道具 举报

ID:387410 发表于 2019-9-30 16:22 | 显示全部楼层
顶一下,不错
回复

使用道具 举报

ID:276663 发表于 2020-5-23 00:38 | 显示全部楼层
问题是,如果屏幕不支持读数据呢?
回复

使用道具 举报

ID:601642 发表于 2020-5-23 19:03 来自手机 | 显示全部楼层
妙啊!
回复

使用道具 举报

ID:253767 发表于 2020-5-24 06:57 | 显示全部楼层
谢谢分享!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表