TraSH/sim/simple/driver/Task_tft.c

1250 lines
32 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
******************************************************************************
*
* 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 ******************** */