运用 U8G2 与 TFT_eSPI 玩转 UINIO-Monitor 显示屏
UINIO-Monitor
同时拼接有 128×64
分辨率 SSD1315 驱动的
0.96 英寸 OLED 显示屏,160×80
分辨率
ST7735 驱动的 0.96 英寸 LCD
显示屏,240×240
分辨率 ST7789 驱动的 1.3
英寸 LCD 显示屏。以及采用相同驱动芯片,但是分辨率分别为
240×320
与 240×280
的 2.4 英寸以及 1.69 英寸
LCD 显示屏。所有屏幕全部板载有 0.5mm
间距的
FPC 柔性排线连接器,同时还引出 2.54mm
间距的直插排针,便于通过杜邦线快速搭建实验电路。
之前由我设计制作并且开源出来的 UINIO-MCU-ESP32C3 和 UINIO-MCU-ESP32S3 两款核心板,分别基于乐鑫科技的 ESP32-C3 (RISC-V) 与 ESP32-S3 (Xtensa) 微控制器(更多玩法可以参考之前撰写的 《基于 UINIO-MCU-ESP32 的 Arduino 进阶教程》 一文)。而本篇文章就会采用这两款核心板,以及乐鑫官方的 Arduino-ESP32 板级支持包,结合 U8G2 和 TFT_eSPI 两款开源显示库,帮助大家快速上手 UINIO-Monitor 系列里的 5 款显示屏。
0.96 英寸 OLED 显示屏
UINIO-Monitor 系列显示屏幕当中的 0.96 英寸
OLED(有机发光二极管,Organic Light-Emitting Diode)显示屏,分辨率为
128 × 64
像素,使用 I²C
总线进行通信,驱动集成电路采用的是香港晶门半导体(Solomon
Systech)的 SSD1315(可以同时兼容
SSD1306)。
注意:如果焊接上丝印为
0x78
的电阻 R20,就会把 I²C 从设备的地址配置为0x78
。相应的,如果焊接上0x7A
丝印的电阻 R19,则表示从设备地址为0x7A
。当使用 Arduino-ESP32 和 U8G2 库进行通信时,需要焊接上 R20,而 R19 位置留空。
该屏幕模组采用了日本特瑞仕(TOREX)的
XC6206P332MR 低压差线性稳压芯片,可以同时兼容
3.3V
与 5V
两种工作电压。屏幕在全亮状态下的工作电流约为
25mA
,而全部熄灭黑屏状态下的待机电流约为
1.5mA
。正是由于该屏幕工作电流较小,为了防止正负极反接导致稳压芯片损坏,所以串接了一枚型号为
1N5819 的肖特基二极管(额定正向电流为
1A
)作为防反接设计,具体电路设计可以参考如下的原理图(鼠标双击可以放大):
开始上手实践之前,需要把 UINIO-Monitor 上 0.96 英寸
OLED 显示屏的
SCK
、SDA
、GND
、VCC
引脚,分别与 UINIO-MCU-ESP32S3 核心板的
GPIO16
、GPIO17
、5V
、GND
引脚进行连接,后续 U8G2
库相关的示例代码都将会沿用这个连接关系:
注意:为了文章撰写与阅读的方便直观,UINIO-Monitor 当中的 0.96 英寸 OLED 显示屏,在后续 U8G2 库相关章节的内容里全部直接简称为 UINIO-Monitor。
U8G2 库开发速成
U8G2
是一款运行在嵌入式设备上的 Arduino 单色显示库,可以通过 Arduino
IDE 的【库管理器】直接进行安装。U8G2 库包含有
文字
、位图
、线/框/圆
的绘制方法,并且可以支持多种字体,显示内容时需要使用到微控制器的 RAM
作为缓冲区。除此之外,U8G2 库还内嵌有一个小巧的
U8x8
库,该库只能输出文本内容,并且只能显示固定像素大小的字体,不过显示内容时无需再使用微控制器的
RAM 存储器作为缓冲区。关于两个库的更多介绍,可以参考 《U8g2
Reference Manual》 和 《U8x8
Reference Manual》 两份官方文档。
u8g2() 构造函数
使用 U8G2
库的第一步是要根据当前使用的屏幕规格与总线通信方式,选择对应的
u8g2()
构造函数,从而实例化出相应的 u8g2
对象。本文以 UINIO-Monitor 当中 0.96 英寸 OLED
显示屏所需要使用到的 U8G2_SSD1306_128X64_NONAME_F_HW_I2C
硬件 I²C 类型和 U8G2_SSD1306_128X64_NONAME_F_SW_I2C
软件
I²C 类型为例进行讨论:
1 | /* 采用 SSD1306 驱动芯片,分辨率为 128*X*64,通信方式为软件 I²C 总线 */ |
注意:硬件 I²C 相比于软件 I²C 总线的显示刷新频率更高,渲染动画效果的时候更加顺滑。
事实上,U8G2 库的 Arduino C++
构造函数 u8g2()
,其返回值类型都遵循着统一的命名规则:
前缀 | 屏幕驱动芯片型号 | 分辨率 | 生产品牌 | 缓冲区大小 | 通信方式 |
---|---|---|---|---|---|
U8G2 |
SSD1306 |
128X64 |
NONAME |
F |
HW_I2C |
U8G2 |
SSD1306 |
128X64 |
NONAME |
F |
SW_I2C |
接下来的三个表格,分别展示了上述表格当中缓冲区大小、通信方式、显示旋转方向的具体参数信息:
缓冲区大小 | 功能描述 |
---|---|
1 |
占用 1 页的微控制器 RAM 作为缓冲区。 |
2 |
占用 2 页的微控制器 RAM 作为缓冲区(可以获得更快的显示刷新速度)。 |
F |
在微控制器 RAM 当中保存完整的显示帧(推荐在 RAM 存储空间足够大的场景下使用)。 |
显示旋转方向 | 功能描述 |
---|---|
U8G2_R0 |
不旋转,横向显示。 |
U8G2_R1 |
顺时针 90° 度旋转。 |
U8G2_R2 |
顺时针 180° 度旋转。 |
U8G2_R3 |
顺时针 270° 度旋转。 |
U8G2_MIRROR |
不旋转,横向显示,但是内容会被镜像。 |
通信方式 | 功能描述 |
---|---|
4W_SW_SPI |
四线制(Clock\Data\CS\DC )的软件模拟
SPI。 |
4W_HW_SPI |
四线制(Clock\Data\CS\DC )的硬件
SPI。 |
2ND_4W_HW_SPI |
第 2 个四线制的硬件 SPI。 |
3W_SW_SPI |
三线制(Clock\Data\CS )的软件模拟
SPI。 |
SW_I2C |
软件模拟的 I²C 总线通信。 |
HW_I2C |
硬件 I²C 总线通信。 |
2ND_HW_I2C |
第 2 个硬件 I²C 通信总线。 |
6800 |
采用 6800 协议的 8 位并行接口。 |
8080 |
采用 8080 协议的 8 位并行接口。 |
注意:如果当前没有连接重置输入引脚,那么就可以将构造函数中的
reset
参数,直接填写为U8X8_PIN_NONE
。
采用 u8g2()
构造函数创建 u8g2
类的时候,需要传入一系列的参数,下面表格就展示了这些参数的具体信息:
引脚参数 | 数据手册名称 | 功能描述 |
---|---|---|
clock |
SCL / SCLK ... |
SPI 或者 I²C 总线的时钟线。 |
data |
SDA / MOSI / SDIN ... |
SPI 或者 I²C 总线的数据线。 |
d0 ... d7 |
D0 ... D7 |
并行接口的数据线。 |
cs |
CS |
片选信号线。 |
dc |
D/C / A0 / RS, ... |
数据/命令选择线。 |
enable |
8080:WR / 6800:E |
8080 接口的 Write
写入线,6800 接口的 Enable 使能线。 |
reset |
- | 重置信号线。 |
U8G2 库默认使用 8 位显示模式(即
256 色),如果需要使用 16 位显示模式,则必须在
u8g2.h
头文件当中添加如下注释:
1 |
注意:16 位显示模式下,保存 U8G2 像素坐标的数据类型也会从 8 位变换为 16 位。
接下来,就会通过 Arduino C++ 和
U8G2 库,结合 UINIO-MCU-ESP32S3 和
UINIO-Monitor 实现一个显示
Hello UinIO.com!
字符串的示例:
1 |
|
u8x8() 构造函数
U8G2 所包含的 U8x8
库无需占用微控制器的 RAM
存储空间,可以用于直接显示一些文本信息。但是需要注意 u8x8()
构造函数的参数构成,与 u8g2()
构造函数并不相同:
1 | U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/16, /* data=*/17, /* reset=*/U8X8_PIN_NONE); |
U8x8 库的 Arduino C++ 构造函数
u8x8()
,其返回值类型都遵循着如下的命名规则:
前缀 | 屏幕驱动芯片型号 | 分辨率 | 生产品牌 | 通信方式 |
---|---|---|---|---|
U8G2 |
SSD1306 |
128X64 |
NONAME |
HW_I2C |
... | ... ... | ... ... | ... ... | SW_I2C |
观察可以发现,除了没有缓冲区大小设置相关的参数之外,u8x8()
构造函数的返回类型命名方式,与 U8G2 库的
u8g2()
构造函数基本保持一致。接下来同样可以通过
Arduino C++ 和 U8x8 库,基于
UINIO-MCU-ESP32S3 和 UINIO-Monitor
实现一个 Hello UinIO.com!
字符串显示的示例:
1 |
|
初始化工作
u8g2
类的 begin()
函数用于简化 Arduino
环境下的显示设置步骤,该函数在底层会依次调用
initDisplay()
、clearDisplay()
、setPowerSave()
三个函数:
1 | bool begin(void) |
begin()
函数还可以用于绑定按键检测事件(最高可以绑定 6
个按键),如果没有连接相应的按键,则对应的参数可以设置为
U8X8_PIN_NONE
:
1 | bool begin( |
除了 begin()
函数之外,u8g2
类还提供有如下的屏幕显示初始化函数:
API 方法 | 功能描述 |
---|---|
void setBusClock(uint32_t clock_speed); |
设置总线通信的时钟频率,I²C 总线可以尝试
200000 或者 400000 ,SPI 总线可以尝试
1000000 或者 8000000 。 |
void setContrast(uint8_t value) |
设置显示对比度,取值范围从
0 ~ 255 。 |
字体配置
U8G2 库使用的是点阵字体,使用时需要通过
setFont()
函数配置当前所要显示的字体,其中字体名称
u8g2_font_字体类型与字符集
的最后两个字符定义了字体的类型和字符集:
字体名称 | 助记词 | 字体类型 |
---|---|---|
u8g2_xxx_tx |
Transparent | 具有可变宽度的透明字体。 |
u8g2_xxx_mx |
Monospace | 等宽字体。 |
u8g2_xxx_hx |
Height | 具有可变宽度和共同高度的字体。 |
u8g2_xxx_8x |
8x8 | 位于 8x8 盒子当中的等宽字体。 |
字体名称 | 助记词 | 字符集 |
---|---|---|
u8g2_xxx_xe |
Extended | 包含 Unicode 编码 32 ~ 701
的字符。 |
u8g2_xxx_xf |
Full | 包含 Unicode 编码 32 ~ 255
的字符。 |
u8g2_xxx_xr |
Restricted | 包含 Unicode 编码 32 ~ 127
的字符。 |
u8g2_xxx_xu |
Uppercase | 只包含有数字和大写字母。 |
u8g2_xxx_xn |
Numbers | 包含日期和时间表达的数值与额外字符。 |
u8g2_xxx_x_something |
- | 特殊字体。 |
注意:U8G2 库不支持直接设置字体的大小,而是通过选用不同尺寸的字体来完成字体大小的控制。
如果需要通过 U8G2 库显示中文,则必须在 begin()
调用之后,print()
调用之前执行下面的方法,从而使能 UTF8
编码字符的显示输出,具体说明请参见下表所示:
API 方法 | 功能描述 |
---|---|
void enableUTF8Print(void) |
使能 UTF8 显示支持,从而可以通过
u8g2.print() 打印中文; |
void disableUTF8Print(void) |
失能 UTF8 显示支持,默认状态。 |
目前 U8G2 库已经包含了中文的文泉驿字体,可以同时支持
12
、13
、14
、15
、16
像素大小的字体:
u8g2_font_wqy(12~16)_t_chinese1
:只包含 U8G2 官方提供的小字符集。u8g2_font_wqy(12~16)_t_chinese2
:只包含 U8G2 官方提供的小字符集。u8g2_font_wqy(12~16)_t_chinese3
:只包含 U8G2 官方提供的小字符集。u8g2_font_wqy(12~16)_t_gb2312
:包含有完整的 GB2312 中文简体字符集。u8g2_font_wqy(12~16)_t_gb2312a
:仅包含 GB2312 的01
、02
和16 ~ 55
以及部分08
区编码,没有包含全角标点符号。u8g2_font_wqy(12~16)_t_gb2312b
:仅包含 GB2312 的1 ~ 55
区编码,其中10 ~ 15
属于空区,相比于gb2312a
会多出一些额外的符号。
注意:使用上述字体时,只需要将
(12~16)
部分替换为当前所需的像素大小即可。
除此之外,U8G2 库还可以支持 GNU 的 Unifont 点阵黑中文字体,不过这些字体的美观程度明显逊色于文泉驿字体:
u8g2_font_unifont_t_chinese1
:包含 U8G2 官方提供的小字符集。u8g2_font_unifont_t_chinese2
:包含 U8G2 官方提供的小字符集。u8g2_font_unifont_t_chinese3
:包含 U8G2 官方提供的小字符集。
下面的示例代码,就将会分别使用 u8g2_font_wqy16_t_gb2312
和 u8g2_font_wqy13_t_gb2312
两种字体,在
UINIO-Monitor 上面显示 "Hello UinIO.com!"
和 "你好,电子技术博客!"
两组字符串内容:
1 |
|
除了上面介绍的方法之外,U8G2 库还额外提供有如下几个字体显示相关的工具函数:
API 方法 | 功能描述 |
---|---|
u8g2_uint_t getMaxCharHeight(void) |
返回指定点阵字体里,最大的字体高度。 |
u8g2_uint_t getMaxCharWidth(void) |
返回指定点阵字体里,最大的字体宽度。 |
void setDrawColor(uint8_t color) |
参数 color 为 0
表示字体不亮背景亮,为 1 表示背景不亮字体亮(默认)。 |
显示坐标系统
显示坐标系统是 U8G2
库当中比较重要的概念,运用显示相关的函数时,需要特别关注其显示起始的坐标。当使用
u8g2
类的 print()
函数显示内容时,需要先运用
setCursor()
函数设置显示内容在 x
轴与
y
轴的起始像素坐标位置:
API 方法 | 功能描述 |
---|---|
void setCursor(u8g2_uint_t x, u8g2_uint_t y) |
设置显示内容的起始像素坐标位置。 |
void home(void) |
将光标放置到屏幕的左上角。 |
void clear(void) |
清除屏幕和缓冲区上的内容,并且将光标放置到左上角。 |
U8G2 库将屏幕的左上角作为坐标原点
(0, 0)
,显示内容将会沿着起始坐标位置分别向上和向右进行输出,例如下图左侧的代码分别将显示的起始坐标设置为
x = 0
与
y = 15
,最终渲染显示出来的结果如下面右图所示:
屏幕刷新方法
U8G2 库提供有 clearBuffer()
和
sendBuffer()
这组屏幕显示刷新的方法(刷新速度比较快,但是
RAM 空间占用较大):
API 方法 | 功能描述 |
---|---|
void clearBuffer(void) |
清除微控制器 RAM 帧缓冲区当中的所有内容。 |
void sendBuffer(void) |
将微控制器 RAM 帧缓冲区当中的内容发送至屏幕进行显示。 |
显示缓冲区操作相关的代码,都必须放置到 clearBuffer()
和
sendBuffer()
函数之间的区域:
1 | void loop(void) { |
除此之外,U8G2 库还提供了 firstPage()
与 nextPage()
来刷新屏幕显示内容(消耗的 RAM
空间相对较小):
API 方法 | 功能描述 |
---|---|
void firstPage(void) |
该命令是内容渲染循环的一部分,需要与
nextPage() 配合使用。 |
uint8_t nextPage(void) |
该命令是内容渲染循环的一部分,需要与
firstPage() 配合使用。 |
使用时即可以采用 do...while()
循环的方式来组合调用
firstPage()
与 nextPage()
函数:
1 | u8g2.firstPage(); |
也可以把 firstPage()
放置到 Arduino 草图代码的
setup()
函数当中,而 nextPage()
函数放置到
loop()
循环的内部:
1 | void setup() { |
文本输出函数
除了之前示例代码当中使用过的 print()
和
drawStr()
之外,U8G2
库还提供有如下一系列可以用于显示内容输出的方法:
API 方法 | 功能描述 |
---|---|
u8g2_uint_t drawStr(u8g2_uint_t x, u8g2_uint_t y, const char *s) |
在指定的坐标位置绘制字符串(不能绘制编码大于或等于 256 的字符),使用前必须指定字体。 |
u8g2_uint_t drawStrX2(u8g2_uint_t x, u8g2_uint_t y, const char *s) |
功能同上,只是绘制的字体大小加倍。 |
u8g2_uint_t drawUTF8(u8g2_uint_t x, u8g2_uint_t y, const char *s) |
绘制一个编码为 UTF-8
的字符串(中文),该函数能够绘制编码值大于 127
的字符。 |
u8g2_uint_t drawUTF8X2(u8g2_uint_t x, u8g2_uint_t y, const char *s) |
功能同上,只是绘制的字体大小加倍。 |
u8g2_uint_t drawGlyph(u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding) |
在指定的坐标位置绘制图像字符,需要配合特殊的图像字体一起使用。 |
u8g2_uint_t drawGlyphX2(u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding) |
功能同上,只是绘制的字体大小加倍。 |
void print(...) |
向当前的光标位置(通过
setCursor() 设置)写入指定字体(通过 setFont()
设置)的文本(需要调用 enableUTF8Print() 使能 UTF-8
编码)。 |
接下来的示例代码,就会分别采用上面表格当中介绍的各种工具函数,测试输出各种显示内容:
1 |
|
绘制位图
XBM(X-Bitmap)是一种通用的图像文件格式,可以通过一个
16 进制数组来表示二进制图像。U8G2 库提供的
drawXBM()
函数,可以直接用来绘制单色位图(图片在使用之前需要进行单值化处理和取模):
API 方法 | 功能描述 |
---|---|
void drawXBM(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, const uint8_t *bitmap) |
绘制 XBM 格式的位图,参数 x
和 y 表示位图的左上角,而 w 与 h
表示位图的宽高,参数 bitmap
表示取模之后得到的单色位图数组。 |
注意:通常会将
bitmap
数组变量定义为PROGMEM
类型,表示将其存储在 Flash 存储器当中,便于保存一些较大的位图数据,并且节省微控制器 RAM 的存储空间。
位图取模
drawXBM()
中的单色位图数组参数
bitmap
,可以通过取模工具软件 PCtoLCD2002
获取,具体操作步骤如下面列表所示:
- 调整分辨率:将图片转换为适配 OLED 屏幕的
128*64
分辨率。 - 转换单色位图:再将转换分辨率之后的图片处理为
.bmp
单色位图格式。 - 生成 XBM 数组:使用 PCtoLCD2002 工具软件对该单色位图进行取模,得到 XBM 数组。
- U8G2 绘制位图:调用
u8g2
类的drawXBM()
函数显示位图。
注意:可以采用更为方便的在线工具 image-to-bitmap-array 进行取模操作。
首先使用 Windows
操作系统自带的画图工具打开目标图片,然后点击顶部工具栏的【重新调整大小】,在弹出的对话框中选择【像素】,再将水平和垂直高度分别设置为
64
个像素:
完成位图尺寸的调整之后,鼠标依次点击 Windows 画图工具顶部菜单栏的【文件 → 另存为 → BMP 图片】:
在接下来弹出的【保存为】对话框当中,选择保存类型为【单色位图】的
.bmp
文件:
接着打开 PCtoLCD2002 取模软件,点击顶部工具栏上的【字模生成和液晶面板选项】按钮,在弹出的【字模选项】对话框当中进行如下设置:
最后,鼠标再次点击顶部工具栏上的【打开一个 BMP
图像】按钮,将刚才得到的 .bmp
单色位图文件导入,再点击【生成字模】按钮,就会在界面的底部区域得到
U8G2 库绘图所需的 XBM 数组:
把这里得到的位图数组赋值给下面示例代码的 Hank
变量,然后调用 drawXBM()
函数就可以进行位图的显示:
1 |
|
将上述代码下载到 UINIO-MCU-ESP32S3 核心板执行之后,显示到 UINIO-Monitor 的 OLED 屏幕内容如下面所示:
汉字取模
除了支持把位图转换为 XBM 数组之外,PCtoLCD2002 还能够把字符转换为 XBM 数组。首先在打开 PCtoLCD2002 取模软件之后,选择顶部菜单栏上的【模式 → 字符模式】:
接下来,依然需要点击顶部工具栏上的【字模生成和液晶面板选项】按钮,在弹出的【字模选项】对话框当中进行如下设置:
然后,选择字体为 楷体
,每一个字的宽度与高度都设置为
64
个像素,并且在中间的输入框填写汉字
成都
,点击【生成字模】按钮:
最后,把上述步骤得到的两个 XBM 数组,分别赋予如下示例代码当中的
Chengdu
和 Du
两个变量,再分别调用
drawXBM()
函数就可以完成显示:
1 |
|
这里同样将上述代码下载到 UINIO-MCU-ESP32S3 核心板运行,此时 UINIO-Monitor 的 OLED 屏幕显示结果如下面所示:
绘制基本图形
矩形绘制
U8G2 库提供了 drawBox()
和
drawFrame()
两个函数用于矩形的绘制:
矩形绘制 API | 功能描述 |
---|---|
void drawBox(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h) |
绘制一个实心的矩形,参数
x 和 y
表示矩形左上角的起始位置,而 w 和
h 分别表示其宽度与高度。 |
void drawFrame(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h) |
绘制一个空心的矩形,参数
x 和 y
表示矩形左上角的起始位置,而 w 和
h 分别表示其宽度与高度。 |
下面的示例代码会在 UINIO-Monitor 屏幕的左右两侧,分别绘制一个实心矩形和一个空心矩形:
1 |
|
圆形绘制
U8G2 库提供了 drawCircle()
和
drawDisc()
两个函数用于圆形的绘制:
圆形绘制 API | 功能描述 |
---|---|
void drawCircle(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t opt = U8G2_DRAW_ALL) |
以 (x0, y0)
位置为圆心,绘制一个半径为 rad
的空心圆,参数 opt
用于指定只绘制圆形的哪些部分。 |
void drawDisc(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t opt = U8G2_DRAW_ALL) |
以 (x0, y0)
位置为圆心,绘制一个半径为 rad
的实心圆,参数 opt
用于指定只绘制圆形的哪些部分。 |
下面的示例代码会在 UINIO-Monitor 屏幕的左右两侧,分别绘制一个实心圆形和一个空心圆形:
1 |
|
椭圆形绘制
U8G2 库提供了 drawEllipse()
和
drawFilledEllipse()
两个函数用于椭圆形的绘制:
椭圆形绘制 API | 功能描述 |
---|---|
void drawEllipse(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rx, u8g2_uint_t ry, uint8_t opt) |
以 (x0, y0)
作为圆心,位置绘制水平半径为 rx ,垂直半径为 ry
的空心椭圆(8 位显示模式下,两者取值必须小于
512)。 |
void drawFilledEllipse(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rx, u8g2_uint_t ry, uint8_t opt) |
以 (x0, y0)
作为圆心,位置绘制水平半径为 rx ,垂直半径为 ry
的实心椭圆(8 位显示模式下,两者取值必须小于
512)。 |
下面的示例代码会在 UINIO-Monitor 屏幕的左右两侧,分别绘制一个实心椭圆形和一个空心椭圆形:
1 |
|
直线绘制
U8G2 库提供了 drawHLine()
和
drawVLine()
以及 drawLine()
三个函数来绘制直线:
直线绘制 API | 功能描述 |
---|---|
void drawHLine(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w) |
基于 (x, y)
位置从左至右绘制一条长度为 w
像素的水平直线。 |
void drawVLine(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t h) |
基于 (x, y)
位置从下至上绘制一条长度为 w
像素的垂直直线。 |
void drawLine(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t x1, u8g2_uint_t y1) |
基于两个像素点的位置绘制一条直线,参数
(x0, y0) 是第 1 个点的坐标,而 (x1, y1) 则是第
2 个点的坐标。 |
下面的示例代码会在 UINIO-Monitor 屏幕上面,绘制呈现米字形交错的 1 条水平直线和 1 条垂直直线,以及 2 条斜线(类似于英国国旗的图案):
1 |
|
像素点绘制
U8G2 库提供了 drawPixel()
函数来绘制一个像素点:
像素点绘制 API | 功能描述 |
---|---|
void drawPixel(u8g2_uint_t x, u8g2_uint_t y) |
在 (x, y)
位置绘制一个像素点。 |
下面的示例代码会在 UINIO-Monitor 屏幕当中,每间隔 8 个像素绘制一个点,最终形成一条水平的虚线效果:
1 |
|
圆角矩形绘制
U8G2 库提供了 drawRBox()
和
drawRFrame()
两个函数用于圆角矩形的绘制:
直线绘制 API | 功能描述 |
---|---|
void drawRBox(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, u8g2_uint_t r) |
以 (x, y)
位置作为左上角,绘制一个宽高度分别为 w 和 h
的圆角实心矩形,圆角的半径为 r 。 |
void drawRFrame(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, u8g2_uint_t r) |
以 (x, y)
位置作为左上角,绘制一个宽高度分别为 w 和 h
的圆角空心矩形,圆角的半径为 r 。 |
下面的示例代码会在 UINIO-Monitor 屏幕的左右两侧,分别绘制一个实心和一个空心的圆角矩形:
1 |
|
绘制三角形
U8G2 库提供了 drawTriangle()
函数用于绘制实心的三角形:
直线绘制 API | 功能描述 |
---|---|
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2) |
分别以
(x0, y0) 、(x1, y1) 、(x2, y2)
作为顶点绘制一个实心的三角形。 |
下面的示例代码,分别以屏幕顶部中间点 (64, 0)
、屏幕左下角
(0, 64)
、屏幕右下角 (128, 64)
作为顶点,绘制出了一个实心的三角形:
1 |
|
MUI 图形界面库
MUI 是一款基于 U8G2
库的单色图形用户界面库,提供了诸如
事件处理
、用户界面绘图
、丰富的预定义用户元素
、静态菜单定义
等特性。详细信息可以参考 U8G2 库作者提供的 《MUI
手册》和 《MUI 参考》
两份文档。
0.96/1.3/1.69/2.4 英寸 LCD 显示屏
UINIO-Monitor 里的 2.4
英寸显示屏幕,采用了 320 × 240
分辨率的薄膜晶体管(TFT,Thin Film
Transistor)屏幕材质,总线通信方式为
SPI,驱动芯片型号是台湾矽创电子(Sitronix)的
ST7789,属于本系列当中显示尺寸最大的屏幕:
UINIO-Monitor 里的 1.3
英寸显示屏幕,采用了 240 × 240
分辨率的薄膜晶体管(TFT,Thin Film
Transistor)屏幕材质,总线通信方式为
SPI,驱动芯片型号是台湾矽创电子(Sitronix)的
ST7789:
UINIO-Monitor 里的 1.69
英寸圆角显示屏幕,采用了 280 × 240
分辨率的薄膜晶体管(TFT,Thin Film
Transistor)屏幕材质,总线通信方式为
SPI,驱动芯片型号是台湾矽创电子(Sitronix)的
ST7789:
UINIO-Monitor 里的 0.96
英寸显示屏幕,采用了 160 × 80
分辨率的薄膜晶体管(TFT,Thin Film
Transistor)屏幕材质,总线通信方式为
SPI,驱动芯片型号是台湾矽创电子(Sitronix)的
ST7735:
由于 UINIO-Monitor 系列的 TFT 屏幕都采用了台湾矽创电子(Sitronix)的主控方案,因而原理图设计方面基本上大同小异,不过建议线性稳压芯片采用带反接保护的德州仪器 LP2992IM5-3.3,虽然价格相对于国产微盟的 ME6211C33M5G 更贵,不过一分钱一分货,总比烧坏了成本更高的 TFT 屏幕要强:
同样在开始上手实践之前,需要把 UINIO-Monitor 当中
TFT 显示屏的
BLK
、CS
、D/C
、RST
、SCL
、SDA
、GND
、VCC
引脚,分别与 UINIO-MCU-ESP32S3 核心板的
3V3
、GPIO15
、GPIO16
、GPIO17
、GPIO18
、GPIO19
、GND
、5V
引脚进行连接,后续 TFT_eSPI
库相关的示例代码都将会沿用这个连接关系,下面的连接示意图以
280 × 240
分辨率的 1.69
英寸圆角显示屏幕为例:
TFT_eSPI 库开发速成
TFT_eSPI
是一款可以运行在 32 位微控制器上的 TFT
屏幕图形与字体显示库,本文撰写时的最新版本为 v2.5.0
,相关的
API 函数可以参考 《TFT_eSPI
库用户手册》,该库对于如下一系列微控制器进行了专门的性能优化:
- 树莓派 Pico 上的
RP2040
微控制器。 - 乐鑫科技的
ESP8266
、ESP32
、ESP32-S2
、ESP32-C3
、ESP32-S3
微控制器。 - 意法半导体的
STM32F1xx
、STM32F2xx
、STM32F4xx
、STM32F767
微控制器(推荐采用 RAM 空间较大的型号)。
上述的微控制器在 TFT_eSPI 库当中,可以支持如下表格当中的接口类型:
微控制器 | 4 线制 SPI | 8 位并行总线 | 16 位并行总线 | DMA 支持 |
---|---|---|---|---|
ESP32 C3 | 是 | 否 | 否 | 否 |
ESP32 S3 | 是 | 是 | 否 | 是 (仅 SPI) |
ESP32 S2 | 是 | 否 | 否 | 否 |
ESP32 | 是 | 是 | 否 | 是 (仅 SPI) |
RP2040 | 是 | 是 | 是 | 是 (全部) |
ESP8266 | 是 | 否 | 否 | 否 |
STM32Fxxx | 是 | 是 | 否 | 是 (仅 SPI) |
其它 | 是 | 否 | 否 | 否 |
TFT_eSPI 库能够支持如下一系列 TFT
液晶显示屏驱动芯片(官方推荐使用内置有 ILI9341
和
ST7796
两款驱动芯片的 SPI 屏幕):
型号 | 型号 | 型号 | 型号 | 型号 |
---|---|---|---|---|
ILI9163 | ILI9225 | ILI9341 | ILI9342 | ILI9481 |
ILI9486 | ILI9488 | HX8357B | HX8357C | HX8357D |
GC9A01 | R61581 | RM68120 | RM68140 | S6D02A1 |
SSD1351 | SSD1963 | ST7735 | ST7789 | ST7796 |
配置 User_Setup.h
通过 Arduino IDE 的【库管理器】安装完成
TFT_eSPI 库之后,还需要对
D:\Workspace\Workspace_Arduino\libraries\TFT_eSPI
路径下面的 User_Setup.h
头文件进行相应的编辑:
1 |
|
如果 UINIO-Monitor 屏幕显示出现异常,可以尝试通过调整如下的选项进行修复:
1 | /* 只针对 ST7735、ST7789、ILI9341 有效,如果显示屏上红色与蓝色发生互换,那么可以重新调整其颜色顺序(只能启用一个选项)*/ |
开始上手
Arduino IDE 的【库管理器】可以直接安装
TFT_eSPI 库,安装完成之后就可以在 Arduino
草图代码当中包含 #include <TFT_eSPI.h>
头文件,下面代码展示了 TFT_eSPI 库的基本使用方式:
1 |
|
颜色模式
TFT_eSPI 库所采用的颜色模式为
RGB565,即每一个像素占据着 2 Byte
个字节的数据量(即 2 个字节的无符号整型数据),其中红色占据
5 bit
位,绿色占据 6 bit
位,蓝色占据
5 bit
位。TFT_eSPI 库提供了一个便捷的
color565()
方法,可以将普通的 RGB 颜色转换为 RGB565
模式的颜色:
归属类与返回值 | API 函数 | 功能描述 |
---|---|---|
uint16_t TFT_eSPI:: |
color565(uint8_t r, uint8_t g, uint8_t b) |
用于将普通 RGB 颜色转换为 RGB565 模式的颜色。 |
下面的示例代码,通过 color565()
函数将红、黄、蓝、绿
4 种 RGB 颜色,分别转换为了 RGB565 模式的颜色值:
1 | uint16_t RGB_Red = tft.color565(255, 0, 0); |
在 TFT_eSPI 库安装目录下的 TFT_eSPI.h
源文件里,已经预定义了如下一系列的默认颜色,代码当中可以直接进行使用:
1 |
文本显示
下面表格当中的函数用于控制
TFT_eSP::print/printf/println()
系列文本输出函数(可以自动换行)的坐标系统:
API 方法 | 功能描述 |
---|---|
void setCursor(int16_t x, int16_t y) |
为 tft.print() 设置文本光标的
(x, y) 坐标位置。 |
void setCursor(int16_t x, int16_t y, uint8_t font) |
为 tft.print() 设置文本光标的
(x, y) 坐标位置和字体。 |
int16_t getCursorX(void) |
获取当前 tft.print()
文本光标在 x 轴的坐标位置。 |
int16_t getCursorY(void) |
获取当前 tft.print()
文本光标在 y 轴的坐标位置。 |
而接下来表格当中的这些方法,则用于控制
TFT_eSP::drawXxx()
系列文本输出函数(无法自动换行)的参考基准点:
API 方法 | 功能描述 |
---|---|
uint8_t getTextDatum(void) |
获取文本输出基准点。 |
void setTextDatum(uint8_t d) |
设置文本输出基准点。 |
上面表格当中的 setTextDatum(uint8_t d)
函数的参数
d
表示基准点的位置,可供选择的枚举参数有如下这些:
1 |
除此之外,TFT_eSPI 库还提供了如下一系列文本输出相关的辅助函数:
API 方法 | 功能描述 |
---|---|
void setTextFont(uint8_t f) |
设置当前所要显示文本的字体。 |
void setTextSize(uint8_t s) |
设置文本放大倍数(自定义字体无效),参数
s 的取值范围介于 1 ~ 7 之间。 |
void setTextColor(uint16_t c) |
设置字体颜色(背景为透明)。 |
void setTextColor(uint16_t c, uint16_t b) |
设置字体的颜色以及其背景色。 |
void setTextWrap(bool wrapX, bool wrapY) |
设置文本是否自动换行。 |
void setTextPadding(uint16_t x_width) |
设置填充宽度(以像素为单位),将会擦除之前的文本内容。 |
void getTextPadding(void) |
获取填充宽度(以像素为单位)。 |
下面的示例代码,会向 UINIO-Monitor
屏幕从上至下依次打印 Hello UinIO.com
字符串内容:
1 |
|
自定义字体
TFT_eSPI 库在其安装目录
TFT_eSPI\Tools\Create_Smooth_Font\Create_font
下面提供了处理自定义字体的 Create_font
工具,其中包含有如下源文件和目录:
data
目录:用于存放.ttf
以及.otf
字体文件。FontFiles
目录:保存的是转换处理之后所获得的.vlw
字体文件。Create_font.pde
工程文件:用于将自定义字体,从 Unicode 编码转换为.vlw
格式的字体文件(后续需要再进一步转换为.h
文件)。
Processing 生成 .vlw 字体文件
Processing
是一款用于图像处理的开源编程语言与开发环境,通过其可以打开位于
TFT_eSPI 库安装目录
TFT_eSPI\Tools\Create_Smooth_Font\Create_font
下面,用于制作自定义字体的 Processing 工程文件
Create_font.pde
:
将下面的代码复制到 Create_font.pde
的用户配置参数注释
USER CONFIGURED PARAMETERS
所在的位置,并且替换掉原来的内容:
1 | // >>>>>>>>>> USER CONFIGURED PARAMETERS START HERE <<<<<<<<<< |
接下来,就可以根据下面列出的步骤,依次进行相关的处理和操作:
- 使用在线中文转 Uinicode
工具,获得当前所需中文汉字的 Unicode 编码,然后将转换结果当中的
\u
替换为0x
,最后将结果填写到Create_font.pde
工程源文件的specificUnicodes()
函数里。 - 紧接着把思源黑体的字体文件
SourceHanSansSC-Bold.otf
复制到TFT_eSPI\Tools\Create_Smooth_Font\Create_font
路径下面的data
目录,同时把Create_font.pde
里的fontName
变量修改为字体的文件名称SourceHanSansSC-Bold
,而fontType
变量修改为.otf
。 - 完成上述步骤之后,点击 Processing 工具顶部的【运行】按钮,就会弹出下面的提示框,展示当前生成完毕的字体内容。
与此同时,就会在
TFT_eSPI\Tools\Create_Smooth_Font\Create_font
路径下面的
FontFiles
目录里,发现刚才已经转换完成了的
SourceHanSansSC-Bold14.vlw
文件:
1 | D:\Workspace\Workspace_Arduino\libraries\TFT_eSPI\Tools\Create_Smooth_Font\Create_font\FontFiles |
将 .vlw 转换为 .h 头文件
接下来,继续通过在线文件十六进制转换器,
或者该网站上提供的 bin2hex.exe
程序,把前面生成的
SourceHanSansSC-Bold14.vlw
文件转换为十六进制的格式:
此时可以打开 Arduino IDE
新建一个草图工程,接着在工程文件的根目录再新建一个
font_chengdu.h
头文件(用于保存上述十六进制编码),把上面获得的十六进制编码拷贝到下面的
font_chengdu
数组变量当中,就成功创建出了可供
TFT_eSPI 库使用的 font_chengdu.h
字体头文件:
1 |
|
显示自定义字体
在刚才新建的 Arduino 草图工程源代码里边,通过预处理命令
#include
包含上面建立的 font_chengdu.h
字体头文件,然后使用 loadFont()
函数加载字体,再分别通过
print()
和 drawString()
函数向屏幕输出思源黑体的成都,最后在使用完成之后调用
unloadFont()
函数卸载字体:
1 |
|
TFT_eWidget 图形界面库
TFT_eSPI 库的作者还提供了一个简单小巧的 TFT_eWidget 图形界面库,不过 Arduino 当中通常使用 LVGL 结合 TFT_eSPI 来绘制图形界面,所以该库的运用并不广泛,本文就不再赘述,有需要的朋友可以直接参考开源项目当中的说明文档。
运用 U8G2 与 TFT_eSPI 玩转 UINIO-Monitor 显示屏