標(biāo)題: 12864液晶顯示圖片,畫點(diǎn),畫任意直線 [打印本頁]

作者: sans    時間: 2015-4-7 00:35
標(biāo)題: 12864液晶顯示圖片,畫點(diǎn),畫任意直線
12864液晶更高級的用法。
首先是它的繪圖功能。
讓我們先來顯示一整副的圖片吧,也就是128x64大小。
在使用繪圖功能時,先要打開擴(kuò)充指令集,然后再打開繪圖功能。接著就是送數(shù)據(jù)顯示了。這里我們首先要弄明白ST7920的顯示坐標(biāo)關(guān)系。其顯示坐標(biāo)如下。



從圖中可以看出,X方向共有8個字(16個字節(jié))Y方向共有0~31 行 分為上下兩個屏。
弄懂了之后我們就可以依照此坐標(biāo)來顯示一整屏的圖片了。
隨便用一個圖片的提取轉(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坐標(biāo)
            if( i == 0 )                    //寫X坐標(biāo)
            {
                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 ) ;
}

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


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

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

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

然后是畫點(diǎn)的函數(shù),其實(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 )    ;
}

有了畫點(diǎn)的函數(shù)之后,一切似乎都變得簡單了,因?yàn)辄c(diǎn)是一切復(fù)雜圖形的最基本的組成單位。
下面我們就在這個畫點(diǎn)函數(shù)的基礎(chǔ)上,實(shí)現(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 ) ;

看看顯示效果


怎么樣,你的實(shí)現(xiàn)了嗎?
只能畫水平線和垂直線似乎太簡單和單調(diào)點(diǎn)了。
要是能在任意兩點(diǎn)間畫一條直線就好了,那樣我們就可以做很多事情了。
下面就讓我們?nèi)?shí)現(xiàn)它!
在這里我們采用Bresenham畫線算法,關(guān)于這個算法,網(wǎng)上有很多資料,請大家以它為關(guān)鍵字到網(wǎng)上去搜索,在這里就不啰嗦了。
下面是算法的具體實(shí)現(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 ) ;

下面是具體的效果圖:




作者: JY腳印    時間: 2015-4-7 16:47
觀摩。51黑有你更精彩!
作者: jiakuo25    時間: 2015-5-16 21:19
這么高級的功能怎么沒人頂呢!頂起來!
作者: koenlee93    時間: 2016-3-23 07:36
這個不錯我先回復(fù),
作者: guobd    時間: 2016-3-23 21:21
謝謝分享
作者: thlb    時間: 2016-3-24 11:16
挺好的程序
作者: ggggggb    時間: 2016-8-2 17:36
我的撒撒手動閥手動閥樓上的啦啦啦啦
作者: dxa572862121    時間: 2016-9-25 14:21
想不到12864還可以畫圖,,用按鍵控制喏,很有意思
作者: byjj3312    時間: 2017-3-10 13:06
這個好,工程應(yīng)用上非常有用。太感謝了
作者: eastking    時間: 2017-5-10 19:59
這個不錯
作者: 汶爾雅    時間: 2018-7-12 20:44
非常感謝
作者: echowithme    時間: 2018-7-22 00:25
delta_x = ABS( delta_x );   
    delta_y = ABS( delta_y );
對不起,原諒我是個菜雞,這個ABS是個函數(shù)嗎?那為什么沒看到定義呢?
作者: echowithme    時間: 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>

絕對值

作者: 我對你情有獨(dú)鐘    時間: 2019-4-12 16:39
有更全一點(diǎn)的代碼嗎
作者: lls5201    時間: 2019-9-30 16:21
樓主優(yōu)秀,用到看一下,謝謝
作者: lls5201    時間: 2019-9-30 16:22
頂一下,不錯
作者: IdeaMing    時間: 2020-5-23 00:38
問題是,如果屏幕不支持讀數(shù)據(jù)呢?
作者: xutao123    時間: 2020-5-23 19:03
妙。
作者: tieq1952    時間: 2020-5-24 06:57
謝謝分享!!!




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1