GFX Forever:物联网 GFX 完整指南

本文档详述了物联网 GFX 图形库的使用,涵盖了从环境配置到驱动程序构建,再到不同显示设备的支持,包括 TFT_eSPI、Windows DirectX 和电子纸显示。文章深入探讨了 GFX 的核心概念,如绘制源、目标、像素类型和绘图元素,并介绍了字体、图片加载及异步操作。此外,还提供了示例代码和下载链接,以帮助开发者更好地理解和应用 GFX 库。
摘要由CSDN通过智能技术生成

GFX Forever:物联网 GFX 完整指南

文章末尾有代码和示例下载链接。

GFX 可在任何地方使用,无论是 PC 机还是物联网设备,以及介于两者之间的所有设备。它是跨平台的,可以使用 GCC 或 Clang 进行编译,并且应该是标准 C++14(首选 17)。它是独立于设备的,允许您制作自己的驱动程序。它将以减少驱动程序工作所需的 I/O 量的方式使用这些驱动程序,无论是 SPI 还是 I2C。不仅它可以在任何地方绘制,甚至可以将 ASCII 绘制到控制台或串行端口。

介绍

要为物联网设备找到图形库更快、更好的图形库。最流行的可能是 Adafruit_GFX,但它并不是最好的。它非常简约,不是很优秀,并且没有完全解耦的驱动程序接口。此外,由于与 Arduino 框架绑定,它无法利用可提高性能的平台特定功能,例如能够在 ESP32 上基于中断和轮询的 SPI 事务之间切换。

另一方面,GFX 不与任何东西绑定。它可以在任何平台上的任何地方绘图。它基本上是标准的 C++,以及诸如线条绘制和字体绘制算法之类的东西。如果没有驱动程序,它只能绘制内存位图,但是一旦添加驱动程序,您就可以像绘制位图一样直接绘制到显示器上。

所需环境

需要安装了 Platform IO 扩展的 Visual Studio Code。需要一个连接有 ILI9341 LCD 显示屏、SSD1306 显示屏或其他显示屏的 ESP32。

推荐Espressif ESP-WROVER-KIT开发板,它具有集成的 ILI9341 显示屏和其他几个预接线的外围设备,以及集成的调试器和具有更快上传速度的卓越 USB 转串行桥。集成调试器虽然与 PC 相比非常慢,但比连接到标准 WROVER 开发板的外部 JTAG 探针要快。

然而,大多数人都会使用一种或多种通用 esp32 配置。首先决定您要使用哪个框架 - ESP-IDF 还是 Arduino。在 VS Code 的蓝色栏中的屏幕底部,有一个配置切换器。应将其设置为默认值才能启动,可以通过单击默认值来更改它。许

多配置的列表将从屏幕顶部下拉。从那里,您可以根据附加的显示来选择您拥有的通用 esp32 设置,以及您想要使用的框架。

为了连接所有这些,请参阅Wiring_guide.txt  ,其中包含 SPI 和 I2C 显示器的显示接线。请记住,一些显示器供应商使用非标准名称命名其引脚。例如,在某些显示器上MOSI可能标记为DINA0。必须进行一些搜索查询才能找到您设备的详细信息。

在运行它之前,您必须在平台 IO 侧栏 - 任务下上传文件系统映像。

目前支持以下配置。在构建之前选择您要使用的:

  • esp-idf-esp-wrover-kit
  • esp-idf-lilygo-ttgo
  • esp-idf-ST7735
  • esp-idf-ILI9341
  • esp-idf-ST7789
  • esp-idf-SSD1306
  • esp-idf-SSD1351
  • esp-idf-MAX7219*
  • esp-idf-GDEH0154Z90
  • arduino-esp-wrover-kit
  • arduino-lilygo-ttgo
  • arduino-lilygo-t5_v22
  • arduino-ILI9341
  • arduino-ILI9341-P8
  • arduino-DEPG0290B
  • arduino-MAX7219*
  • arduino-GDEH0154Z90
  • arduino-ST7789
  • arduino-SSD1306
  • arduino-SSD1306-i2c
  • arduino-SSD1351
  • arduino-ST7735
  • arduino-RA8875
  • ardiuino-waveshare5in65
  • arduino-TFT_eSPI
  • arduino-wio-terminal
  • Windows DirectX

MAX7219的CS引脚是15,而不是5。驱动器是实验性的,多行段不起作用,但单行中的多个段可以工作。

使用 TFT_eSPI 构建

Bodmer 的 TFT_eSPI 可能是 Arduino 框架最快的 TFT 驱动程序。它确实是一个很棒的产品,但它的工作方式与 GFX 有很大不同,并且具有不同的功能。借助该gfx_tft_espi驱动程序,您可以将 GFX 与 TFT_eSPI 结合使用,享受更高的帧速率和更多受支持的显示器,同时利用 True Type 和灵活的像素格式等 GFX 功能。

出于多种原因,我不向该发行版提供 Bodmer 的库,并且我不建议通过lib_deps/使用平台 IO 的自动安装程序获取它来使用它。从这里的 Bodmer 的 Github 存储库下载它 并将其放在 gfx_demo 项目中的 libs 文件夹下。切换到 arduino-TFT_eSPI 配置。只要该库位于该文件夹中,其他项目就不会构建。不幸的是,我还没有找到一种方法可以在不修改 TFT_eSPI 本身的情况下使用 PlatformIO 解决这个问题,这是不可能的。

过程如下:

  • 下载库并解压缩。
  • 将其放在 /lib 下(TFT_eSPI-master 文件夹应位于 gfx 文件夹旁边)
  • 将您的配置切换到 arduino-TFT_eSPI
  • 通过在库文件夹下的 User_Setup.h 中设置显示屏和引脚来配置 TFT_eSPI 库。
使用 Windows 和 DirectX 进行构建

首先进入 PlatformIO/Quick Access/Miscellaneous/PlatformIO Core CLI,打开一个新控制台并输入:

bat

pio platform install "windows_x86"

转到您的项目,然后打开/src/windows/directx_demo.hpp。 到达那里后,进行更改 #define FONT_PATH "Maziro.ttf" 以使路径与该字体文件的完整路径匹配,该文件将位于/fonts文件夹下。

接下来,由于 Microsoft 的 C++ 编译器和 GCC 之间的不一致,这有点棘手。您必须修补系统标头,否则您的程序将崩溃。该补丁不会伤害其他程序,事实上,如果使用 GCC 编译,其他程序仍然会在修补的标头上崩溃。这是因为您必须进行定义 WIDL_EXPLICIT_AGGREGATE_RETURNS 才能使修补后的代码生效。

现在您需要构建 Windows 配置以确保 PlatformIO 拥有所需的所有文件。

接下来,您需要找到 PlatformIO 系统头文件d2d1.h的副本。您可以通过打开windows/drivers/dxd2d.hpp并找到#include <d2d1.h>并右键单击文件名并选择“转到定义”来完成此操作。在那里,右键单击它的选项卡以复制完整路径。

接下来使用 Windows 搜索栏搜索记事本,右键单击结果,然后单击“以管理员身份运行”。

打开后,打开一个文件,将路径粘贴到对话框中,然后按 Enter 键。

转到 VS Code,复制d2d1_patched_minigw.h的内容 并将其粘贴到记事本实例中。最后,保存。

现在转到 PlatformIO 并清理您的项目。这是必须要做的。

现在您可以构建一个工作应用程序。请记住,Windows 在流程方面与 IoT 应用程序的工作方式截然不同。您必须渲染WM_PAINT事件的每一帧,因此该演示的结构与其他演示有很大不同,它使用状态机从行演示中创建一个协程。

为了运行该应用程序,请再次打开控制台。然后你需要输入以下命令:

bat

.pio\build\windows-DirectX\program.exe

由于 DirectX 和 GFX 之间的“极性不匹配”,该驱动程序速度不是很快。 DirectX 的工作方式与 GFX 有很大不同,并且弥合差距的效率并不高。该驱动程序适用于原型屏幕,因此它非常有效,因为它缩短了构建时间并消除了上传时间。

电子纸显示支持

黑白电子纸显示驱动程序可以虚拟化扩展的位深度,以通过抖动模拟灰度。驱动程序的最终模板参数指示位深度,默认为 1,这会禁用抖动。

某些彩色电子纸显示屏会抖动,或者会匹配调色板中最接近的颜色。如果您需要更好的抖动性能,您可以在针对电子纸显示器调色板的绘画程序中对 JPEG 进行预抖动,然后禁用虚拟化。最后的模板参数指示您想要虚拟化的颜色像素的像素类型。

请记住,虚拟化位深度越高,驱动程序将使用的内存就越多。

大多数这些驱动程序都有附加功能,例如sleep()没有draw::访问器。您必须直接与驱动程序通信才能访问这些功能。

解耦总线和 8 位并行支持

较新的 Arduino 驱动程序支持新的驱动程序框架,因此可以在 I2C、8 位并行或 SPI 下运行。 SPI 还具有 DMA 功能,并且比旧的基于 SPI 的框架性能更好,并且可以从支持它的设备中读取数据。

使用它需要一些额外的步骤,因为驱动程序独立于总线。

首先,包含 I/O 标头:

C++

#include "drivers/common/tft_io.hpp"

您必须初始化您的总线。请记住,并行的数据和 DR 引脚存在限制。为了安全起见,它们应该在 GPIO 范围 0-31 内才能工作。我已经包含了使它们可以正常工作的代码,但我还没有对其进行测试。

初始化 SPI 总线(在 ESP32 上):

C++

using bus_type = tft_spi_ex<VSPI,PIN_NUM_CS,PIN_NUM_MOSI,PIN_NUM_MISO,PIN_NUM_CLK,SPI_MODE0,true,320*240*2+8>;

以上初始化了 VSPI 上的总线并使用 DMA。

初始化并行总线类似,只是您需要的只是引脚号。

实例化总线类型后,将其传递给驱动程序模板:

C++

using lcd_type = ili9341<PIN_NUM_DC,PIN_NUM_RST,PIN_NUM_BCKL,bus_type,3>;

有关这方面的信息,请参阅此处

概念

以下是高级摘要。有关更详细的信息,我一直在制作一个从链接开始的系列。

绘制来源和目的地

GFX 引入了绘制源和目的地的概念。这些是模糊或松散定义的类型,公开一组允许 GFX 绑定到它们以执行绘图操作的成员。它们公开的成员集根据其功能而有所不同,并且 GFX 会适应以目标支持给定操作的最有效方式调用它们。 GFX 中的绘图函数采用目标,而某些操作(例如复制位图像素数据或以其他方式读取像素信息)采用源。

代码大小与您拥有多少种不同类型的源和目标以及您在它们之间进行的绘图或复制类型有关。您的来源和目的地越多样化,代码就越大。

绘制源和目标包含在内存位图和显示驱动程序中,但您可以自行设计。我们稍后会讨论如何进行。

位图

位图是一种通用的绘制源/目标。它们基本上允许您将绘制的数据保存在内存中,然后您可以在其他地方绘制这些数据。位图不拥有自己的内存。这是因为并非所有内存都是一样的。例如,在某些平台上,为了能够将位图发送到驱动程序,位图数据必须存储在支持 DMA 的 RAM 中。另一个原因是你可以回收缓冲区。当您使用完一个位图后,您可以将内存重新用于另一个位图(只要它足够大),而无需取消分配或重新分配。缺点是会稍微增加代码复杂性,其中您必须确定位图所需的大小,然后自己为其分配内存,并可能稍后自己释放它。

驱动

驱动程序通常是一个更有限的绘制目标,但可能具有性能特征,GFX 将在可用时使用这些特征。您可以使用成员检查绘图源和目标有哪些功能可用,caps以便您可以为作业和设备调用正确的方法。如果您使用draw为您完成所有工作的类,则无需担心这一点。驱动程序在一次操作中可以采用的位图大小或因设备而异的性能特征方面可能具有某些限制。我尽可能地尝试使不同来源/目的地的使用它们保持一致,但是某些设备(例如电子纸显示器)差异很大,因此在使用它们时必须小心,以便以正确的方式使用它们最有效率。

自定义

您只需编写一个具有适当成员的类即可实现您自己的绘制源和目标。我们将在最后介绍这一点。

像素类型

GFX 中的像素可以采用您能想象到的任何形式,直至您的机器的最大字长。它们的每位最多可以有一个通道,并且将采用您指定的任何二进制占用空间。如果您想要 3 位 RGB 像素,您可以轻松制作一个,然后创建该格式的位图 - 每 9 位有 3 个像素。您永远不必担心该库是否可以支持您的显示驱动程序或文件格式的像素和颜色模型。使用 GFX,您可以定义像素的二进制占用空间和通道,然后只需告诉 GFX 如何在 RGB* 之间进行转换,即可扩展 GFX 以支持其支持的 4 种颜色模型之外的其他颜色模型。

*考虑了索引像素格式,但有一定的限制,使用它们时必须小心,因为它们需要关联的调色板才能解析为颜色。

当您声明像素格式时,它就会成为使用它的任何内容的类型签名的一部分。例如,使用 24 位像素格式的位图与使用 16 位像素格式的位图是不同的类型。

因此,您拥有的像素格式越多,代码大小就越大。

Alpha混合

如果您创建带有 Alpha 通道的像素,它将在支持的目标上受到尊重。并非所有设备都支持实现此功能所需的功能。它也是一个性能杀手,如果没有硬件支持,就无法提高速度,目前任何受支持的设备都无法获得硬件支持。通常,最好在位图上进行 Alpha 混合,然后将位图绘制到驱动程序,因为性能问题以及许多驱动程序当前不充当绘制源,因此无法进行 Alpha 混合。

索引颜色/调色板支持

一些绘制目标使用索引颜色方案,其中它们可能具有 16 种活动颜色,例如从 262,144 种可能颜色的调色板中选取的颜色。或者它们可能有一组固定的 8 种活动颜色,仅此而已。活动颜色是在任何给定点可以显示的所有颜色。这在帧缓冲区大小有限的旧系统上很常见。某些物联网显示硬件也可能出现这种情况,尤其是彩色电子纸显示器。我见过的电子纸显示屏范围从 2 色(单色)到 7 色。

使用索引像素的绘制目标pixel_type - 也就是说,具有带有 of 通道的像素的设备channel_nameindex预计会公开一个palette_type 类型别名,指示它们正在使用的调色板的类型,以及palette_type* palette() const返回一个方法指向当前调色板的指针。

当您绘制到具有索引像素的目标时,系统会尽最大努力将请求的颜色与调色板中的活动颜色之一进行匹配。它将匹配它找到的最接近的颜色。这不是免费的。它非常消耗 CPU 资源,因此买家要小心,尤其是在将 JPEG 或其他内容加载到索引目标中时。它将必须对每个像素运行最接近的匹配,为每个像素扫描一次调色板!

您必须小心索引颜色。它们不能单独使用,因为如果没有调色板,您就没有足够的信息来从中获取颜色。绘制目标可以具有调色板,因此索引像素和匹配绘制目标的组合会产生有效的颜色。因此,您不能使用color<>带有索引颜色的模板,因为如果没有调色板,就无法知道什么索引值最对应,例如old_lace,甚至white。当您尝试在无法使用索引像素的地方使用索引像素时,您可能会遇到编译错误,但更糟糕的情况是,在尝试绘制时在运行时会出现错误。当尝试绘画时,这通常不需要太担心。 

如果您必须自己将索引像素转换为其他类型的像素,可以使用convert_palette_from<>()convert_palette_to<>()convert_palette<>()。这些将在索引颜色之间进行转换,可选地在此过程中进行 alpha 混合。他们采用绘制目标来访问调色板信息。

绘图元素

绘图元素只是可以绘制的东西,例如直线和圆形。

基础

绘图基元包括线、点、矩形、圆弧、椭圆和多边形,除了前两种之外,还有填充和未填充的种类。大多数采用边界矩形来定义其范围,对于某些圆弧和直线,矩形的方向将改变元素的绘制位置或方式。

绘制来源

再次绘制源,是位图之类的东西,或者支持读取操作的显示驱动程序。这些可以被绘制到绘制目的地,再次像其他支持写入操作的位图或显示驱动程序一样。绘制操作中使用的源和目标组合的不同类型越多,代码大小就越大。绘制这些时,目标矩形的方向指示是否沿水平轴或垂直轴翻转绘图。绘图还可以调整大小、裁剪或转换像素格式。

字体

GFX 支持两种类型的字体。它支持快速光栅字体和 True Type 或 Open Type 字体,具体取决于您的需要。如果您需要快速和肮脏,并且强调快速,请使用该类font。如果要以牺牲性能为代价获得美观、可扩展且可能具有抗锯齿功能的字体,请使用该类open_font

由于不同的功能和不同的性能考虑,每个的行为和设计都略有不同。例如,光栅字体始终分配在 RAM 或 PROGMEM 空间中。这是因为它们很小,因此它们将以最大速度运行。另一方面,TrueType 字体更大、更复杂,因此 GFX 将根据需要直接从文件中传输它们,以最小的 RAM 使用速度换取速度。与光栅字体不同,True Type 字体本质上不会加载到内存中,只会根据渲染文本的需要进行临时内存分配。

font和都open_font 可以从可读、可查找的流(例如file_stream.如果有的话,这会 比嵌入它们时font 稍微快一点或慢得多。open_font光栅字体是旧的 Windows 3.1 FON 文件,而 True Type 字体文件是与平台无关的 TTF 和 OTF 文件。

或者,您可以使用fontgen从字体文件创建 C++ 头文件。然后可以包含此标头,以便将字体数据直接嵌入到二进制文件中。这是静态资源而不是加载到堆中。这是在可能的情况下推荐的加载字体的方法,尤其是对于open_font.

绘制字体时,支持非常基本的终端控制字符,例如制表符、回车符和换行符。光栅字体可以在有背景或没有背景的情况下绘制,尽管使用背景绘制它们几乎总是要快得多,至少在绘制到显示器时是这样。

True Type 布局注意事项

True Type 字体在显示之前通常必须缩小其原始大小。您可以使用scale()传递所需字体高度(以像素为单位)的方法。

请注意,True Type 的尺寸和位置有些近似,因为它们并不总是反映您的想法。部分原因是数字排版的本质,部分原因是非商业字体文件中通常含有不良字体规格。通常需要一些尝试和错误才能使它们像素完美。

另请注意,与光栅字体不同,True Type 字体字形不限于边界框。它们可能会将字母的一部分悬垂到指定绘图区域之外,这可能会导致目标区域中字母的左边缘和上边缘被剪掉。幸运的是,您可以使用参数来绘制文本,offset以在绘图区域内偏移文本以避免这种情况,和/或调整文本的精确位置。

除了加载和提供有关字体的基本信息之外,font 和open_font类还允许您测量该字体中文本的特定区域需要多少空间。

图片

图像包括 JPEG 之类的内容,这是目前该库支持的唯一格式,尽管很快就会包含 PNG。

图像不是绘图元素,因为由于压缩或渐进存储数据之类的原因,将图像一次性加载到内存中或随机访问其中的像素数据都是不切实际的。

为了处理图像,您可以使用draw将图像的全部或部分绘制到目的地的类,或者您可以处理一次报告图像的一部分的回调,以及指示图像位置的位置。部分在图像内。例如,对于 JPEG,从左到右、从上到下的每个 8x8 区域都会返回一个小位图(通常为 8x8 左右)。每次收到一部分时,您都可以将其绘制到显示器或其他目标上,或者您可以对其进行后处理或其他任何操作。

目前与字体不同的是,没有工具可以创建将图像直接嵌入到二进制文件中的标题。这可能会在未来版本中添加。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值