上一篇文章写了ST7789的基本驱动代码,但是没有实现具体的绘图代码。
这里加上。
头文件
#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
>j) )?0:0xffff;
}
}else
{
//TODO. 处理多余的0
printf(" bit err\r\n");
}
p++;
}
pos=ONESIZE;
while(pos>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
如果编译错误,试试勾选C99模式,因为我把一些变量放在语句后面定义了。
即使更换了其他驱动芯片的LCD,也只需要修改上篇文章的lcd_drv.c的底层驱动,和lcd_drv.h的LCD_RAM地址即可。本文件是中间层代码,隔离逻辑业务层与底层驱动层。
如果屏幕IC不使用FSMC驱动,则应该将画点函数,单色填充函数,颜色数据填充函数等几个基本画图函数放在底层lcd_drv.c文件实现。而为了追求速度,我设计了lcddrv_FillColorPre函数,导致不是很通用。