上一篇文章寫了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函數,導致不是很通用。