1250 lines
32 KiB
C
1250 lines
32 KiB
C
/**
|
||
******************************************************************************
|
||
*
|
||
* TFT 3.2寸显示屏驱动文件,目前使用FSMC(stm32f407系列可用,其他暂不支持!)
|
||
*
|
||
* 功能说明:
|
||
* 1.包含基本的显示、画点、画线功能及基本的数字显示;
|
||
* 2.包含中点画圆算法和改进中点画圆算法;
|
||
* 3.包含中点画椭圆算法;
|
||
* 4.显示字符的函数可返回当前目标所占空间的状态(坐标范围和颜色状态等!);
|
||
* 5.TFT的算法和OLED算法不同,TFT是按点写入,OLED按字节,因此TFT不存在覆盖!
|
||
* 6.区域操作的时间很长,有视觉可分辨延时,原因是对数组操作耗时太长!
|
||
*
|
||
* 使用注意:
|
||
* 1.本文件是不使用emWin等成熟移植方案的测试版本;
|
||
* 2.本文件并不独立,部分函数依赖硬件,目前是FSMC版本!
|
||
* 3.本程序为GUI界面服务,除学习外不得作为他用!同时欢迎不断补充功能!
|
||
*
|
||
* 版本修订:
|
||
* 修改时间 版本号 修改内容
|
||
* 2017-01-01 v1.0 移植oled程序,构建本文件;
|
||
* 2017-01-02 v2.0 增加中点画圆算法和改进中点画圆算法;
|
||
* 2017-01-02 v2.1 增加中点画椭圆算法和改进中点画椭圆算法;
|
||
* 2017-03-05 v3.0 添加区域移屏、翻转、颜色替换、颜色对调操作函数;
|
||
* 2017-03-05 v3.1 添加了操作的全局控制开关量;
|
||
* 2018-01-023 v4.0 重构文件,对部分函数进行优化,部分函数名修改!
|
||
* 2021-03-28 v5.0 添加gd32f407
|
||
*
|
||
* 程序出处:
|
||
* Copyright (C), 2017-2017, TYUT TSS-plan by SERI.LJI
|
||
* All rights reserved
|
||
*
|
||
*
|
||
* Create :2017年01月01日
|
||
* Update :2018年01月23日
|
||
* Author :dengchow
|
||
*
|
||
******************************************************************************
|
||
***/
|
||
|
||
|
||
|
||
#include "Driver_tftspi.h"
|
||
#include "Task_tft.h"
|
||
#include "Task_font.h"//包含tft使用的字体编码
|
||
|
||
#ifndef ABS
|
||
#define ABS(n) (((n)<0) ? -(n) : (n))
|
||
#endif
|
||
|
||
_TFTDisplayStyleStruct DefaultStyle={BLACK, WHITE, 0, 0, 0, 0, 0, 16};//默认风格:白底黑字,1206字体
|
||
|
||
|
||
/**
|
||
* @brief :BGR转化为RGB
|
||
* @note :--从ILI9341读出的数据为BGR格式,电脑BMP图像识别是RGB格式!
|
||
--其实,BGR和RGB相互转化是一样的公式!
|
||
* @param :BGR, BGR格式的颜色值
|
||
* @return :uint16_t, RGB格式的颜色值
|
||
*
|
||
* @data :2017/03/04
|
||
* @design :
|
||
**/
|
||
uint16_t TFT_BGR2RGB(uint16_t BGR)
|
||
{
|
||
uint16_t R=0, G=0, B=0;
|
||
|
||
B = (BGR>>11)&0x001F;
|
||
G = (BGR>>5) &0x003F;
|
||
R = (BGR>>0) &0x1F;
|
||
|
||
return ((R<<11) + (G<<5) + B);
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :RGB转化为BGR
|
||
* @note :--写入ILI9341的时候为BGR格式,取模软件得到的是RGB格式!
|
||
--其实,BGR和RGB相互转化是一样的公式!
|
||
* @param :RGB, RGB格式的颜色值
|
||
* @return :uint16_t, BGR格式的颜色值
|
||
*
|
||
* @data :2017/03/06
|
||
* @design :
|
||
**/
|
||
uint16_t TFT_RGB2BGR(uint16_t RGB)
|
||
{
|
||
uint16_t R=0, G=0, B=0;
|
||
|
||
R = (RGB>>11)&0x001F;
|
||
G = (RGB>>5) &0x003F;
|
||
B = (RGB>>0) &0x001F;
|
||
|
||
return ((B<<11) + (G<<5) + R);
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :调色函数(输入RGB三色值,输出TFT的颜色值)
|
||
* @note :--写入的时候为RGB格式!
|
||
* @param :RGB, 三色值
|
||
* @return :uint16_t, BGR565
|
||
*
|
||
* @data :2017/03/04
|
||
* @design :
|
||
**/
|
||
uint16_t TFT_MakeColor(uint8_t R, uint8_t G, uint8_t B)
|
||
{
|
||
uint16_t r, g, b;
|
||
|
||
r = (R >> 3);
|
||
g = (G >> 2);
|
||
b = (B >> 3);
|
||
|
||
return ((b<<11) | (g<<5) | r);
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :提色函数(输入TFT的颜色值,输出RGB三色值)
|
||
* @note :--写入的时候为RGB格式!
|
||
* @param :Color, RGB565颜色
|
||
* @return :void
|
||
*
|
||
* @data :2020/11/04
|
||
* @design :
|
||
**/
|
||
void TFT_GetColor(uint16_t Color, uint8_t *R, uint8_t *G, uint8_t *B)
|
||
{
|
||
*B = (Color)&0x1F;
|
||
*G = (Color>>5)&0x3F;
|
||
*R = (Color>>11)&0x1F;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :画实线
|
||
* @note :--
|
||
* @param :XS , 行起始坐标
|
||
YS , 列起始坐标
|
||
XE , 行终止坐标
|
||
YE , 列终止坐标
|
||
color, 颜色
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/04
|
||
* @design :
|
||
**/
|
||
void TFT_DrawLine(uint16_t XS, uint16_t YS, uint16_t XE, uint16_t YE, uint16_t color)
|
||
{
|
||
uint16_t start=0, end=0;
|
||
uint16_t i=0;
|
||
int16_t x_width=0; //x轴宽度
|
||
int16_t y_height=0; //y轴高度
|
||
int16_t rem=0; //current remainder
|
||
int8_t x_inc=0; //x方向自增标记
|
||
int8_t y_inc=0; //y方向自增标记
|
||
|
||
if(YS == YE)//绘制水平线,horizon line
|
||
{
|
||
if(XS > XE)
|
||
{
|
||
start = XE;
|
||
end = XS;
|
||
}else{
|
||
start = XS;
|
||
end = XE;
|
||
}
|
||
|
||
for(i=start; i<=end; i++){
|
||
TFT_FastDrawPoint(i, YS, color);
|
||
}
|
||
}else if(XS == XE){//绘制垂直线,vertical line
|
||
if(YS > YE)
|
||
{
|
||
start = YE;
|
||
end = YS;
|
||
}else{
|
||
start = YS;
|
||
end = YE;
|
||
}
|
||
|
||
for(i=start; i<=end; i++){
|
||
TFT_FastDrawPoint(XS, i, color);
|
||
}
|
||
}else{//绘制任意直线
|
||
x_width = XE - XS;
|
||
y_height = YE - YS;
|
||
|
||
if (x_width < 0){
|
||
x_width = 0 - x_width;
|
||
}
|
||
if (y_height < 0){
|
||
y_height = 0 - y_height;
|
||
}
|
||
|
||
x_inc = (XE > XS) ? 1 : -1;
|
||
y_inc = (YE > YS) ? 1 : -1;
|
||
|
||
if(x_width >= y_height)
|
||
{
|
||
rem = x_width/2;
|
||
for(; XS!=XE; XS+=x_inc)
|
||
{
|
||
TFT_FastDrawPoint(XS, YS, color);
|
||
|
||
rem += y_height;
|
||
if(rem >= x_width)
|
||
{
|
||
rem -= x_width;
|
||
YS += y_inc;
|
||
}
|
||
}
|
||
}else{
|
||
rem = y_height/2;
|
||
for(; YS!=YE; YS+=y_inc)
|
||
{
|
||
TFT_FastDrawPoint(XS, YS, color);
|
||
|
||
rem += x_width;
|
||
if(rem >= y_height)
|
||
{
|
||
rem -= y_height;
|
||
XS += x_inc;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :画虚线
|
||
* @note :--
|
||
* @param :XS , 行起始坐标
|
||
YS , 列起始坐标
|
||
XE , 行终止坐标
|
||
YE , 列终止坐标
|
||
color, 颜色
|
||
* @return :void
|
||
*
|
||
* @data :2020/11/15
|
||
* @design :
|
||
**/
|
||
#define _DELTA_PIXEL 5
|
||
void TFT_DrawDottedLine(uint16_t XS, uint16_t YS, uint16_t XE, uint16_t YE, uint16_t color)
|
||
{
|
||
float k;
|
||
int change_flag;
|
||
float xdelta[2], ydelta[2];
|
||
|
||
if ((XE == XS) && (YE == YS))
|
||
return;
|
||
|
||
if (XE == XS)
|
||
{
|
||
change_flag = 0;
|
||
for (int i=0; i<(ABS(YE-YS)/_DELTA_PIXEL); i++)
|
||
{
|
||
ydelta[0] = ((YE > YS) ? 1 : -1) * _DELTA_PIXEL * i;
|
||
ydelta[1] = ((YE > YS) ? 1 : -1) * _DELTA_PIXEL * (i+1);
|
||
|
||
if (0 == change_flag)
|
||
{
|
||
TFT_DrawLine(XS, YS+ydelta[0], XS, YS+ydelta[1], color);
|
||
} else {
|
||
TFT_DrawLine(XS, YS+ydelta[0], XS, YS+ydelta[1], DefaultStyle.BC);
|
||
}
|
||
change_flag = ~change_flag;
|
||
}
|
||
}
|
||
else if (YE == YS)
|
||
{
|
||
change_flag = 0;
|
||
for (int i=0; i<(ABS(XE-XS)/_DELTA_PIXEL); i++)
|
||
{
|
||
xdelta[0] = ((XE > XS) ? 1 : -1) * _DELTA_PIXEL * i;
|
||
xdelta[1] = ((XE > XS) ? 1 : -1) * _DELTA_PIXEL * (i+1);
|
||
|
||
if (0 == change_flag)
|
||
{
|
||
TFT_DrawLine(XS+xdelta[0], YS, XS+xdelta[1], YS, color);
|
||
} else {
|
||
TFT_DrawLine(XS+xdelta[0], YS, XS+xdelta[1], YS, DefaultStyle.BC);
|
||
}
|
||
change_flag = ~change_flag;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
k = 1.0f * (YE-YS) / (XE-XS);
|
||
|
||
change_flag = 0;
|
||
for (int i=0; i<(ABS(XE-XS)/_DELTA_PIXEL); i++)
|
||
{
|
||
xdelta[0] = ((XE > XS) ? 1 : -1) * _DELTA_PIXEL * i;
|
||
xdelta[1] = ((XE > XS) ? 1 : -1) * _DELTA_PIXEL * (i+1);
|
||
|
||
ydelta[0] = ((YE > YS) ? 1 : -1) * k * _DELTA_PIXEL * i;
|
||
ydelta[1] = ((YE > YS) ? 1 : -1) * k * _DELTA_PIXEL * (i+1);
|
||
|
||
if (0 == change_flag)
|
||
{
|
||
TFT_DrawLine(XS+xdelta[0], YS+ydelta[0], XS+xdelta[1], YS+ydelta[1], color);
|
||
} else {
|
||
TFT_DrawLine(XS+xdelta[0], YS+ydelta[0], XS+xdelta[1], YS+ydelta[1], DefaultStyle.BC);
|
||
}
|
||
change_flag = ~change_flag;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief :画矩形框
|
||
* @note :--仅边框
|
||
* @param :XS , 行起始坐标
|
||
YS , 列起始坐标
|
||
XE , 行终止坐标
|
||
YE , 列终止坐标
|
||
color, 颜色
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/04
|
||
* @design :
|
||
**/
|
||
void TFT_DrawBlock(uint16_t XS, uint16_t YS, uint16_t XE, uint16_t YE, uint16_t color)
|
||
{
|
||
TFT_DrawLine(XS, YS, XS, YE, color);//左界
|
||
TFT_DrawLine(XE, YS, XE, YE, color);//右界
|
||
TFT_DrawLine(XS, YS, XE, YS, color);//上界
|
||
TFT_DrawLine(XS, YE, XE, YE, color);//下界
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :画矩形(填充矩形)
|
||
* @note :--边框和内部填充颜色!
|
||
* @param :XS , 行起始坐标
|
||
YS , 列起始坐标
|
||
width , 矩形长度
|
||
height , 矩形宽度
|
||
blockColor, 边框颜色
|
||
fillColor , 填充颜色
|
||
* @return :void
|
||
*
|
||
* @data :2016/09/09
|
||
* @design :
|
||
**/
|
||
void TFT_DrawRect(uint16_t XS, uint16_t YS, uint16_t width, uint16_t height, uint16_t blockColor, uint16_t fillColor)
|
||
{
|
||
uint16_t rect_xs=XS;
|
||
uint16_t rect_ys=YS;
|
||
uint16_t rect_xe=XS + width - 1;
|
||
uint16_t rect_ye=YS + height - 1;
|
||
|
||
TFT_DrawBlock(rect_xs, rect_ys, rect_xe, rect_ye, blockColor);//绘制边框
|
||
TFT_FillSingleColor((rect_xs+1), (rect_ys+1), (rect_xe-1), (rect_ye-1), fillColor);//绘制内部填充
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :八分对称法
|
||
* @note :--画出给定点的八分对称点(画圆基础算法)
|
||
* @param :XC , 圆心行坐标
|
||
YC , 圆心列坐标
|
||
X , 给定点
|
||
Y , 给定点
|
||
color, 颜色
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/04
|
||
* @design :
|
||
**/
|
||
static void TFT_Circle8Point(uint16_t XC, uint16_t YC, uint16_t X, uint16_t Y, uint16_t color)
|
||
{
|
||
//直角坐标系第一象限x轴开始,逆时针旋转!
|
||
TFT_FastDrawPoint((XC+X), (YC+Y), color);//1
|
||
TFT_FastDrawPoint((XC+Y), (YC+X), color);//2
|
||
TFT_FastDrawPoint((XC-Y), (YC+X), color);//3
|
||
TFT_FastDrawPoint((XC-X), (YC+Y), color);//4
|
||
TFT_FastDrawPoint((XC-X), (YC-Y), color);//5
|
||
TFT_FastDrawPoint((XC-Y), (YC-X), color);//6
|
||
TFT_FastDrawPoint((XC+Y), (YC-X), color);//7
|
||
TFT_FastDrawPoint((XC+X), (YC-Y), color);//8
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :画圆
|
||
* @note :--本算法原理是递推公式,理解算法请Google圆算法公式推导!
|
||
* @param :XC , 圆心行坐标
|
||
YC , 圆心列坐标
|
||
R , 半径
|
||
color, 颜色
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/04
|
||
* @design :
|
||
**/
|
||
void TFT_DrawCircle(uint16_t XC, uint16_t YC, uint16_t R, uint16_t color)
|
||
{
|
||
uint16_t x=0, y=0;
|
||
float d=0;
|
||
|
||
//对半径进行限制:半径不得比圆心坐标绝对值大!
|
||
R = (R>XC) ? XC : R;
|
||
R = (R>YC) ? YC : R;
|
||
|
||
x = 0;
|
||
y = R;
|
||
d = 1.25f + R;
|
||
|
||
TFT_Circle8Point(XC ,YC, x, y, color);
|
||
while(x < y)
|
||
{
|
||
if(d < 0)
|
||
{
|
||
d += 2*x+3;
|
||
}else{
|
||
d += 2*(x-y)+5;
|
||
--y;
|
||
}
|
||
++x;
|
||
TFT_Circle8Point(XC, YC, x, y, color);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :改进画圆(避免浮点运算)
|
||
* @note :--避免浮点运算(轴上点不突进!)!
|
||
* @param :XC , 圆心行坐标
|
||
YC , 圆心列坐标
|
||
R , 半径
|
||
color, 颜色
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/04
|
||
* @design :
|
||
**/
|
||
void TFT_DrawCircle2(uint16_t XC, uint16_t YC, uint16_t R, uint16_t color)
|
||
{
|
||
uint16_t x=0, y=0;
|
||
int16_t d=0;//改进,避免浮点运算!
|
||
|
||
//对半径进行限制:半径不得比圆心坐标绝对值大!
|
||
R = (R>XC) ? XC : R;
|
||
R = (R>YC) ? YC : R;
|
||
|
||
x = 0;
|
||
y = R;
|
||
d = 3 - 2*R;
|
||
|
||
TFT_Circle8Point(XC ,YC, x, y, color);
|
||
while(x < y)
|
||
{
|
||
if(d < 0)
|
||
{
|
||
d += 4*x+6;
|
||
}else{
|
||
d += 4*(x-y)+10;
|
||
--y;
|
||
}
|
||
++x;
|
||
TFT_Circle8Point(XC, YC, x, y, color);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :四分对称法
|
||
* @note :--画出给定点的四分对称点(画椭圆基础算法);
|
||
* @param :XC , 椭圆中心行坐标
|
||
YC , 椭圆中心列坐标
|
||
X , 给定点
|
||
Y , 给定点
|
||
color, 颜色
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/04
|
||
* @design :
|
||
**/
|
||
static void TFT_Ellipse4Point(uint16_t XC, uint16_t YC, uint16_t X, uint16_t Y, uint16_t color)
|
||
{
|
||
//直角坐标系第一象限开始,逆时针旋转!
|
||
TFT_FastDrawPoint((XC+X), (YC+Y), color);//1
|
||
TFT_FastDrawPoint((XC-X), (YC+Y), color);//2
|
||
TFT_FastDrawPoint((XC-X), (YC-Y), color);//3
|
||
TFT_FastDrawPoint((XC+X), (YC-Y), color);//4
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :画椭圆
|
||
* @note :--本算法原理是递推公式,理解算法请Google椭圆算法公式推导!
|
||
* @param :XC , 椭圆中心行坐标
|
||
YC , 椭圆中心列坐标
|
||
A , 半长轴长度
|
||
B , 半短轴长度
|
||
color, 颜色
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/04
|
||
* @design :
|
||
**/
|
||
void TFT_DrawEllipse(uint16_t XC, uint16_t YC, uint16_t A, uint16_t B, uint16_t color)
|
||
{
|
||
int16_t x=0;
|
||
int16_t y=B;
|
||
|
||
float sqa=A*A;
|
||
float sqb=B*B;
|
||
float d=sqb+sqa*(-B+0.25);
|
||
|
||
TFT_Ellipse4Point(XC, YC, x, y, color);
|
||
while((sqb*(x+1)) < (sqa*(y-0.5)))
|
||
{
|
||
if(d < 0)
|
||
{
|
||
d += sqb*(2*x+3);
|
||
}else{
|
||
d += sqb*(2*x+3)+sqa*(-2*y+2);
|
||
--y;
|
||
}
|
||
++x;
|
||
TFT_Ellipse4Point(XC, YC, x, y, color);
|
||
}
|
||
|
||
while(y > 0)
|
||
{
|
||
if(d < 0)
|
||
{
|
||
d += sqb*(2*x+2)+sqa*(-2*y+3);
|
||
++x;
|
||
}else{
|
||
d += sqa*(-2*y+3);
|
||
}
|
||
--y;
|
||
TFT_Ellipse4Point(XC, YC, x, y, color);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :画16位bmp格式图片
|
||
* @note :--算法中心思想就是把两个8位数据整合成16位数据,然后写入tft!
|
||
* @param :XS , 图片左上角行坐标
|
||
YS , 图片左上角列坐标
|
||
width , 窗口宽度,必须大于0!
|
||
height, 窗口高度,必须大于0!
|
||
*PIC , 图片起始地址
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/06
|
||
* @design :
|
||
**/
|
||
void TFT_DrawPIC16(uint16_t XS, uint16_t YS, uint16_t width, uint16_t height, uint8_t *PIC)
|
||
{
|
||
/*
|
||
uint32_t i=0;
|
||
uint16_t color=0;
|
||
uint8_t picH=0, picL=0;
|
||
|
||
TFT_SetWindowSize(XS, YS, width, height);//窗口设置
|
||
|
||
TFT_SetCursor(XS, YS, XS+width-1, YS+height-1);//设置光标位置
|
||
TFT_StartWriteRAM();//开始写入GRAM
|
||
for(i=0; i<width*height; i++)
|
||
{
|
||
picL = PIC[i*2];//数据低位在前
|
||
picH = PIC[i*2 + 1];
|
||
color = TFT_RGB2BGR(picH<<8 | picL);
|
||
TFT_WR_DATA(color);
|
||
}
|
||
TFT_SetWindowSize(0, 0, TFTCmd.width, TFTCmd.height);//恢复显示窗口为全屏
|
||
*/
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :显示ASCII标准字体字符
|
||
* @note :--
|
||
* @param :X , 行起始坐标
|
||
Y , 列起始坐标
|
||
*style, 显示格式
|
||
CHAR , 待显示的字符
|
||
* @return :_TFTDisplayStyleStruct, 控制状态字
|
||
*
|
||
* @data :2017/03/04
|
||
* @design :梁宗南((SERI.LJI))
|
||
**/
|
||
_TFTDisplayStyleStruct TFT_DisplayCHAR(uint16_t X, uint16_t Y, _TFTDisplayStyleStruct *style, char CHAR)
|
||
{
|
||
_TFTDisplayStyleStruct ctl_handle;
|
||
|
||
uint16_t y_zero=Y;
|
||
uint8_t temp, byte_i, i;
|
||
uint8_t all_byte=(style->FontSize/8 + ((style->FontSize%8) ? 1 : 0))*(style->FontSize/2);//得到字体一个字符对应点阵集所占的字节数
|
||
|
||
///记录显示的格式:
|
||
ctl_handle.FC = style->FC;
|
||
ctl_handle.BC = style->BC;
|
||
ctl_handle.XS = X;
|
||
ctl_handle.YS = Y;
|
||
ctl_handle.XE = X + style->FontSize/2 - 1;
|
||
ctl_handle.YE = Y + style->FontSize - 1;
|
||
ctl_handle.FontSize = style->FontSize;
|
||
|
||
CHAR = CHAR - 0x20;//得到偏移后的值
|
||
for(byte_i=0; byte_i<all_byte; byte_i++)
|
||
{
|
||
if(style->FontSize == 12)
|
||
{
|
||
temp = asc_tft_1206[CHAR][byte_i];//1206字体
|
||
}
|
||
#ifdef _USE_FONT1608
|
||
else if(style->FontSize == 16){
|
||
temp = asc_tft_1608[CHAR][byte_i];//1608字体
|
||
}
|
||
#endif
|
||
#ifdef _USE_FONT2412
|
||
else if(style->FontSize == 24){
|
||
temp = asc_tft_2412[CHAR][byte_i];//2412字体
|
||
}
|
||
#endif
|
||
else{
|
||
temp = asc_tft_1206[CHAR][byte_i];//没有的字体统一用1206字体!
|
||
}
|
||
|
||
for(i=0;i<8;i++)
|
||
{
|
||
if(temp&0x80)
|
||
{
|
||
TFT_FastDrawPoint(X, Y, style->FC);//前景板
|
||
}else{
|
||
TFT_FastDrawPoint(X, Y, style->BC);//背景板
|
||
}
|
||
temp <<= 1;
|
||
Y++;
|
||
|
||
/*防止显示超区域的处理*/
|
||
if(Y >= TFTCmd.height)
|
||
{
|
||
ctl_handle.YE = 319;
|
||
return ctl_handle;
|
||
}
|
||
|
||
if((Y-y_zero) == style->FontSize)
|
||
{
|
||
Y = y_zero;
|
||
X++;
|
||
if(X >= TFTCmd.width){
|
||
ctl_handle.XE = 239;
|
||
return ctl_handle;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
return ctl_handle;
|
||
}
|
||
|
||
|
||
static uint16_t sys_strlen(char *pstr, char ch)
|
||
{
|
||
uint16_t num=0;
|
||
|
||
while(*(pstr+num) != ch)
|
||
{
|
||
num++;
|
||
}
|
||
|
||
return num;
|
||
}
|
||
|
||
/**
|
||
* @brief :显示ASCII标准字体字符串
|
||
* @note :--为了方便计算,字体宽高比统一都为1:2!
|
||
--统一以字符串结束符来作为结束!
|
||
* @param :X , 行起始坐标
|
||
Y , 列起始坐标
|
||
*style, 显示格式
|
||
*STR , 待显示的字符串指针
|
||
* @return :_TFTDisplayStyleStruct, 控制状态字
|
||
*
|
||
* @data :2017/03/04
|
||
* @design :
|
||
**/
|
||
_TFTDisplayStyleStruct TFT_DisplaySTR(uint16_t X, uint16_t Y, _TFTDisplayStyleStruct *style, char *STR)
|
||
{
|
||
_TFTDisplayStyleStruct ctl_handle;
|
||
|
||
uint16_t xx=X, yy=Y;//保护初始点的坐标值!
|
||
char *p=STR;//因为之后要改变STR指向的!
|
||
|
||
while((*STR <= '~') && (*STR >= ' '))//判断是不是非法字符!
|
||
{
|
||
if(*STR == '\0') break;//退出
|
||
|
||
ctl_handle = TFT_DisplayCHAR(X, Y, style, *STR);
|
||
X += style->FontSize/2;
|
||
++STR;
|
||
}
|
||
|
||
ctl_handle.XS = xx;//注意此处,恢复初始点坐标值!
|
||
ctl_handle.YS = yy;
|
||
ctl_handle.Num = sys_strlen(p, '\n');//获取显示字符个数,对于本函数,这条语句位置固定!
|
||
|
||
return ctl_handle;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :显示转化后的16进制数字
|
||
* @note :--显示位数为4位!
|
||
* @param :X , 行起始坐标
|
||
Y , 列起始坐标
|
||
*style, 显示格式
|
||
HEX , 待显示的数字
|
||
* @return :_TFTDisplayStyleStruct, 控制状态字
|
||
*
|
||
* @data :2017/03/04
|
||
* @design :
|
||
**/
|
||
_TFTDisplayStyleStruct TFT_DisplayHEX(uint16_t X, uint16_t Y, _TFTDisplayStyleStruct *style, uint16_t HEX)
|
||
{
|
||
_TFTDisplayStyleStruct ctl_handle;
|
||
|
||
uint8_t hex_num[5]={0, 0, 0, 0, '\n'};//多余的一个字节存放"\n",注意与oled不同!
|
||
uint8_t i=0;
|
||
|
||
for(i=0; i<4; i++)
|
||
{
|
||
switch((HEX>>(12-4*i)) & 0x000F)//从高位到低位依此转换为字符!
|
||
{
|
||
case 0: hex_num[i] = '0'; break;
|
||
case 1: hex_num[i] = '1'; break;
|
||
case 2: hex_num[i] = '2'; break;
|
||
case 3: hex_num[i] = '3'; break;
|
||
case 4: hex_num[i] = '4'; break;
|
||
case 5: hex_num[i] = '5'; break;
|
||
case 6: hex_num[i] = '6'; break;
|
||
case 7: hex_num[i] = '7'; break;
|
||
case 8: hex_num[i] = '8'; break;
|
||
case 9: hex_num[i] = '9'; break;
|
||
case 10: hex_num[i] = 'A'; break;
|
||
case 11: hex_num[i] = 'B'; break;
|
||
case 12: hex_num[i] = 'C'; break;
|
||
case 13: hex_num[i] = 'D'; break;
|
||
case 14: hex_num[i] = 'E'; break;
|
||
case 15: hex_num[i] = 'F'; break;
|
||
}
|
||
}
|
||
|
||
ctl_handle = TFT_DisplaySTR(X, Y, style, (char *)hex_num);//显示转换后的16进制数字
|
||
return ctl_handle;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :显示无符号的十进制数字
|
||
* @note :--
|
||
* @param :X , 行起始坐标
|
||
Y , 列起始坐标
|
||
*style, 显示格式
|
||
UINT , 待显示的数字
|
||
* @return :_TFTDisplayStyleStruct, 控制状态字
|
||
*
|
||
* @data :2017/03/04
|
||
* @design :
|
||
**/
|
||
static _TFTDisplayStyleStruct TFT_DisplayUINT(uint16_t X, uint16_t Y, _TFTDisplayStyleStruct *style, uint32_t UINT)
|
||
{
|
||
_TFTDisplayStyleStruct ctl_handle;
|
||
|
||
uint8_t dec_num[TFT_MAX_LENGTH_OF_DEC]={0};//最大显示TFT_MAX_LENGTH_OF_DEC位数!
|
||
uint8_t i=0, n=0, temp=0;
|
||
|
||
if(UINT == 0)//数字0为特殊情况,单独考虑!
|
||
{
|
||
dec_num[i++] = 0+0x30;
|
||
++n;
|
||
}else{
|
||
while((UINT/10) || (UINT%10))
|
||
{
|
||
dec_num[i++] = UINT%10+0x30;
|
||
UINT /= 10;
|
||
++n;
|
||
}
|
||
}
|
||
dec_num[i] = '\n';//添加字符串结尾符号!
|
||
|
||
n--;
|
||
for(i=0; i<=(n/2); i++)//倒序,以备显示!
|
||
{
|
||
temp = dec_num[i];
|
||
dec_num[i] = dec_num[n-i];
|
||
dec_num[n-i] = temp;
|
||
}
|
||
ctl_handle = TFT_DisplaySTR(X, Y, style, (char *)dec_num);//显示转换后的16进制数字
|
||
|
||
return ctl_handle;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :显示有符号的十进制数字
|
||
* @note :--
|
||
* @param :X , 行起始坐标
|
||
Y , 列起始坐标
|
||
*style, 显示格式
|
||
INT , 待显示的数字
|
||
* @return :_TFTDisplayStyleStruct, 控制状态字
|
||
*
|
||
* @data :2017/03/05
|
||
* @design :
|
||
**/
|
||
_TFTDisplayStyleStruct TFT_DisplayINT(uint16_t X, uint16_t Y, _TFTDisplayStyleStruct *style, int32_t INT)
|
||
{
|
||
_TFTDisplayStyleStruct ctl_handle;
|
||
|
||
uint16_t xx=X, yy=Y;//保护初始点的坐标值!
|
||
|
||
if(INT < 0)//若为负数!
|
||
{
|
||
TFT_DisplayCHAR(X, Y, style, '-');//显示'-'
|
||
ctl_handle = TFT_DisplayUINT((X+style->FontSize/2), Y, style, (uint32_t)(ABS(INT)));
|
||
|
||
ctl_handle.XS = xx;//注意此处,恢复初始点坐标值!
|
||
ctl_handle.YS = yy;
|
||
++ctl_handle.Num;//因为有个'-'号!
|
||
}else{
|
||
ctl_handle = TFT_DisplayUINT(X, Y, style, (uint32_t)(ABS(INT)));
|
||
}
|
||
|
||
return ctl_handle;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :显示可变精度的小数
|
||
* @note :--改进后的算法(先前正序分离小数,弊端,float向uint32_t转化丢失精度!)
|
||
--改进后的算法仍有精度问题,不可避免,只能不断减少误差,原因就是转化丢精度!
|
||
* @param :X , 行起始坐标
|
||
Y , 列起始坐标
|
||
*style, 显示格式
|
||
FLOAT , 待显示的数字
|
||
accu , 精确位数
|
||
* @return :_TFTDisplayStyleStruct, 控制状态字
|
||
*
|
||
* @data :2017/03/05
|
||
* @design :
|
||
**/
|
||
_TFTDisplayStyleStruct TFT_DisplayFLOAT(uint16_t X, uint16_t Y, _TFTDisplayStyleStruct *style, float FLOAT, uint8_t accu)
|
||
{
|
||
_TFTDisplayStyleStruct ctl_handle;
|
||
|
||
uint8_t float_a[TFT_MAX_LENGTH_OF_DEC];//最大显示TFT_MAX_LENGTH_OF_DEC位数,包括符号和小数点!
|
||
uint8_t temp[TFT_MAX_LENGTH_OF_DEC-2];
|
||
uint8_t i=0, float_i=0, temp_i=0;
|
||
|
||
float deci=0.0f;//小数
|
||
uint32_t inte=0;//整数
|
||
|
||
///判断是否为负数:
|
||
if(FLOAT < 0)
|
||
{
|
||
float_a[float_i++] = '-';
|
||
FLOAT = 0 - FLOAT;
|
||
}
|
||
|
||
inte = (uint32_t)FLOAT;
|
||
deci = FLOAT-inte;
|
||
|
||
///反序整数部分:
|
||
if(inte)
|
||
{
|
||
while(inte)
|
||
{
|
||
temp[temp_i++] = inte%10 + 0x30;
|
||
inte /= 10;
|
||
}
|
||
}else{
|
||
temp[temp_i++] = '0';
|
||
}
|
||
|
||
i = temp_i;
|
||
while(i--)
|
||
{
|
||
float_a[float_i++] = temp[--temp_i];//后面必须是--temp_i,原因:前一步中在写入数组后temp_i已经自加1!
|
||
}
|
||
|
||
///反序小数部分(改进后的算法,虽然速度较慢,但保证准确性!):
|
||
if(accu)
|
||
{
|
||
float_a[float_i++] = '.';//添加小数点
|
||
for(i=0; i<accu; i++){
|
||
deci *= 10.0f;
|
||
}
|
||
|
||
inte = (uint32_t)deci;
|
||
temp_i = 0;
|
||
while(accu--)
|
||
{
|
||
temp[temp_i++] = inte%10 + 0x30;
|
||
inte /= 10;
|
||
}
|
||
|
||
i = temp_i;
|
||
while(i--)
|
||
{
|
||
float_a[float_i++] = temp[--temp_i];//后面必须是--temp_i,原因:前一步中在写入数组后temp_i已经自加1!
|
||
}
|
||
}
|
||
|
||
///显示最后结果:
|
||
float_a[float_i] = '\n';
|
||
ctl_handle = TFT_DisplaySTR(X, Y, style, (char *)float_a);
|
||
|
||
return ctl_handle;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :移屏操作
|
||
* @note :--
|
||
* @param :*area , 移屏范围
|
||
direct, 移屏方向(_TFTScrollDirect枚举中定义类型!)
|
||
loop , 模式选择(1循环 0不循环)
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/05
|
||
* @design :
|
||
**/
|
||
void TFT_Move(_TFTDisplayStyleStruct *area, _TFTScrollDirect direct, uint8_t loop)
|
||
{
|
||
uint16_t row=0, column=0;
|
||
uint16_t temp=0;
|
||
|
||
if(direct == TFT_DIRECT_LEFT)
|
||
{
|
||
for(row=area->YS; row<=area->YE; row++)
|
||
{
|
||
temp = TFT_ReadPoint(area->XS, row);
|
||
for(column=area->XS; column<area->XE; column++){
|
||
TFT_FastDrawPoint(column, row, TFT_ReadPoint((column+1), row));
|
||
}
|
||
|
||
if(loop)//采用循环模式
|
||
{
|
||
TFT_FastDrawPoint(area->XE, row, temp);//填充首列的颜色!
|
||
}else{
|
||
TFT_FastDrawPoint(area->XE, row, area->BC);//填充背景色即可!
|
||
}
|
||
}
|
||
}else if(direct == TFT_DIRECT_RIGHT){
|
||
for(row=area->YS; row<=area->YE; row++)
|
||
{
|
||
temp = TFT_ReadPoint(area->XE, row);
|
||
for(column=area->XE; column>area->XS; column--){
|
||
TFT_FastDrawPoint(column, row, TFT_ReadPoint((column-1), row));
|
||
}
|
||
|
||
if(loop)//采用循环模式
|
||
{
|
||
TFT_FastDrawPoint(area->XS, row, temp);//填充首列的颜色!
|
||
}else{
|
||
TFT_FastDrawPoint(area->XS, row, area->BC);//填充背景色即可!
|
||
}
|
||
}
|
||
}else if(direct == TFT_DIRECT_UP){
|
||
for(column=area->XS; column<=area->XE; column++)
|
||
{
|
||
temp = TFT_ReadPoint(column, area->YS);
|
||
for(row=area->YS; row<area->YE; row++){
|
||
TFT_FastDrawPoint(column, row, TFT_ReadPoint(column, (row+1)));
|
||
}
|
||
|
||
if(loop)//采用循环模式
|
||
{
|
||
TFT_FastDrawPoint(column, area->YE, temp);//填充首列的颜色!
|
||
}else{
|
||
TFT_FastDrawPoint(column, area->YE, area->BC);//填充背景色即可!
|
||
}
|
||
}
|
||
}else if(direct == TFT_DIRECT_DOWN){
|
||
for(column=area->XS;column<=area->XE;column++)
|
||
{
|
||
temp = TFT_ReadPoint(column, area->YE);
|
||
for(row=area->YE; row>area->YS; row--){
|
||
TFT_FastDrawPoint(column, row, TFT_ReadPoint(column, (row-1)));
|
||
}
|
||
|
||
if(loop)//采用循环模式
|
||
{
|
||
TFT_FastDrawPoint(column, area->YS, temp);//填充首列的颜色!
|
||
}else{
|
||
TFT_FastDrawPoint(column, area->YS, area->BC);//填充背景色即可!
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :翻转操作
|
||
* @note :--只支持上下、左右翻转!
|
||
* @param :*area , 移屏范围
|
||
direct, 翻转方向(_TFTTurnDirect枚举中定义类型!)
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/05
|
||
* @design :
|
||
**/
|
||
void TFT_Turn(_TFTDisplayStyleStruct *area, _TFTTurnDirect direct)
|
||
{
|
||
uint16_t row=0, column=0;//指的偏移量!
|
||
uint16_t temp=0;
|
||
|
||
if(direct == TFT_TURN_L2R)
|
||
{
|
||
for(row=area->YS; row<=area->YE; row++)
|
||
{
|
||
for(column=0; column<=(area->XE - area->XS)/2; column++)//column指的偏移量!
|
||
{
|
||
temp = TFT_ReadPoint((area->XS + column), row);
|
||
TFT_FastDrawPoint((area->XS + column), row, TFT_ReadPoint((area->XE - column), row));
|
||
TFT_FastDrawPoint((area->XE - column), row, temp);
|
||
}
|
||
}
|
||
}else if(direct == TFT_TURN_U2D){
|
||
for(column=area->XS; column<=area->XE; column++)
|
||
{
|
||
for(row=0; row<=(area->YE - area->YS)/2; row++)//row指的偏移量!
|
||
{
|
||
temp = TFT_ReadPoint(column, (area->YS + row));
|
||
TFT_FastDrawPoint(column, (area->YS + row), TFT_ReadPoint(column, (area->YE - row)));
|
||
TFT_FastDrawPoint(column, (area->YE - row), temp);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :颜色替换操作
|
||
* @note :--注意,若对调前后颜色时,注意三者互换问题!
|
||
--也可用于检查颜色存在问题!
|
||
* @param :*area , 替换范围
|
||
SourceC, 替换前颜色
|
||
TargetC, 替换后颜色
|
||
* @return :uint8_t, 若替换的颜色不存在,返回1
|
||
*
|
||
* @data :2017/03/05
|
||
* @design :
|
||
**/
|
||
uint8_t TFT_ColorChange(_TFTDisplayStyleStruct *area, uint16_t src, uint16_t tgt)
|
||
{
|
||
uint16_t row=0, column=0;
|
||
uint8_t is_color=1;
|
||
|
||
for(column=area->XS; column<=area->XE; column++)
|
||
{
|
||
for(row=area->YS; row<=area->YE; row++)
|
||
{
|
||
if(TFT_ReadPoint(column, row) == src){
|
||
TFT_FastDrawPoint(column, row, tgt);
|
||
is_color = 0;
|
||
}
|
||
}
|
||
}
|
||
return is_color;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :颜色对调操作
|
||
* @note :--注意,若对调前后颜色时(自己书写时),注意三者互换问题!
|
||
--无法操作时,可能原因是临时替换颜色干扰!
|
||
--看到第三色时,正常现象!
|
||
* @param :*area, 替换范围
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/05
|
||
* @design :
|
||
**/
|
||
void TFT_ColorSwap(_TFTDisplayStyleStruct *area)
|
||
{
|
||
TFT_ColorChange(area, area->FC, TFT_SWAP_TEMP_COLOR);//临时替换颜色过渡!
|
||
TFT_ColorChange(area, area->BC, area->FC);
|
||
TFT_ColorChange(area, TFT_SWAP_TEMP_COLOR, area->BC);
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :对创建的结构体进行初始化
|
||
* @note :--在外部创建显示状态结构体,用本函数进行初始化!
|
||
--按照我的设计思路,由于 _TFTDisplayStyleStruct 结构体成员过大,赋值通过两个函数进行:
|
||
TFT_SetDisplayStyle(); //设置显示风格(在Display系列函数前调用!)
|
||
TFT_SetPosition(); //设置坐标(在区域相关系列函数前调用!)
|
||
--本函数是上述两个函数的综合,调用直接初始化成功,但格式只是白色背景、黑色画笔、1206字体;
|
||
* @param :*style, 需要初始化的结构体
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/08
|
||
* @design :
|
||
**/
|
||
void TFT_StyleStructInit(_TFTDisplayStyleStruct *style)
|
||
{
|
||
style->FC = BLACK; //黑色画笔
|
||
style->BC = WHITE; //白色背景板
|
||
|
||
style->XS = 0; //起始坐标(0,0)
|
||
style->YS = 0;
|
||
style->XE = 0; //终止坐标(0,0)
|
||
style->YE = 0;
|
||
|
||
style->Num = 0;
|
||
style->FontSize = 12; //1206字体
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :设置前后板颜色、字体大小
|
||
* @note :--在Display系列函数前调用,具体如下:
|
||
TFT_DisplayCHAR(); //字符
|
||
TFT_DisplaySTR(); //字符串(必须以'\n'结尾)
|
||
TFT_DisplayHEX(); //十六进制
|
||
TFT_DisplayINT(); //十进制
|
||
TFT_DisplayFLOAT(); //可变精度小数
|
||
* @param :penColor , 画笔颜色
|
||
backColor, 背景板颜色
|
||
fontSize , 字体大小
|
||
*style , 显示结构体(最终存放)
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/08
|
||
* @design :
|
||
**/
|
||
void TFT_SetColorFont(uint16_t penColor, uint16_t backColor, uint8_t fontSize, _TFTDisplayStyleStruct *style)
|
||
{
|
||
style->FC = penColor;
|
||
style->BC = backColor;
|
||
style->FontSize = fontSize;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :设置显示的坐标
|
||
* @note :--为方便直接修改使用,采用指针寻址修改方式!
|
||
--在区域相关系列函数前调用,具体如下:
|
||
TFT_Move(); //区域移屏
|
||
TFT_Turn(); //区域翻转
|
||
TFT_ColorChange(); //区域颜色变换
|
||
TFT_ColorSwap(); //区域颜色对调
|
||
TFT_Align(); //区域对齐
|
||
* @param :XS , 起点横坐标
|
||
YS , 起点纵坐标
|
||
XE , 终点横坐标
|
||
YE , 终点纵坐标
|
||
*style, 显示结构体(最终存放)
|
||
* @return :void
|
||
*
|
||
* @data :2017/03/08
|
||
* @design :
|
||
**/
|
||
void TFT_SetPosition(uint16_t XS, uint16_t YS, uint16_t XE, uint16_t YE, _TFTDisplayStyleStruct *style)
|
||
{
|
||
style->XS = XS;
|
||
style->XE = XE;
|
||
style->YS = YS;
|
||
style->YE = YE;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* @brief :区域对齐操作
|
||
* @note :--对齐方式在头文件中定义,参考word排版的思路,基础有6种,可组合!
|
||
--还需注意,调用函数前更换 area 中XS/YS/XE/YE,使其为对齐区域的范围!
|
||
--区域是无边框的,即显示的内容可与边界重合!
|
||
--若不对称,上边距比下边距多1个px!
|
||
* @param :*area, 对齐范围
|
||
align, 对齐方式(_TFTAlignMode枚举中定义类型!)
|
||
* @return :_TFTAlignStruct, 对齐操作后的起始点
|
||
*
|
||
* @data :2017/03/06
|
||
* @design :
|
||
**/
|
||
_TFTAlignStruct TFT_Align(_TFTDisplayStyleStruct *area, _TFTAlignMode align)
|
||
{
|
||
_TFTAlignStruct align_xy;
|
||
|
||
switch(align)
|
||
{
|
||
///垂直方向居中对齐,YS+Y偏移量:
|
||
case TFT_ALIGN_V_CENTER : align_xy.Y = ((area->YE - area->YS + 1) - area->FontSize)/2 + area->YS; break;
|
||
///垂直方向居上对齐,直接用区域的起始坐标YS:
|
||
case TFT_ALIGN_V_TOP : align_xy.Y = area->YS; break;
|
||
///垂直方向上居下对齐,显示字符的低侧与区域下边界重合:
|
||
case TFT_ALIGN_V_BOTTOM : align_xy.Y = area->YE - area->FontSize + 1; break;
|
||
|
||
///水平方向居中对齐,YS+Y偏移量(水平的字符宽度是高度的一半!):
|
||
case TFT_ALIGN_H_CENTER : align_xy.X = ((area->XE - area->XS + 1) - area->FontSize/2*area->Num)/2 + area->XS; break;
|
||
case TFT_ALIGN_H_LEFT : align_xy.X = area->XS; break;
|
||
case TFT_ALIGN_H_RIGHT : align_xy.X = area->XE - area->FontSize/2*area->Num + 1; break;
|
||
|
||
default : break;
|
||
}
|
||
return align_xy;
|
||
}
|
||
|
||
/* ******************** Copyright (C), 2017-2017, TYUT TSS-plan by SERI.LJI ******************** */
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|