文章目录
1. TFT_eSPI 驱动TFT屏幕
TFT_eSPI库支持Arduino、PlatformIO平台,兼容树莓派(RP2040)、STM32、ESP8266 和 ESP32,支持以下几种驱动芯片的TFT屏幕:
●ILI9163、9225、9341、9481、9486、9488
●ST7735、7789、7796
●SSD1351、1963
●HX8357D
●S6D02A1
通过修改TFT_eSPI库提供的配置文件User_Setup.h实现驱动TFT屏幕,结果如下:
引脚连接:
TFT | ESP8266 |
---|---|
DI(MOSI) | D7 |
SC (SCLK、SCK) | D5 |
CS | D8 |
RST | D4 、RST |
RS(DC、A0) | D3 |
BLK & VCC | 3.3V |
GND | GND |
Notes: 需要在User_Setup.h文件中做的修改主要有:
- 选定设备(IC)型号
- 屏幕尺寸
- 根据屏幕上的标签颜色选定初始化的定义(94-102行附近),有些可能会有小问题,这时候需要一个一个试(无奈)
- 是否有背光控制
- 找到引脚定义的地方(158行附近)并取消注释,按上述表格接线。如果TFT屏幕的 RST连接到MCU的 RST引脚上 需要将
#define TFT_RST -1
行取消注释 - 根据显示效果微调。看是否有黑白对调、蓝红转色等,如果有按文件提示取消相应行的注释
2. TFT_eSPI详解
2.1 文件配置
该库有User_Setup.h
和 User_Setup_Select.h
两个配置文件,支持 ①自定义参数或 ②使用已有配置 驱动TFT屏幕。
- User_Setup.h — 由自己定义设备使用的引脚,若使用此文件配置,则
User_Setup_Select.h
文件内容不要做修改,主要修改有以下几处:
- User_Setup_Select.h — 针对某些特定设备,已经配置好了参数。如果使用则需要将
#include <User_Setup.h>
一行注释掉,取消使用的设备的那一行即可使用,如下图。其实它的引脚连接方式等各种参数还可以在User_Setup文件夹下(红箭头指的)对应的文件里设置,但前提是你必须要了解每个参数的修改会带来什么样的效果。
2.2 类、常用函数
2.1.1 TFT_eSPI类
实例化 TFT_eSPI tft = TFT_eSPI(); //引入库,其引脚定义在User_Setup.h
1.初始化
//init() 和 begin() 等价
tft.begin(uint8_t)
tft.init(uint8_t)
2.清屏
tft.fillScreen(uint32_t); //用某一颜色填充屏幕
3.屏幕方向
tft.setRotation(uint8_t r); //设置显示图像方向,r可选参数为0、1、2、3
tft.getRotation(void); //读取当前旋转角度
4.颜色反转
tft.invertDisplay(bool i);//反转所有显示颜色i = 1反转,i = 0正常
5.绘制
- 绘制窗口
void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h), //起始坐标+宽高
void setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); //开始+结束坐标
void setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum = true); //设置 TFT 屏幕的裁剪区域
bool checkViewport(int32_t x, int32_t y, int32_t w, int32_t h); //检查指定区域在窗口中是否可见
int32_t getViewportX(void);
int32_t getViewportY(void);
int32_t getViewportWidth(void);
int32_t getViewportHeight(void);
bool getViewportDatum(void); //获取基准标志
void frameViewport(uint16_t color, int32_t w); //在宽度为 w 的视口内或外画一个框架。如果 w 为正,则在内绘制框架,w负,在外绘制。
在 setAddrWindow()之后使用,给绘制的窗口填充颜色。
//将颜色送到 TFT
void pushColor(uint16_t color),
void pushBlock(uint16_t color, uint32_t len); //画单一颜色的实心块
void pushPixels(const void * data_in, uint32_t len);//写入一组存储在内存中的像素
uint16_t readPixel(int32_t x, int32_t y);//读取 x,y 处像素的颜色并以 565 格式返回值
- 绘制图形
drawxxxx绘制空心图形,fillxxxx绘制实心图形(多数见名知意的函数不再注释)
void fillScreen(uint32_t); //绘制前先清屏
void drawPixel(int32_t x, int32_t y, uint32_t color) // 画点
void drawLine(int32_t xs, int32_t ys, int32_t xe, int32_t ye, uint32_t color)
void drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) //水平线
void drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) //垂直线
//矩形
void drawRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color),
void drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color),
void fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color);
void drawCircle(int32_t x, int32_t y, int32_t r, uint32_t color),
void fillCircle(int32_t x, int32_t y, int32_t r, uint32_t color),
//椭圆
void drawEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color),
void fillEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color),
//三角形 角 1 | 角2 | 角 3
void drawTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color);
void fillTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color);
- 绘制文字
//1.设置游标
void setCursor(int16_t x, int16_t y), // 为tft.print()设置光标
void setCursor(int16_t x, int16_t y, uint8_t font); // 为tft.print()设置光标、字号
//2.设置字体颜色
void setTextColor(uint16_t color), // 只设置字符(字形)颜色(背景不被覆盖)
void setTextColor(uint16_t fgcolor, uint16_t bgcolor),//设置字符(字形)前景色和背景色,设置背景颜色可以有效的防止数字叠在一起
//3.设置字号
void setTextSize(uint8_t size); //字号为 1~7 的整数,字库7是仿7段数码管的样式!!!
void setTextWrap(bool wrapX, bool wrapY = false); //打开(关闭)屏幕宽度(高度)中的文本换行
//4.设置文本基准位置(默认为左上角)
void setTextDatum(uint8_t datum);
uint8_t getTextDatum(void); //获取文本基准位置(默认为左上角)
// 5.绘制文字、数字
// 绘制前使用setTextDatum选定绘制位置,使用 setTextPadding() 清除旧的文本或数字
int16_t drawString(const char *string, int32_t x, int32_t y, uint8_t font),
int16_t drawString(const char *string, int32_t x, int32_t y),
int16_t drawString(const String& string, int32_t x, int32_t y, uint8_t font),
int16_t drawString(const String& string, int32_t x, int32_t y),
// 返回值是渲染文本的像素宽度
int16_t drawNumber(long intNumber, int32_t x, int32_t y, uint8_t font), // 使用指定字号绘制整数
int16_t drawNumber(long intNumber, int32_t x, int32_t y), // 使用当前字体绘制整数
int16_t drawFloat(float floatNumber, uint8_t decimal, int32_t x, int32_t y, uint8_t font),
int16_t drawFloat(float floatNumber, uint8_t decimal, int32_t x, int32_t y),
- 绘制图片(BMP、XBM)(存储于RAM数组、FLASH内)
//BMP图片
void drawBitmap( int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor), //在TFT上绘制存储在阵列中的图像
void drawBitmap( int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor, uint16_t bgcolor), //绘制带有前景色和背景色的图像
void drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor),
void drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor, uint16_t bgcolor), //绘制带有前景色和背景色的 XBM 图像
void setBitmapColor(uint16_t fgcolor, uint16_t bgcolor); // 为 1bpp sprites定义前景色、背景色
void readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data); //读取一个像素块到数据缓冲区,缓冲区为16位,大小至少为w *h
void pushRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data);//将一块已被readRect()读取的像素写入屏幕
//渲染存储在 RAM 数组中的图像或 Sprite
void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data);
void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data, uint16_t transparent);
//渲染存储在 FLASH (PROGMEM) 中的图像
void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data, uint16_t transparent);
void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data);
/*
*用于将 TFT 屏幕转储到 PC 文档
*读取屏幕的一个区域到缓冲区,每个像素返回8位的RGB颜色值
*将 w 和 h 设置为 1 以读取 1 个像素的颜色。数据缓冲区必须至少为 w *h *3 字节
*/
void readRectRGB(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data);
2.1.2 Sprite 类
Sprite 理论上是一个不可见的图形屏幕,它保存在处理器 RAM 中。图形可以绘制到 Sprite 中,就像它们可以直接绘制到屏幕上一样。Sprite 完成后,可以将其绘制到屏幕上的任何位置。如果有足够的 RAM,则 Sprite 可以与屏幕大小相同并用作帧缓冲区。默认情况下,精灵使用 16 位颜色,位深度可以设置为 8 位(256 色)或 1 位(任意 2 种颜色)以减少所需的 RAM。在 ESP8266 上,可以创建的最大 16 位彩色 Sprite 大约为 160x128 像素,这会消耗 40 KB 的 RAM。在 ESP32 上,16 位色深的 Sprite 限制为约 200x200 像素(~ 80KB),8 位色深的 sprite 限制为 320x240 像素(~76KB)。
可以创建一个或多个Sprite ,Sprite 可以是任何像素宽度和高度,仅受可用 RAM 的限制。16 位色深 Sprite 所需的 RAM 为(2 x 宽 x 高)字节,8 位色深 Sprite 所需的 RAM 为(宽 x 高)字节。 Sprite 可以根据需要在程序中动态创建和删除,这意味着可以在 Sprite 绘制在屏幕上后释放 RAM,然后可以运行更多 RAM 密集型基于 WiFi 的代码,并且正常的图形操作仍然可以工作。
将图形绘制到Sprite 中的速度非常快,对于熟悉示例 Adafruit “graphicstest”的人来说,用 160x128 Sprite 可以在 18ms 内完成整个测试。Sprite 使用示例可以在“examples/Sprite”文件夹中找到。Sprite 可以绘制到 TFT 中,其中一种颜色被指定为“透明”,这需要看 Transparent_Sprite_Demo 示例。
如果 ESP32 开发板安装了 SPIRAM(即 PSRAM),那么 Sprite 将使用 PSRAM 内存,并且可以创建大型全屏缓冲区 Sprite。全屏Sprite需要更长的时间来渲染(320 x 240 16 位Sprite大约需要 45 毫秒)!!!
上述是TFT_eSPI官方给的解释,简单理解为在运行速度较快的RAM中开辟的一、多个用于绘制文字、图形、图片的缓冲区。3中的函数绝大多数都可以供Sprite 使用,以下是Sprite 独有的函数:
TFT_eSprite yourSpriteName = TFT_eSprite(&tft);
1.创建、删除Sprite
创建sprite所需的内存是:
1位色深:1bit / pixel
4位色深:4bit / pixel
8位色深:1Byte / pixel
16 位色深: 2 Byte / pixel
//创建一个 宽x高像素 的sprite,返回一个指向RAM的指针
//如果需要,Sketch 可以将返回值转换为 (uint16_t*) 以获得 16 位深度
void* createSprite(int16_t width, int16_t height, uint8_t frames = 1);
void* getPointer(void);//如果未创建,则返回一个指向精灵或 nullptr 的指针,用户必须转换为指针类型
bool created(void); //如果精灵已经创建,则返回真
void deleteSprite(void);//删除精灵以释放 RAM
2.设置色深
//设置或获取颜色深度为 4、8 或 16 位。可用于更改现有精灵的深度,但会将其清除为黑色,如果重新创建精灵,则返回一个新指针。
void* setColorDepth(int8_t b);
int8_t getColorDepth(void);
3.调色板
//设置 4 位深度精灵的调色板。仅使用前 16 种颜色。
void createPalette(uint16_t *palette = nullptr, uint8_t colors = 16); // RAM中的调色板
void createPalette(const uint16_t *palette = nullptr, uint8_t colors = 16); // FLASH中的调色板
void setPaletteColor(uint8_t index, uint16_t color); //将单个调色板索引设置为给定的颜色
uint16_t getPaletteColor(uint8_t index);//获取给定调色板索引处的颜色
4.绘制
1.字符
void drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t font);//在 Adafruit GLCD 或 freefont 中绘制单个字符
//在屏幕上绘制一个 unicode 字形。任何 UTF-8 解码都必须在调用 drawChar() 之前完成
int16_t drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font);
int16_t drawChar(uint16_t uniCode, int32_t x, int32_t y);
2.滚动、旋转
//设置滚动区域,从左上角定义x,y,宽度和高度。颜色(可选,默认为黑色)用于填充滚动后的间隙
void setScrollRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t color = TFT_BLACK);
//滚动 定义区域 dx,dy 像素。负值向上、左滚动;正值向右、下滚动。向上、向下滚动是可选的(默认是没有向上/向下滚动)。
//Sprite 坐标系不移动,移动的是像素
void scroll(int16_t dx, int16_t dy = 0),
void setRotation(uint8_t rotation);//设置Sprite 的旋转坐标(仅适用于 1位色深的Sprite ) 显示器内部硬件中的 CGRAM 旋转
uint8_t getRotation(void);
//将 Sprite 的旋转副本推送到具有可选透明颜色的 TFT
bool pushRotated(int16_t angle, uint32_t transp = 0x00FFFFFF); // Using fixed point maths
//将 Sprite 的旋转副本推送到另一个具有可选透明颜色的不同 Sprite
bool pushRotated(TFT_eSprite *spr, int16_t angle, uint32_t transp = 0x00FFFFFF);
//获取此 Sprite 旋转副本的 TFT 边界框
bool getRotatedBounds(int16_t angle, int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y);
//获取此 Sprite 的旋转副本的目标 Sprite 边界框
bool getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min_x, int16_t *min_y,
int16_t *max_x, int16_t *max_y);
//获取旋转的 Sprite wrt 枢轴的 TFT 边界框
void getRotatedBounds(int16_t angle, int16_t w, int16_t h, int16_t xp, int16_t yp,
int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y);
uint16_t readPixel(int32_t x0, int32_t y0);//读取 x,y 处像素的颜色并以 565 格式返回值
uint16_t readPixelValue(int32_t x, int32_t y);//返回 x,y 处像素的数值(滚动时使用)
3.其他
TFT_eSPI类的绘制几何图形、线条等的函数Sprite都可以使用,重复的不再记录。
void fillSprite(uint32_t color); //用颜色填充sprite
//将图像(位图)写入sprite
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint16_t *data, uint8_t sbpp = 0);
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, const uint16_t *data);
//将精灵推到 x, y 处的 TFT
void pushSprite(int32_t x, int32_t y);
void pushSprite(int32_t x, int32_t y, uint16_t transparent);
bool pushSprite(int32_t tx, int32_t ty, int32_t sx, int32_t sy, int32_t sw, int32_t sh)
//将sprite推送到 x,y 处的另一个sprite。此函数在目标sprite (dspr) 类中调用 了pushImage()
bool pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y);
bool pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y, uint16_t transparent);
//与抗锯齿字体相关的函数
void drawGlyph(uint16_t code); //向sprite光标位置写入一个字符
void printToSprite(String string);//向sprite光标位置写入字符串
void printToSprite(char *cbuffer, uint16_t len);
int16_t printToSprite(int16_t x, int16_t y, uint16_t index);
3. OVERLAP模式驱动TFT
TFT_eSPI库设计的OVERLAP模式与 TFT 共享 ESP8266 的 FLASH SPI 总线,这是节省引脚的一种有效解决方案。具体配置如下:
此时的引脚连接为:
TFT | ESP8266 |
---|---|
DI(MOSI) | SD1、S1 |
SC (SCLK、SCK) | CLK、S2 |
CS | D3 |
RST | D4 、RST |
RS(DC、A0) | D5 |
BLK & VCC | 3.3V |
GND | GND |
效果如下: