找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

帖子
查看: 25137|回復(fù): 19
收起左側(cè)

12864液晶顯示圖片,畫點,畫任意直線

  [復(fù)制鏈接]
ID:76244 發(fā)表于 2015-4-7 00:35 | 顯示全部樓層 |閱讀模式
12864液晶更高級的用法。
首先是它的繪圖功能。
讓我們先來顯示一整副的圖片吧,也就是128x64大小。
在使用繪圖功能時,先要打開擴充指令集,然后再打開繪圖功能。接著就是送數(shù)據(jù)顯示了。這里我們首先要弄明白ST7920的顯示坐標關(guān)系。其顯示坐標如下。



從圖中可以看出,X方向共有8個字(16個字節(jié))Y方向共有0~31 行 分為上下兩個屏。
弄懂了之后我們就可以依照此坐標來顯示一整屏的圖片了。
隨便用一個圖片的提取轉(zhuǎn)換軟件,講一副126X64大小的圖片轉(zhuǎn)換成字節(jié)數(shù)據(jù),總共字節(jié)大小為128*64/8 = 1024個字節(jié)。

下面我們來看看這個顯示整屏圖像的函數(shù)
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++ )      //寫一整行數(shù)據(jù)
            {
                v_Lcd12864SendData_f( *pPicture++ ) ;
            }
        }
    }
    v_Lcd12864SendCmd_f( 0x30 ) ;
}

看看效果圖片如下:顯示一個人的圖像


下面來看看如何在任意一個位置顯示或者是擦除一個點

對于12864這種二值顯示屏來說,其顯示狀態(tài)無外乎顯示和不顯示一個點這兩種狀態(tài)。而在任意位置畫點,是我們隨心所欲的畫線,畫圓,畫矩形的等GUI函數(shù)的基礎(chǔ)。
為了讓這個位置有一個參考點,我們有必要定義一個坐標系
在這里,我定義的坐標系如下
0,0------------------------------------127,0
|                                                          |
|                                                          |
|                                                          |
|                                                          |
0,63----------------------------------127,63

0,0代表屏幕的左上角,127,63代表屏幕的右下角。
對于屏幕上面任意一個點,如果我們想要點亮它,必須先讀出此點的狀態(tài),然后再修改該點,最后送出去,即 讀----修改----寫。按照這個步驟,然后再運用C語言中的位操作運算符 可以很方便的完成畫點的函數(shù)。
由于畫點函數(shù)涉及到讀ST7920內(nèi)部RAM的操作,因此,我們必須先要完成這個讀數(shù)據(jù)的函數(shù)
具體實現(xiàn)過程如下:
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 ;   
}

然后是畫點的函數(shù),其實現(xiàn)過程如下:

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

有了畫點的函數(shù)之后,一切似乎都變得簡單了,因為點是一切復(fù)雜圖形的最基本的組成單位。
下面我們就在這個畫點函數(shù)的基礎(chǔ)上,實現(xiàn)畫水平線和垂直線的兩個函數(shù)。
畫水平線:
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)    ;
}

下面我們就用以上兩個畫線函數(shù),在液晶屏上面畫一個表格出來
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 ) ;

看看顯示效果


怎么樣,你的實現(xiàn)了嗎?
只能畫水平線和垂直線似乎太簡單和單調(diào)點了。
要是能在任意兩點間畫一條直線就好了,那樣我們就可以做很多事情了。
下面就讓我們?nèi)崿F(xiàn)它!
在這里我們采用Bresenham畫線算法,關(guān)于這個算法,網(wǎng)上有很多資料,請大家以它為關(guān)鍵字到網(wǎng)上去搜索,在這里就不啰嗦了。
下面是算法的具體實現(xiàn)過程:
void v_Lcd12864DrawLine_f( unsigned char StartX, unsigned char StartY, unsigned char EndX, unsigned char EndY, unsigned char Color )
{
    int t, distance;      /*根據(jù)屏幕大小改變變量類型(如改為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 ;
        }
    }
}

老規(guī)矩,我們用這個函數(shù)隨便畫任意斜率的幾條直線看看。
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 ) ;

下面是具體的效果圖:



評分

參與人數(shù) 1黑幣 +8 收起 理由
zhaok2013 + 8 贊一個!

查看全部評分

回復(fù)

使用道具 舉報

ID:76348 發(fā)表于 2015-4-7 16:47 | 顯示全部樓層
觀摩!!51黑有你更精彩!
回復(fù)

使用道具 舉報

ID:77282 發(fā)表于 2015-5-16 21:19 | 顯示全部樓層
這么高級的功能怎么沒人頂呢!頂起來!
回復(fù)

使用道具 舉報

ID:94867 發(fā)表于 2016-3-23 07:36 | 顯示全部樓層
這個不錯我先回復(fù),
回復(fù)

使用道具 舉報

ID:105313 發(fā)表于 2016-3-23 21:21 來自觸屏版 | 顯示全部樓層
謝謝分享
回復(fù)

使用道具 舉報

ID:110507 發(fā)表于 2016-3-24 11:16 | 顯示全部樓層
挺好的程序
回復(fù)

使用道具 舉報

ID:135812 發(fā)表于 2016-8-2 17:36 | 顯示全部樓層
我的撒撒手動閥手動閥樓上的啦啦啦啦
回復(fù)

使用道具 舉報

ID:134810 發(fā)表于 2016-9-25 14:21 來自觸屏版 | 顯示全部樓層
想不到12864還可以畫圖,,用按鍵控制喏,很有意思
回復(fù)

使用道具 舉報

ID:57620 發(fā)表于 2017-3-10 13:06 | 顯示全部樓層
這個好,工程應(yīng)用上非常有用。太感謝了
回復(fù)

使用道具 舉報

ID:198716 發(fā)表于 2017-5-10 19:59 | 顯示全部樓層
這個不錯
回復(fù)

使用道具 舉報

ID:290892 發(fā)表于 2018-7-12 20:44 | 顯示全部樓層
非常感謝
回復(fù)

使用道具 舉報

ID:373594 發(fā)表于 2018-7-22 00:25 | 顯示全部樓層
delta_x = ABS( delta_x );   
    delta_y = ABS( delta_y );
對不起,原諒我是個菜雞,這個ABS是個函數(shù)嗎?那為什么沒看到定義呢?
回復(fù)

使用道具 舉報

ID:373594 發(fā)表于 2018-7-24 19:53 | 顯示全部樓層
echowithme 發(fā)表于 2018-7-22 00:25
delta_x = ABS( delta_x );   
    delta_y = ABS( delta_y );
對不起,原諒我是個菜雞,這個ABS是個函 ...

#include<math.h>

絕對值
回復(fù)

使用道具 舉報

ID:481641 發(fā)表于 2019-4-12 16:39 | 顯示全部樓層
有更全一點的代碼嗎
回復(fù)

使用道具 舉報

ID:387410 發(fā)表于 2019-9-30 16:21 | 顯示全部樓層
樓主優(yōu)秀,用到看一下,謝謝
回復(fù)

使用道具 舉報

ID:387410 發(fā)表于 2019-9-30 16:22 | 顯示全部樓層
頂一下,不錯
回復(fù)

使用道具 舉報

ID:276663 發(fā)表于 2020-5-23 00:38 | 顯示全部樓層
問題是,如果屏幕不支持讀數(shù)據(jù)呢?
回復(fù)

使用道具 舉報

ID:601642 發(fā)表于 2020-5-23 19:03 來自觸屏版 | 顯示全部樓層
妙��!
回復(fù)

使用道具 舉報

ID:253767 發(fā)表于 2020-5-24 06:57 | 顯示全部樓層
謝謝分享!!!
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表