📄 tft.c
字号:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "ecrsys.h"
#include "ads7846.h"
#include "tft.h"
#include "font.h"
#include "ftype.h"
#define TFT_WrCmd(cmd) (*(volatile unsigned char *)0x0c00000 = cmd)
#define TFT_WrDat(dat) (*(volatile unsigned char *)0x0c00002 = dat)
#define putpixel(x, y, color) Lcd_Draw_Pixel(x, y, color)
void Lcd_Draw_Pixel(int x, int y, unsigned char color);
void Lcd_Draw_HLine(int x0, int y, int x1, byte c);
void Lcd_Draw_Line(int x1,int y1,int x2,int y2, unsigned char c);
#define Lcd_Draw_VLine(x, y0, y1, c) Lcd_Draw_Line(x, y0, x, y1, c)
int Lcd_Draw_Char(byte qu, byte wei, byte size, byte font, byte color, int x0, int y0);
/*********************************************************************************
* Clear the mapped memory buffer of TFT
*********************************************************************************/
void TFT_ClrDispBuffer(void)
{
}
/*
********************************************************************************
* Initialize the TFT
* Clear the TFT display buffer
* Clear the TFT panel with TFT_Clear function
*
********************************************************************************
*/
void Init_TFT(void)
{
TFT_ClrDispBuffer(); /*Need add later*/
TFT_Clear(0x00); /*Clear the TFT with black background*/
}
/*********************************************************************************
* Clear the TFT display with specify color
* Input : color -- the color which used for background
*
*********************************************************************************/
void TFT_Clear(char color) //colorb: 背景色
{
unsigned char i,j; /*To save time for scanning fast*/
/*Write lower address*/
TFT_WrCmd(0x00);
TFT_WrDat(0x00);
TFT_WrCmd(0x01);
TFT_WrDat(0x00);
TFT_WrCmd(0x02);
/*------------------------------------------------------------------------------
此处为了加快屏幕的刷新速度,采用了重复代码的方式, 所以也把9"和12"的代码分开
此函数考虑了优化,请不要修改此函数
*-----------------------------------------------------------------------------*/
for ( i = 0; i < 240; i ++ )//当使用800*600的TFT屏时, 此处就不能直接使用常数了
{
for ( j = 0; j < 200; j ++)
{
TFT_WrDat(color);
TFT_WrDat(color);
TFT_WrDat(color);
TFT_WrDat(color);
TFT_WrDat(color);
TFT_WrDat(color);
TFT_WrDat(color);
TFT_WrDat(color);
#if (TFT_SIZE == TFT_12INCH) /*清除12"后面的120个点行*/
TFT_WrDat(color);
TFT_WrDat(color);
#endif
}
}
}
/*
判断是否为一个汉字的区
*/
bool TFT_Text_Qu_Judge(byte dat)
{
return (dat>=0xa1);
}
bool TFT_Text_Wei_Judge(byte dat)
{
return (dat>=0xa1);
}
// 取得一种字体的扩展度
byte TFT_Font_Get_Size(byte size)
{
size &= 0x0f;
if (size < 1)
size = 1;
else if (size > 8)
size = 1;
return (size);
}
/********************************************************************************
* 函数说明: 在LCD上面,显示一串字符, 注意不能换行显示
* 输入参数: text, len, font, size, effect, c, x0, y0
* size为横向和纵向扩展的倍数,其中低四位为纵向扩展的\
* 高四位为横向扩展的。(1~8, 取值非法时,表明以默认字体来显示)
* x0, y0表示为它的起始显示位置。
* typedef EFFECT{
* dir: 2; // 旋转显示, 有四种模式, 顺时针旋转90度,
* 逆时针旋转90度, 和倒置显示, 注意: 当
* 进行旋转和倒置的时候, 它的显示方向也是随之而变化
* 即有纵向的方向和横向的方向, 这一点与POS打印机不同.
* udl_line:1; // 下划线
* color_rvs:1;// 颜色反显的模式(不过这个需要知道背景色)
* blink: 1; // 闪烁, 也需要知道背景色, 比较难以实现
* };
* 目前, Effect的功能完全先保留, 先把扩展的功能先做上去
* 说明: 当显示中文字体的时候, 如果有ASCII码, 会取一个最相匹配的字体显示
* 输出参数: void
* 返回值: void
********************************************************************************/
void TFT_Lcd_Disp_Text(char *text, byte len, byte font, byte size, byte effect, byte c, int x0, int y0)
{
byte *dot_src; // 字库点阵首地址
byte qu=0, wei; // 汉字时使用,存储区和位
bool store_qu_flag = 0; // 是否存储区的标志
byte cur_font; // Current font, 在中文显示中, 也会有显示英文的情况
byte dot_buf[FONT_HOR_MAX*FONT_ELG_MAX/8]; // 开辟一个最大的行缓冲区.
word dot_dst_inc; // 打印一个字符时候的点长
byte i, j, k; // 循环变量
byte src_inc; // 字库的行增量
byte hor_size; // 横向扩展倍数
byte vrt_size; // 纵向扩展倍数
int x, y; // 当前显示的x, y增量
hor_size = TFT_Font_Get_Size(size>>4);
vrt_size = TFT_Font_Get_Size(size&0x0f);
// if(font != FONT_ASC_24x48)
// font = FONT_ASC_9x17;
while(len--)
{
// 取得字体的首地址
if (font == FONT_HZ_12x12 || font == FONT_HZ_16x16 || font == FONT_HZ_24x24) // 中文字体
{
font = FONT_HZ_16x16;
if (!store_qu_flag)
{
if (TFT_Text_Qu_Judge(*text) == TRUE)
{
qu = *text;
store_qu_flag = 1;
text++;
continue;
}
else
{
cur_font = FONT_HZ_ASC_8x16;
dot_src = (byte *)&Font_Addr[cur_font][(dword)(*text-0x20)*((Font_Size[cur_font][2]+7)>>3)*(Font_Size[cur_font][3])];
}
}
else
{
// 这里为了处理上的方便, 只要发现了区的判断是正确的, 则认为位也是正确的
wei = *text;
cur_font = font;
dot_src = (byte *)&Font_Addr[cur_font][((dword)(Font_Search_Offset(qu, wei)))*((Font_Size[cur_font][2]+7)>>3)*(Font_Size[cur_font][3])];
store_qu_flag = 0;
}
}
else // 英文字体
{
qu = ((*text < 0x20)? 0x20: *text); /*此处将控制字符使用空格表示*/
cur_font = font;
dot_src = (byte *)&Font_Addr[cur_font][(qu-0x20)*((Font_Size[cur_font][2]+7)>>3)*(Font_Size[cur_font][3])];
if((cur_font == BTN_DFT_FONT)&&(qu >= 0x80))//在显示特殊字符时, 需要取新的点阵地址, 目前只有9*17的点阵具有这些特殊字符的字库
Get_Font_Addr(qu, &((dword)dot_src));
}
text++;
// 根据所取得的点阵的首地址, 进行横向或者纵向扩展, 和字体效果的显示(目前,暂时还不支持字体效果)
src_inc = (Font_Size[cur_font][2]+7)>>3; // 每一种字体所需的移动变量
dot_dst_inc = (word)Font_Size[cur_font][0] * hor_size;
if (cur_font == FONT_HZ_16x16 ) // 中文字体
dot_dst_inc *= 2;
y = y0;
for (i = 0; i < Font_Size[cur_font][3]; i++) // 总共需要显示的行数,由于有些字库最后一行可能没有,这样就可以直接不用显示
{
memset(dot_buf, 0, FONT_HOR_MAX*FONT_ELG_MAX/8);
// 对点阵进行横向扩展
if (hor_size == 1) // 字体按照原始大小进行打印, 由于这种情况最多,所以为了节约时间,又单独进行了处理
{
memcpy(dot_buf, dot_src, src_inc);
dot_src += src_inc;
}
else // 字体有一定的扩展倍数
{
TFT_Font_Dot_ELg(dot_buf, dot_src, Font_Size[cur_font][2], hor_size); // 把扩展后的目标点阵拷贝到点阵缓冲区中。
dot_src += src_inc;
}
// 把转换后的点阵显示出来, 纵向扩展等于把一列进行重复显示就行了。
for (j = 0; j < vrt_size; j++) // 重复显示的列数
{
x = x0;
for (k = 0; k < dot_dst_inc; k++)
{
if (dot_buf[k>>3]&and_table2[k&0x07])
putpixel(x, y, c);
x++;
}
y++;
}
}
x0 += dot_dst_inc;
}
}
/*---------------------------------------------------------------------------*
* 显示带控制字的字符串.
* 按要求显示Str_Buf的内容.
* 注意 Str_Buf 的格式必须是 Str_Buf[2][2+2*MAX_BTN_DESC_LEN] ;
* 包含的信息有:
* 1. 共2行显示
* 2. Str_Buf的格式为
* Str_Buf[i][0] 表示当前行显示的字符长度
* Str_Buf[i][1] 表示当前行字符是否采用 Bold 显示
* Str_buf[i]+2 存放需要显示的字符串
* 此函数主要用于按键键名的显示.
*---------------------------------------------------------------------------*/
void Tft_Disp_Ctl_Str(char *Str_Buf, byte font, byte color, int x0, int y0, int x1, int y1)
{
char *src_buf; //取当前需要处理的字符串
byte qu, wei; //汉字时的区码
byte font_type = 0; // 1 -- 汉字, 0 -- 字符型(默认)
byte cur_font = font; // Current font, 在中文显示中, 也会有显示英文的情况
byte BOLD; //判断本行是否需要整行显示粗体(双宽字体)
byte size;
byte len, line;
byte i, k;
int x, y;
len = Str_Buf[2+2*MAX_BTN_DESC_LEN];//取第二行字符串的长度, 如果为0, 表示只有1行显示
line = (len) ? 2: 1;
y0 = y0 + (y1 - y0 - ((int)line)*Font_Size[cur_font][1])/2;//行数按中间对齐方式确定y的起始位置
if (font == FONT_HZ_12x12 || font == FONT_HZ_16x16 || font == FONT_HZ_24x24) // 中文字体
{
font = FONT_HZ_16x16;
font_type = 1;
}
for(k = 0; k < line; k++)
{
len = Str_Buf[k*(2+2*MAX_BTN_DESC_LEN)];
if(len == 0)
break;
BOLD = Str_Buf[k*(2+2*MAX_BTN_DESC_LEN) + 1];
x = x0 + (x1 - x0 - ((BOLD == BOLD_FONT)? 2: 1)*len*Font_Size[font][0])/2;//取当前行的横向起始位置
y = y0 + k*Font_Size[font][1];//取当前行的纵向起始位置
src_buf = Str_Buf + k*(2+2*MAX_BTN_DESC_LEN) +2;//取字符串
size = 1;
qu = 0;
wei = 0;
for(i = 0; i < len; i++)
{
wei = src_buf[i];
if(wei < 0x20)
{
if(wei == DB_BOLD_FONT)
{
size = 2;
continue;
}
else
wei = 0x20;
}
if (font_type == 1) // 中文字体
{
if(!qu)
{
if(Judge_Qu(wei) == TRUE)//如果判断为汉字
{
qu = wei;
if(size >1)i++;//跳过控制字
continue;
}
else
{
cur_font = FONT_HZ_ASC_8x16;
}
}
else
{
cur_font = font;
}
}
else
{
cur_font = font;
}
size = (((BOLD == BOLD_FONT)? (size*2) : size)&0x0f)|0x10;
x += Lcd_Draw_Char(qu, wei, size, cur_font, color, x, y);
size = 1;
qu = 0;
wei = 0;
}
}
}
/*---------------------------------------------------------------------------*
* 显示按键的名称. 需要考虑汉字
* 注意按键最多只允许18个字符,
* 共2行显示
* ASCII码使用 8*16 点阵字体, 标为9*17字体
* 汉字使用16*16 点阵字体
* Max_Len 表示当前字符串允许最大长度
* Text 的最后一个字符是Bold 标志
* 自动换行标准:找到最近的一个空格,如果没有空格,从本行最后一个字符处断开
*---------------------------------------------------------------------------*/
void Lcd_Cvt_Btn_Text(char *text, byte Max_Len,byte BOLD, byte color, int x0, int y0, int x1, int y1)
{
char src_buf[2][2+2*MAX_BTN_DESC_LEN];
byte font = BTN_DFT_FONT;
byte len;
byte Line_Max; //每行最大可显字符数
byte i, j;
len = Get_Desc_Len(text, Max_Len);
if(len > MAX_BTN_DESC_LEN)
len = MAX_BTN_DESC_LEN;
memset(src_buf, 0, 4+4*MAX_BTN_DESC_LEN);//缓冲区清0
Line_Max = (byte)( (x1-x0)/(Font_Size[font][0]));//取每行最大可显字符数.
if(len <= Line_Max/2)//需要显示的字符不超过半行,强制 使用Bold 显示
{
src_buf[0][0] = len;
src_buf[0][1] = BOLD_FONT;
memcpy(src_buf[0]+2, text, len);
Tft_Disp_Ctl_Str(src_buf[0], font, color, x0, y0, x1, y1);
return;
}
if(BOLD == BOLD_FONT)
{
if(len > 2*(Line_Max/2))//如果显示空间不够, 只能使用普通方式显示
BOLD = 0;
else
Line_Max = (Line_Max/2);//如果要求双宽显示, 最大可显长度减半
}
src_buf[0][1] = src_buf[1][1] = BOLD;
if(len <= Line_Max)//如果只用一行显示足够,
{
src_buf[0][0] = len;
memcpy(src_buf[0]+2, text, len);
Tft_Disp_Ctl_Str(src_buf[0], font, color, x0, y0, x1, y1);
return;
}
else //需要分行处理
{
byte Chk_Line(char *src, byte src_len, byte max_len);
// for(i = Line_Max; i>1; i--)
// {
// if(text[i] == 0x20)break;//查找本行的最后一个空格
// }
// if(i <= 1)//如果没有找到空格, 从最后一个字符处断开
// {
// i = Line_Max;
// if(text[Line_Max-1] < 0x20)//控制字符
// i = Line_Max-1;
// }
i = Chk_Line(text, len, Line_Max);
src_buf[0][0] = i;
memcpy(src_buf[0]+2, text, i);
if(text[i] == 0x20)i++;
text += i;
len -= i;
if(len > Line_Max)//如果剩余长度超过一行,
{
i = Chk_Line(text, len, Line_Max-1);
src_buf[1][0] = i;
memcpy(src_buf[1]+2, text, i);
src_buf[1][2+i] = '-';
}
else
{
src_buf[1][0] = len;
memcpy(src_buf[1]+2, text, len);
}
}
Tft_Disp_Ctl_Str(src_buf[0], font, color, x0, y0, x1, y1);
}
/*-----------------------------------------------------------------------------*
* 画一个单色位图
****
*-----------------------------------------------------------------------------*/
void TFT_LCD_Disp_LOGO(const char *Logo, byte color, int hor, int vrt, int x0, int y0)
{
int x, y;
int i, j;
byte k = 0;
y = y0;
for(i = 0; i < vrt; i++)//总行数
{
x = x0;
for(j = 0; j < hor; j++)
{
if((*Logo)&and_table2[k&0x07])
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -