STM32:FSMC驅動TFTLCD(2)

上一篇文章寫了ST7789的基本驅動代碼,但是沒有實現具體的繪圖代碼。

這裏加上。

1.代碼

頭文件

#ifndef __BSP_LCD_H
#define __BSP_LCD_H
#include "lcd_drv.h"

/*
    RGB565:
    高位至低位排列, RRRR RGGG GGGB BBBB
*/
#define RGB(R,G,B)    (((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3)) //24位RGB轉化爲 16位RGB565格式
#define RGB565_R(x)  ((x >> 8) & 0xF8)
#define RGB565_G(x)  ((x >> 3) & 0xFC)
#define RGB565_B(x)  ((x << 3) & 0xF8)
enum
{
    CL_WHITE        = RGB(255, 255, 255),   /* 白 */
    CL_BLACK        = RGB(  0,  0,  0),     /* 黑 */
    CL_RED          = RGB(255,    0,  0),   /* 紅 */
    CL_GREEN        = RGB(  0, 255,  0),    /* 綠 */
    CL_BLUE         = RGB(  0,    0, 255),  /* 藍 */
    CL_YELLOW       = RGB(255, 255,  0),    /* 黃 */
    CL_GREY         = RGB( 98, 98, 98),     /* 深灰 */
    CL_BUTTON_GREY  = RGB( 220, 220, 220),  /* 按鈕灰*/
};

/* 可供外部模塊調用的函數 */
void LCD_Init(void);


#define  LCD_GetHeight() LCD_HEIGHT
#define  LCD_GetWidth() LCD_WIDTH
//#define  LCD_FillColorPre lcddrv_FillColorPre

void LCD_PutPixel(uint16_t _usX, uint16_t _usY, uint16_t _usColor);
void LCD_DrawHLine(uint16_t _usX , uint16_t _usY , uint16_t _uslen , uint16_t _usColor);
void LCD_DrawHColorLine(uint16_t _usX , uint16_t _usY, uint16_t _uslen, const uint16_t *_pColor);
void LCD_Fill_Rect(uint16_t _usX,   uint16_t _usY, uint16_t _usWidth, uint16_t  _usHeight, uint16_t _usColor);
void LCD_Fill_ColorRect(uint16_t _usX,   uint16_t _usY, uint16_t _usWidth, uint16_t  _usHeight, const uint16_t *_pColor);

#define  LCD_ClrScr(_usColor)       LCD_Fill_Rect(0,0,LCD_WIDTH,LCD_HEIGHT,_usColor);
#define  LCD_DrawVLine(_usX,_usY,len,_usColor)      LCD_Fill_Rect(_usX,_usY,1,len,_usColor)

void LCD_DrawLine(uint16_t _usX1 , uint16_t _usY1 , uint16_t _usX2 , uint16_t _usY2 , uint16_t _usColor);
void LCD_DrawPolyline(uint16_t *x, uint16_t *y, uint16_t _usSize, uint16_t _usColor);
void LCD_DrawRect(uint16_t _usX, uint16_t _usY, uint16_t _usWidth,uint16_t _usHeight,  uint16_t _usColor);
void LCD_DrawCircle(uint16_t _usX, uint16_t _usY, uint16_t _usRadius, uint16_t _usColor);

void LCD_DrawBinBMP(uint16_t _usX, uint16_t _usY, const char * pPath);

void LCD_DispOn(void);
void LCD_DispOff(void);
void LCD_SetBackLight(uint8_t _ucBright);
uint8_t LCD_GetBackLight(void);

#endif

C文件

#include "bsp.h"
#include "lcd_drv.h"
#include "fonts.h"

//#define LCD_GetWidth() LCD_WIDTH
//#define LCD_GetHeight() LCD_HEIGHT

static uint8_t s_ucBright;                    /* 背光亮度參數 */

/*
*************************************************************************************************
*    函 數 名: LCD_DispOn
*    功能說明: 打開顯示
*    形    參: 無
*    返 回 值: 無
*************************************************************************************************
*/
void LCD_DispOn(void)
{
    lcddrv_DispOn();
}

/*
************************************************************************************************
*    函 數 名: LCD_DispOff
*    功能說明: 關閉顯示
*    形    參: 無
*    返 回 值: 無
************************************************************************************************
*/
void LCD_DispOff(void)
{
    lcddrv_DispOff();
}

/*
*************************************************************************************************
*    函 數 名:  LCD_PutPixel
*    功能說明: 打點函數
*    形    參:
*             _usX,_usY : 像素座標
*             _usColor  :像素顏色
*    返 回 值: 無
*************************************************************************************************
*/
void LCD_PutPixel(uint16_t _usX, uint16_t _usY, uint16_t _usColor)
{
    lcddrv_FillColorPre(_usX, _usY,LCD_WIDTH,LCD_HEIGHT);    /* 設置光標位置 */

    /* Write 16-bit GRAM Reg */
    LCDDRV_RAM = _usColor;
}
/*
*************************************************************************************************
*    函 數 名:  _DrawHLine
*    功能說明:  繪製水平線
*    形    參:  _usX ,_usY : 起始點座標
*               _usLen     :長度
*               _usColor   : 顏色
*    返 回 值: 無
*************************************************************************************************
*/
void LCD_DrawHLine(uint16_t _usX , uint16_t _usY , uint16_t _usLen , uint16_t _usColor)
{
    uint16_t i;

    lcddrv_FillColorPre(_usX, _usY,LCD_WIDTH,LCD_HEIGHT);

    for (i = 0; i < _usLen; i++)
    {
        LCDDRV_RAM = _usColor;
    }
}
/*
*************************************************************************************************
*    函 數 名:  _DrawHColorLine
*    功能說明: 繪製一條彩色水平線
*    形    參:  _usX ,_usY :起始點座標
*              _usLen       :直線的長度
*              _pColor      : 顏色緩衝區
*    返 回 值: 無
*************************************************************************************************
*/
void LCD_DrawHColorLine(uint16_t _usX , uint16_t _usY, uint16_t _usLen, const uint16_t *_pColor)
{
    uint16_t i;

    lcddrv_FillColorPre(_usX, _usY,LCD_WIDTH,LCD_HEIGHT);

    for (i = 0; i < _usLen; i++)
    {
        LCDDRV_RAM = *_pColor++;
    }
}
/*
*************************************************************************************************
*    函 數 名: LCD_Fill_Rect
*    功能說明: 繪製單色矩形區域
*    形    參:
*            _usX,_usY :  矩形左上角的座標
*            _usHeight :  矩形的高度
*            _usWidth  :  矩形的寬度
*            _usColor  :  顏色
*    返 回 值: 無
*************************************************************************************************
*/
void LCD_Fill_Rect(uint16_t _usX,   uint16_t _usY, uint16_t _usWidth, uint16_t  _usHeight, uint16_t _usColor)
{
    uint32_t i;
    uint32_t len = (uint32_t)_usWidth * _usHeight;

    lcddrv_FillColorPre(_usX, _usY, _usWidth, _usHeight);
 
    for (i = 0; i < len; i++)
    {
        LCDDRV_RAM = _usColor;
    }

}
/*
*************************************************************************************************
*    函 數 名: LCD_Fill_ColorRect
*    功能說明: 繪製矩形區域,顏色填充數據
*    形    參:
*            _usX,_usY :  矩形左上角的座標
*            _usHeight :  矩形的高度
*            _usWidth  :  矩形的寬度
*            _pColor   :  顏色緩衝區
*    返 回 值: 無
*************************************************************************************************
*/
void LCD_Fill_ColorRect(uint16_t _usX,   uint16_t _usY, uint16_t _usWidth, uint16_t  _usHeight, const uint16_t *_pColor)
{
    uint32_t i;
    uint32_t len = (uint32_t)_usWidth * _usHeight;

    lcddrv_FillColorPre(_usX, _usY, _usWidth, _usHeight);
 
    for (i = 0; i < len; i++)
    {
        ST7789_RAM = *_pColor++;
    }
}
/*
*************************************************************************************************
*    函 數 名: LCD_DrawRect
*    功能說明: 繪製矩形邊。
*    形    參:
*            _usX,_usY: 矩形左上角的座標
*            _usWidth  : 矩形的寬度
*            _usHeight : 矩形的高度
*    返 回 值: 無
*************************************************************************************************
*/
void LCD_DrawRect(uint16_t _usX, uint16_t _usY, uint16_t _usWidth, uint16_t _usHeight, uint16_t _usColor)
{
    LCD_DrawHLine(  _usX ,  _usY ,                  _usWidth ,  _usColor);
    LCD_DrawHLine(  _usX ,  _usY + _usHeight - 1 ,     _usWidth ,  _usColor);

    LCD_DrawVLine(  _usX ,              _usY ,    _usHeight,  _usColor);
    LCD_DrawVLine(  _usX + _usWidth - 1 ,  _usY ,    _usHeight,  _usColor);
}
/*
*************************************************************************************************
*    函 數 名: LCD_DrawLine
*    功能說明: Bresenham 算法繪製2點間的直線。
*    形    參:
*            _usX1, _usY1 : 起始點座標
*            _usX2, _usY2 : 終止點Y座標
*            _usColor     : 顏色
*    返 回 值: 無
*************************************************************************************************
*/
void LCD_DrawLine(uint16_t _usX1 , uint16_t _usY1 , uint16_t _usX2 , uint16_t _usY2 , uint16_t _usColor)
{
    int32_t dx , dy ;
    int32_t tx , ty ;
    int32_t inc1 , inc2 ;
    int32_t d , iTag ;
    int32_t x , y ;

    LCD_PutPixel(_usX1 , _usY1 , _usColor);

    if ( _usX1 == _usX2 && _usY1 == _usY2 )
    {
        LCD_PutPixel(  _usX1,  _usY2,   _usColor);
        return;
    }

    iTag = 0 ;
    
    if (_usX2 >= _usX1)
    {
        dx = _usX2 - _usX1;
    }
    else
    {
        dx = _usX1 - _usX2;
    }

    if (_usY2 >= _usY1)
    {
        dy = _usY2 - _usY1;
    }
    else
    {
        dy = _usY1 - _usY2;
    }

    if ( dx < dy )   //如果dy爲計長方向,則交換縱橫座標。
    {
        uint16_t temp;

        iTag = 1 ;
        temp = _usX1;
        _usX1 = _usY1;
        _usY1 = temp;
        temp = _usX2;
        _usX2 = _usY2;
        _usY2 = temp;
        temp = dx;
        dx = dy;
        dy = temp;
    }
    tx = _usX2 > _usX1 ? 1 : -1 ;    //確定是增1還是減1 
    ty = _usY2 > _usY1 ? 1 : -1 ;
    x = _usX1 ;
    y = _usY1 ;
    inc1 = 2 * dy ;
    inc2 = 2 * ( dy - dx );
    d = inc1 - dx ;
    while ( x != _usX2 )    // 循環畫點 
    {
        if ( d < 0 )
        {
            d += inc1 ;
        }
        else
        {
            y += ty ;
            d += inc2 ;
        }
        if ( iTag )
        {
            LCD_PutPixel ( y , x , _usColor) ;
        }
        else
        {
            LCD_PutPixel ( x , y , _usColor) ;
        }
        x += tx ;
    }
}


/*
*************************************************************************************************
*    函 數 名: LCD_DrawCircle
*    功能說明: 畫空心圓
*    形    參:
*            _usX,_usY  : 圓心座標
*            _usRadius  : 半徑
*            _usColor   : 顏色
*    返 回 值: 無
*************************************************************************************************
*/
void LCD_DrawCircle(uint16_t _usX, uint16_t _usY, uint16_t _usRadius, uint16_t _usColor)
{
    int32_t  D;            /* Decision Variable */
    uint32_t  CurX;        /* 當前 X 值 */
    uint32_t  CurY;        /* 當前 Y 值 */

    D = 3 - (_usRadius << 1);
    CurX = 0;
    CurY = _usRadius;

    while (CurX <= CurY)
    {
        LCD_PutPixel(_usX + CurX, _usY + CurY, _usColor);
        LCD_PutPixel(_usX + CurX, _usY - CurY, _usColor);
        LCD_PutPixel(_usX - CurX, _usY + CurY, _usColor);
        LCD_PutPixel(_usX - CurX, _usY - CurY, _usColor);
        LCD_PutPixel(_usX + CurY, _usY + CurX, _usColor);
        LCD_PutPixel(_usX + CurY, _usY - CurX, _usColor);
        LCD_PutPixel(_usX - CurY, _usY + CurX, _usColor);
        LCD_PutPixel(_usX - CurY, _usY - CurX, _usColor);

        if (D < 0)
        {
            D += (CurX << 2) + 6;
        }
        else
        {
            D += ((CurX - CurY) << 2) + 10;
            CurY--;
        }
        CurX++;
    }
}

#define ONESIZE (2048)      //從SD卡單次讀取的數據大小
__inline static uint16_t turn332to565( uint16_t c)  //RGB332轉RGB565
{
    uint16_t r= (c&0x00E0)<<8;
    uint16_t g= (c&0x001C)<<6;
    uint16_t b= (c&0x0003)<<3;
    return r+g+b;
}
/*
*************************************************************************************************
*    函 數 名: LCD_DrawBinBMP
*    功能說明: 在LCD上顯示一個SD卡的BMP-BIN格式位圖,使用Img2Lcd將BMP轉BIN;支持1BIT,8BIT,16BIT。
*              位圖點陣掃描次序: 從左到右,從上到下.測試全幅圖(16bit/RGB565),速度如下:
*              ONESIZE =512->180ms,1024->135ms,=2048->110ms,=4096->110ms
*    形    參:
*            _usX, _usY : 圖片的座標
*            path       : 路徑,比如"0:/bmp/001.bin"
*            _ptr       : 圖片點陣指針
*    返 回 值: 無
*************************************************************************************************
*/
void LCD_DrawBinBMP(uint16_t _usX, uint16_t _usY, const char * path)
{
    PICBIN_HEADCOLOR_T head;
    FRESULT  fres;
    FIL xfile;
    u32 br=0,pos=0;
    u16 *const buf= mymalloc(SRAMCCM,ONESIZE);
    u8 *p;
    if(buf==NULL){  printf(" mymalloc err !\r\n");return;}

    fres=f_open(&xfile,path,FA_OPEN_EXISTING|FA_READ);
    if(fres == FR_OK)
    {
        f_lseek(&xfile,0);
        p=(u8*)buf;
        fres = f_read(&xfile,p,ONESIZE,&br);

        if( fres==FR_OK )
        {
            memcpy(&head,p,sizeof(head));
            lcddrv_FillColorPre( _usX,_usY,head.w,head.h);
            if(head.gray==1) //1bit圖
            {
                p+=6;
                u16 i=6;
                for(;i<br;i++)
                {
                    u8 j=0;
                    if( head.w%8 == 0  ) //寬度爲8的倍數的情況
                    {
                        for(;j<8;j++)
                        {
                            LCDDRV_RAM = ( (*p) & (0x80>>j) )?0:0xffff;
                        }
                    }else
                    {
                        //TODO. 處理多餘的0
                        printf(" bit err\r\n");
                    }
                    p++;
                }
            
                pos=ONESIZE;
                while(pos<xfile.fsize)
                {
                    p=(u8*)buf;
                   
                    f_lseek(&xfile,pos);
                    fres = f_read(&xfile,p,ONESIZE,&br);
                    if( fres==FR_OK )
                    {
                        u16 i=0;
                        for(;i<br;i++)
                        {
                            u8 j=0;
                            if( head.w%8 == 0  )
                            {
                                for(;j<8;j++)
                                {
                                    LCDDRV_RAM = ( (*p) & (0x80>>j) )?0:0xffff;
                                }
                            }else
                            {
                                //TODO. 處理多餘的0
                                printf(" bit err\r\n");
                            }
                            p++;
                        }
                    }
                    pos+=ONESIZE;
                }
            }
            else if(head.gray==8) //8bit圖
            {
                p+=6;
                u16 i=6;
                for(;i<br;i++)
                {
                    
                    LCDDRV_RAM =turn332to565(*p)+4 +0x80+0x1000;
                    p++;
                }
            
                pos=ONESIZE;
                while(pos<xfile.fsize)
                {
                    p=(u8*)buf;
                   
                    f_lseek(&xfile,pos);
                    fres = f_read(&xfile,p,ONESIZE,&br);
                    if( fres==FR_OK )
                    {
                        u16 i=0;
                        for(;i<br;i++)
                        {
                            LCDDRV_RAM = turn332to565(*p)+4 +0x80+0x1000;
                            p++;
                        }
                    }
                    pos+=ONESIZE;
                }
            }
            else  //16bit圖
            {
                p+=8;
                u16 i=8;
                for(;i<br;i+=2)
                {
                    LCDDRV_RAM = *(u16*)p;
                    p+=2;
                }
                
                pos=ONESIZE;
                while(pos<xfile.fsize)
                {
                    p=(u8*)buf;
                   
                    f_lseek(&xfile,pos);
                    fres = f_read(&xfile,p,ONESIZE,&br);
                    if( fres==FR_OK )
                    {
                        u16 i=0;
                        for(;i<br;i+=2)
                        {
                            LCDDRV_RAM = *(u16*)p;
                            p+=2;
                        }
                    }
                    pos+=ONESIZE;
                }
            }
        }
        f_close(&xfile);
    }else  
        printf(" no\" %s\" file!\r\n",path);
    
    myfree(SRAMCCM,buf);
}

/*
*************************************************************************************************
*    函 數 名: LCD_SetBackLight
*    功能說明: LCD背光控制
*    形    參: _ucBright 亮度,0滅
*    返 回 值: 無
*************************************************************************************************
*/
void LCD_SetBackLight(uint8_t _ucBright)
{
    s_ucBright =  _ucBright;    /* 保存背光值 */
    lcddrv_SetBackLight(_ucBright);
}

/*
*************************************************************************************************
*    函 數 名: LCD_GetBackLight
*    功能說明: 獲取背光亮度
*    形    參: 無
*    返 回 值: 背光亮度
*************************************************************************************************
*/
uint8_t LCD_GetBackLight(void)
{
    return s_ucBright;
}

/*
*************************************************************************************************
*    函 數 名: LCD_Init
*    功能說明: 初始化LCD
*    形    參: 無
*    返 回 值: 無
*************************************************************************************************
*/
void LCD_Init(void)
{
    lcddrv_Init();
    LCD_ClrScr(0xffff);
    LCD_SetBackLight(BRIGHT_DEFAULT);     /* 打開背光,設置爲缺省亮度 */
}

如果編譯錯誤,試試勾選C99模式,因爲我把一些變量放在語句後面定義了。

即使更換了其他驅動芯片的LCD,也只需要修改上篇文章的lcd_drv.c的底層驅動,和lcd_drv.h的LCD_RAM地址即可。本文件是中間層代碼,隔離邏輯業務層與底層驅動層。

如果屏幕IC不使用FSMC驅動,則應該將畫點函數,單色填充函數,顏色數據填充函數等幾個基本畫圖函數放在底層lcd_drv.c文件實現。而爲了追求速度,我設計了lcddrv_FillColorPre函數,導致不是很通用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章