第三十三章 ESP32S3 RGB 显示屏实验
33.1.1 RGBLCD 简介LCD(Liquid Crystal Display,液晶显示器)是一种利用液晶的光电效应对光线进行调制,从而显示图像或文字的平板显示器。它已成为当今最主流的显示技术之一,广泛应用于从智能手机、电脑显示器到电视等各种设备中。核心工作原理:LCD的显示依赖于液晶这种特殊的物质。液晶既具有液体的流动性,又具有晶体的光学各向异
LCD 液晶屏是常用到的外设,通过 LCD 可以显示绚丽的图形、界面等,提高人机交互的效率。本章学习如何通过ESP32驱动 RGB 接口液晶屏,并且在屏幕上显示字符。
本章分为如下几个小节:
33.1 RGBLCD 和 LCD 模块接口简介
33.2 硬件设计
33.3 程序设计
33.4 下载验证
33.1 RGBLCD 和 LCD 模块接口简介
33.1.1 RGBLCD 简介
LCD(Liquid Crystal Display,液晶显示器)是一种利用液晶的光电效应对光线进行调制,从而显示图像或文字的平板显示器。它已成为当今最主流的显示技术之一,广泛应用于从智能手机、电脑显示器到电视等各种设备中。
核心工作原理:
LCD的显示依赖于液晶这种特殊的物质。液晶既具有液体的流动性,又具有晶体的光学各向异性(其光学性质随方向而变化)。
其基本工作原理可以概括为以下几个关键部分:
- 背光源(Backlight):
液晶本身不发光,因此需要外部光源。LCD面板背后有一层均匀的背光(通常是LED阵列),提供原始白光。
- 偏振滤光片(Polarizing Filter):
在背光层和液晶层之间有一层垂直偏振片,只允许特定振动方向的光线通过。在液晶层的另一侧(靠近观看者一侧),有另一层水平偏振片。
- 液晶层(Liquid Crystal Layer):
这是核心层。液晶分子被放置在两片透明的电极(通常是ITO)之间;
当没有施加电压时,液晶分子会呈螺旋状排列,能够将穿过垂直偏振片的光线旋转90度,使其能够顺利通过前方的水平偏振片,此时像素看起来是“亮”的(常亮型);
当施加电压时,液晶分子会因电场作用而重新排列,不再能旋转光线。光线无法通过前方的水平偏振片,此时像素看起来是“暗”的(常暗型)。通过控制电压的大小,可以精确控制液晶的偏转角度,从而控制透光量的多少,实现灰阶变化。
- 彩色滤光片(Color Filter):
为了显示彩色,每个像素单元被划分为三个子像素,分别覆盖红(R)、绿(G)、蓝(B) 三原色的滤光片;
通过控制每个子像素的透光强度,可以混合出成千上万种颜色。
简单总结:LCD通过电压控制液晶分子的排列,从而改变背光的透过率,再结合彩色滤光片,最终形成我们所看到的图像。
接下来要从使用的角度需要关注 LCD 的几个重要点:
(1)分辨率
提起 LCD 显示器,经常看到 720P、 1080P、 2K 或 4K 这样的字眼,这个就是 LCD 显示器分辨率。 LCD 显示器都是由一个一个的像素点组成,像素点类似一个灯(在 OLED 显示器中,像素点就是一个小灯),这个小灯是 RGB 灯,也就是由 R(红色)、 G(绿色)和 B(蓝色)三种颜色组成,而 RGB 就是光的三原色。 1080P 的意思就是一个 LCD 屏幕上的像素数量是1920*1080 个,也就是这个屏幕一列 1080 个像素点,一共 1920 列,如图 33.1.1.1 所示:

图 33.1.1.1 LCD 像素点排布
在图 33.1.1.1 是 1080P 显示器的像素示意图, X 轴为 LCD 显示器的横轴, Y 轴为显示器的竖轴。图中的小方块就是像素点,一共有 1920*1080=2073600 个像素点。左上角的 A 点是第一个像素点,右下角的 C 点就是最后一个像素点。 2K 就是 2560*1440 个像素点, 4K 是3840*2160 个像素点。很明显,在 LCD 尺寸不变的情况下,分辨率越高越清晰。同样的,分辨率不变的情况下, LCD 尺寸越小越清晰。比如我们常用的 24 寸显示器基本都是 1080P 的,而现在使用的 5 寸的手机基本也是 1080P 的,但是手机显示细腻程度就要比 24 寸的显示器要好很多!
由此可见, LCD 显示器的分辨率是一个很重要的参数,但是并不是分辨率越高的 LCD 就越好。衡量一款 LCD 的好坏,分辨率只是其中的一个参数,还有色彩还原程度、色彩偏离、亮度、可视角度、屏幕刷新率等其他参数。
(2)像素格式
上面讲,一个像素点就相当于一个 RGB 小灯,通过控制 R、 G、 B 这三种颜色的亮度就可以显示出各种各样的色彩。那该如何控制 R、 G、 B 这三种颜色的显示亮度呢?一般一个 R、G、 B 这三部分分别使用 8bit 的数据,那么一个像素点就是 8bit*3=24bit,也就是说一个像素点
3 个字节,这种像素格式称为 RGB888。在第二十二章了解RGB565 这种像素格式,在本章实验中使用 RGB565 这种像素格式,一个像素占用 2个字节的内存。
(3) LCD 屏幕接口
LCD 屏幕或者说显示器有很多种接口,比如在显示器上常见的 VGA、 HDMI、 DP 等等,但是ESP32S3不支持这些接口。ESP32S3支持RGB接口的LCD, RGBLCD接口的信号线如表33.1.1.1 所示:
| LCD-TFT 信号 | I/O | 说明 |
|---|---|---|
| LCD_CLK | O | 时钟输出 |
| LCD_HSYNC | O | 水平同步 |
| LCD_VSYNC | O | 垂直同步 |
| LCD_DE | O | 数据使能 |
| LCD_R[7:0] | O | 数据: 8 位红色数据 |
| LCD_G[7:0] | O | 数据: 8 位绿色数据 |
| LCD_B[7:0] | O | 数据: 8 位蓝色数据 |
表 33.1.1.1 RGBLCD 信号线
表33.1.1.1 RGBLCD的信号线, R[7:0]、G[7:0]和B[7:0] 24根是数据线, DE、VSYNC、HSYNC 和 PCLK 这四根是控制信号线。 RGB LCD 一般有两种驱动模式: DE 模式和 HV 模式,这两个模式的区别是 DE 模式需要用到 DE 信号线,而 HV 模式不需要用到 DE 信号线,在 DE模式下是可以不需要 HSYNC 信号线的,即使不接 HSYNC 信号线 LCD 也可以正常工作。
原子目前提供五款 RGBLCD 模块: ATK-4342(4.3 寸, 480*272)、 ATK-4384(4.3 寸, 800*480) ATK-7084(7 寸, 800*480)、 ATK-7016(7 寸, 1024*600) 和 ATK-1018 (10.1 寸, 1280*800),由于手头有 ATK-7016,因此本次使用该款介绍。该模块的接口原理图如下图 所示:

图 33.1.1.2 RGB LCD 液晶屏屏幕接口
图中 J3 为对外接口,是一个 40PIN 的 FPC 座(0.5mm 间距),通过 FPC 线,连接到 ESP32-S3 开发板上,从而实现和 ESP32-S3 的连接。该接口十分完善,采用 RGB565格式,并支持 DE&HV 模式,还支持触摸屏和背光控制。右侧的几个电阻,并不是都焊接的,而是用户自己选择。默认情况, R1 和 R6 焊接,设置 LCD_LR 和 LCD_UD,控制 LCD 的扫描方向,是从左到右,从上到下(横屏看)。而 LCD_R7/G7/B7 则用来设置 LCD 的 ID,由于RGBLCD 没有读写寄存器,也就没有所谓的 ID,这里我们通过在模块上面,控制 R7/G7/B7 的上/下拉,来自定义 LCD 模块的 ID,帮助 MCU 判断当前 LCD 面板的分辨率和相关参数,以提高程序兼容性。这几个位的设置关系如下表所示:
| M2(B7) | M1(G7) | M0(R7) | RGBLCD 模块参数 |
|---|---|---|---|
| 0 | 0 | 0 | 4.3 寸, 480*272 分辨率(RGB) |
| 0 | 0 | 1 | 7 寸, 800*480 分辨率(RGB) |
| 0 | 1 | 0 | 7 寸, 1024*600 分辨率(RGB) |
| 0 | 1 | 1 | 7 寸, 1280*800 分辨率(RGB) |
| 1 | 0 | 0 | 4.3 寸, 800*480 分辨率(RGB) |
| 1 | 0 | 1 | 10.1 寸, 1280*800 分辨率(RGB) |
| X | X | X | 暂时未用到 |
表 33.1.1.2 原子 RGBLCD 模块 ID 对应关系
ATK-7016 模块,设置 M2:M0=010 即可。这样,在程序里面,读取 LCD_R7/G7/B7,得到 M0:M2 的值,从而判断 RGBLCD 模块的型号,并执行不同的配置,即可实现不同 LCD 模块的兼容。
(4) LCD 时间参数
如果将 LCD 显示一帧图像的过程想象成绘画,那么在显示的过程中就是用一根“笔”在不同的像素点画上不同的颜色。这根笔按照从左至右、从上到下的顺序扫描每个像素点,并且在像素画上对应的颜色,当画到最后一个像素点的时候一幅图像就绘制好了。假如一个 LCD 的分辨率为 1024*600,那么其扫描如下图所示:

图 33.1.1.3 LCD 一帧图像扫描图
结合图 33.1.1.3 看一下 LCD 是怎么扫描显示一帧图像的。一帧图像也是由一行一行组成的。HSYNC 是水平同步信号,也叫做行同步信号,当产生此信号的话就表示开始显示新的一行了,所以此信号都是在图 33.1.1.3 的最左边。当 VSYNC 信号是垂直同步信号,也叫做帧同步信号,当产生此信号的话就表示开始显示新的一帧图像了,所以此信号在图 33.1.1.3 的左上角。
在图 33.1.1.3 可以看到有一圈“黑边”,真正有效的显示区域是中间的白色部分。那这一圈“黑边”是什么东西呢?这就要从显示器的“祖先” CRT 显示器开始说起了, CRT 显示器就是以前很常见的那种大屁股显示器。CRT 显示器屁股后面是个电子枪,这个电子枪就是我们上面说的“画笔”,电子枪打出的电子撞击到屏幕上的荧光物质使其发光。只要控制电子枪从左到右扫完一行(也就是扫描一行),然后从上到下扫描完所有行,这样一帧图像就显示出来了。也就是说,显示一帧图像电子枪是按照‘Z’形在运动,当扫描速度很快的时候看起来就是一幅完成的画面了。
当显示完一行以后会发出 HSYNC 信号,此时电子枪就会关闭,然后迅速的移动到屏幕的左边,当 HSYNC 信号结束以后就可以显示新的一行数据了,电子枪就会重新打开。在 HSYNC信号结束到电子枪重新打开之间会插入一段延时,这段延时就图 24.1.1.5 中的 HBP。当显示完一行以后就会关闭电子枪等待 HSYNC 信号产生,关闭电子枪到 HSYNC 信号产生之间会插入一段延时,这段延时就是图 24.1.1.5 中的 HFP 信号。同理,当显示完一帧图像以后电子枪也会关闭,然后等到 VSYNC 信号产生,期间也会加入一段延时,这段延时就是图 33.1.1.3 中的 VFP。VSYNC 信号产生,电子枪移动到左上角,当 VSYNC 信号结束以后电子枪重新打开,中间也会加入一段延时,这段延时就是图 24.1.1.5 中的 VBP。
HBP、 HFP、 VBP 和 VFP 就是导致图 24.1.1.5 中黑边的原因,但是这是 CRT 显示器存在黑边的原因,现在是 LCD 显示器,不需要电子枪了,那么为何还会有黑边呢?这是因为 RGB LCD屏幕内部是有一个 IC 的,发送一行或者一帧数据给 IC, IC 是需要反应时间的。通过这段反应时间可以让 IC 识别到一行数据扫描完了,要换行了,或者一帧图像扫描完了,要开始下一帧图
像显示了。因此,在 LCD 屏幕中继续存在 HBP、 HFP、 VPB 和 VFP 这四个参数的主要目的是为了锁定有效的像素数据。这四个时间是 LCD 重要的时间参数,后面编写 LCD 驱动的时候要用到的,至于这四个时间参数具体值是多少,那要需要去查看所使用的 LCD 数据手册了。
(5)RGB LCD 屏幕时序
上面为行显示和帧显示,接下来看一下行显示对应的时序图,如图 33.1.1.4 所示:

图 33.1.1.4 行显示时序
图 33.1.1.4 RGB LCD 的行显示时序,接下来分析重要的几个参数:
HSYNC:行同步信号,当此信号有效的话就表示开始显示新的一行数据,查阅所使用的LCD数据手册可以知道此信号是低电平有效还是高电平有效,假设此时是低电平有效;
HSPW: 有些地方也叫做 thp,是 HSYNC 信号宽度,也就是 HSYNC 信号持续时间。SYNC信号不是一个脉冲,而是需要持续一段时间才是有效的,单位为 CLK;
HBP: 有些地方叫做 thb,前面已经讲过了,术语叫做行同步信号后肩,单位是 CLK;
HOZVAL:有些地方叫做 thd,显示一行数据所需的时间,假如屏幕分辨率为1024*600, HOZVAL 为1024,单位为 CLK;
HFP:有些地方叫做 thf,前面已经讲过了, 术语叫做行同步信号前肩,单位是 CLK;
当 HSYNC 信号发出以后,需要等待 HSPW+HBP 个 CLK 时间才会接收到真正有效的像素数据。当显示完一行数据以后需要等待 HFP 个 CLK 时间才能发出下一个 HSYNC 信号,所以显示一行所需要的时间就是: HSPW + HBP + HOZVAL + HFP。
一帧图像就是由很多个行组成的, RGB LCD 的帧显示时序如下图所示:

图 33.1.1.5 帧显示时序图
图 233.1.1.5 为RGB LCD 的帧显示时序,分析其中重要的几个参数:
VSYNC:帧同步信号,当此信号有效的话就表示开始显示新的一帧数据,查阅所使用的LCD 数据手册可以知道此信号是低电平有效还是高电平有效,假设此时是低电平有效;
VSPW: 有些地方也叫做 tvp,是 VSYNC 信号宽度,也就是 VSYNC 信号持续时间,单位为 1 行的时间;
VBP: 有些地方叫做 tvb,前面已经讲过,术语叫做帧同步信号后肩,单位为 1 行的时间;
LINE: 有些地方叫做 tvd,显示一帧有效数据所需的时间,假如屏幕分辨率为 1024*600, LINE 就是 600 行的时间;
VFP: 有些地方叫做 tvf,前面已经讲过了,术语叫做帧同步信号前肩,单位为 1 行的时间。显示一帧所需要的时间就是: VSPW+VBP+LINE+VFP 个行时间,最终的计算公式:
T = (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP)
因此在配置一款 RGB LCD 的时候需要知道这几个参数: HOZVAL(屏幕有效宽度)、LINE(屏幕有效高度)、 HBP、 HSPW、 HFP、 VSPW、 VBP 和 VFP。 ALIENTEK 三款 RGB LCD屏幕的参数如表 33.1.1.3 所示:
| 屏幕型号 | 参数 | 值 | 单位 |
|---|---|---|---|
| ATK4342 | 水平显示区域 | 480 | tCLK |
| HSPW(thp) | 1 | tCLK | |
| HBP(thb) | 40 | tCLK | |
| HFP(thf) | 5 | tCLK | |
| 垂直显示区域 | 272 | th | |
| VSPW(tvp) | 1 | th | |
| VBP(tvb) | 8 | th | |
| VFP(tvf) | 8 | th | |
| 像素时钟 | 9 | MHz | |
| ATK4384 | 水平显示区域 | 800 | tCLK |
| HSPW(thp) | 48 | tCLK | |
| HBP(thb) | 88 | tCLK | |
| HFP(thf) | 40 | tCLK | |
| 垂直显示区域 | 480 | th | |
| VSPW(tvp) | 3 | th | |
| VBP(tvb) | 32 | th | |
| VFP(tvf) | 13 | th | |
| 像素时钟 | 31 | MHz | |
| ATK7084 | 水平显示区域 | 800 | tCLK |
| HSPW(thp) | 1 | tCLK | |
| HBP(thb) | 46 | tCLK | |
| HFP(thf) | 210 | tCLK | |
| 垂直显示区域 | 480 | th | |
| VSPW(tvp) | 1 | th | |
| VBP(tvb) | 23 | th | |
| VFP(tvf) | 22 | th | |
| 像素时钟 | 33.3 | MHz | |
| ATK7016 | 水平显示区域 | 1024 | tCLK |
| HSPW(thp) | 20 | tCLK | |
| HBP(thb) | 140 | tCLK | |
| HFP(thf) | 160 | tCLK | |
| 垂直显示区域 | 600 | th | |
| VSPW(tvp) | 3 | th | |
| VBP(tvb) | 20 | th | |
| VFP(tvf) | 12 | th | |
| 像素时钟 | 51.2 | MHz |
表 33.1.1.3 RGB LCD 屏幕时间参数
(6)像素时钟
像素时钟就是 RGB LCD 的时钟信号,以 ATK7016 这款屏幕为例,显示一帧图像所需要的时钟数如下:
= (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP)
= (3 + 20 + 600 + 12) * (20 + 140 + 1024 + 160)
= 635 * 1344
= 853440。
显示一帧图像需要853440个时钟数,那么显示60帧就是: 853440 * 60 = 51206400≈51.2M,所以像素时钟为 51.2MHz。
(7)显存
在讲像素格式的时候就已经说过了,如果采用 ARGB888 格式的话一个像素需要 3 个字节的内存来存放像素数据,那么 1024*600 分辨率就需要 1024*600*3=1843200B≈1.8MB 内存。但是 RGB LCD 内部是没有内存的,所以就需要申请一段内存作为 RGB LCD 屏幕的显存,我们如果要在屏幕上显示什么图像的话直接操作这部分显存即可。
33.1.2 LCD 模块接口简介
本小节主要介绍 LCD_CAM 控制器的 LCD 模块,至于 CAMERA 模块,会在摄像头章节中涉及学习,下面来看一下 LCD 模块的结构框架。

图 33.1.2.1 LCD_CAM 控制器结构框架
这个系统的 LCD 模块(即上图的下方部分)包括以下模块:一个独立的发送控制单元(LCD_Ctrl),用于控制 LCD 的发送;一个发送异步 FIFO(Async Tx FIFO),用于与外部设备交互,发送数据;一个 LCD_Clock Generator 时钟生成模块,用于生成对应模块的时钟;以及一个格式转换模块,即RGB/YCbCr Converter,用于各种格式的视频数据互相转换。这些模块协同工作,确保系统能够高效、稳定地处理和传输并行视频数据信号。
需要注意: LCD_CAM的所有信号均需要经过 GPIO交换矩阵映射到芯片管脚。更多信息请参考章节 6 IO MUX 和 GPIO 交换矩阵(GPIO, IO MUX)。
(1)LCD 模块信号描述
LCD 模块信号对应了上图右下角的几个信号,它们的具体作用如下所示。
| 信号 | 方向 | 功能 |
|---|---|---|
| LCD_PCLK | 输出 | LCD 像素时钟输出信号 |
| LCD_H_SYNC | 输出 | RGB 格式下,用作行同步信号 |
| LCD_V_SYNC | 输出 | RGB 格式下,用作帧同步信号 |
| LCD_H_ENABLE | 输出 | RGB 格式下,用作行有效信号 |
| LCD_CD | 输出 | I8080 格式下,用作命令和数据信号 (CD) |
| LCD_CS | 输出 | 输出 I8080/MOTO6800 格式下,用作片选信号 (CS) |
| LCD_Data_out[N:0] | 输出 | 输出 并行输出数据总线,支持 8/16 位并行数据输出 |
表 33.1.2.1 LCD 模块信号描述
在启动 LCD模块时,信号的位宽是一个关键参数。根据所接入的 LCD的位宽, N的值会有所不同。如果使用 RGBLCD 接口连接,并且位宽为 16 位,则 N 的值为 15。相反,如果接入的LCD 使用 8 位的位宽,则 N 的值为 7。因此,根据 LCD 的位宽,可以确定 N 的具体值。
(2)LCD 时钟选择
从上图可以看到, LCD 模块的时钟由三个不同的时钟源提供,它们分别是 XTAL_CLK、 PLL_D2_CLK 和 PLL_F160M_CLK。 LCD 模块的时钟源选择模式是由寄存器 LCD_CAM_LCD_CLOCK_REG 中的 LCD_CAM_LCD_CLK_SEL 位决定的。最后, LCD_Clock Generator 时钟生成模块负责生成 LCD 模块所需的时钟,即上图中的 LCD_CLK。
下图是 LCD 时钟选择与计算框图。

图 33.1.2.2 LCD 时钟选择与计算框图
LCD_CLK 的频率 fLCD_CLK 与分频器时钟源频率 fLCD_CLK_S 间的关系如下:

其中, 2<=N<=256, N对应为 LCD_CAM_LCD_CLOCK_REG 寄存器中LCD_CAM_LCD_CLKM_DIV_NUM 的值。 LCD 模块的像素时钟 PCLK 为 LCD_PCLK 信号,由 LCD_CLK 分频获得。计算公式如下:

其中, MO 由寄存器 LCD_CAM_LCD_CLK_EQU_SYSCLK 和 LCD_CAM_LCD_CLKCNT_N 决定。最终我们得到了 LCD_PCLK 时钟,该时钟经过分频得到了像素时钟 LCD_PCLK。
更多LCD模块知识 ,可参考 《esp32-s3_technical_reference_manual_cn.pdf》技术手册 29 章节内容。
33.2 硬件设计
33.2.1 例程功能
本章实验功能简介:本实验利用 ESP32-S3 开发板的 RGB接口来驱动 RGB屏, RGBLCD模块的接口在核心板上,通过 40P 的 FPC 排线连接 RGBLCD 模块,实现 RGBLCD 模块的驱动和显示,下载成功后,按下复位之后,就可以看到 RGBLCD 模块不停的显示一些信息并不断切换底色。同时,屏幕上会显示 LCD 的 ID。需要注意的是: DNESP32S3 开发板的 RGB 例程仅支持
4.3 寸的 RGB 显示屏。
33.2.2 硬件资源
1. LED 灯
LED-IO1
2. XL9555
IIC_SDA-IO41
IIC_SCL-IO42
3. RGBLCD
LCD_BL-IO1_3(XL9555)
LCD_DE-IO4
LCD_VSYNC-NC
LCD_HSYNC-NC
LCD_PCLK-IO5
LCD_R3-IO45
LCD_R4-IO48
LCD_R5-IO47
LCD_R6-IO21
LCD_R7-IO14
LCD_G2-IO10
LCD_G3-IO9
LCD_G4-IO46
LCD_G5-IO3
LCD_G6-IO8
LCD_G7-IO18
LCD_B3-IO17
LCD_B4-IO16
LCD_B5-IO15
LCD_B6-IO7
LCD_B7-IO6
33.2.3 原理图
RGB 接口与 ESP32-S3 的连接关系,如下图所示:

图 33.2.3.1 RGB 接口与 ESP32-S3 的连接电路图
33.3 程序设计
33.3.1 程序流程图
本实验的程序流程图:

图 33.3.1.1 RGB 实验程序流程图
33.3.2 RGB-LCD 函数解析
ESP-IDF 提供了一套 API 来配置 RGB。要使用此功能,需要导入必要的头文件:
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_rgb.h"
接下来,介绍一些常用的 ESP32-S3 中的 RGB 函数,这些函数的描述及其作用如下:
(1)创建 RGB 对象
该函数通过配置结构体参数的方式将参数以指针的方式传进,该函数原型如下所示:
esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_config,
esp_lcd_panel_handle_t *ret_panel);
该函数的形参描述如下表所示:
| 参数 | 描述 |
|---|---|
| rgb_panel_config | RGB 配置,指针参数 |
| ret_panel | 返回 LCD 句柄,指针参数 |
表 33.3.2.1 esp_lcd_new_rgb_panel()函数形参描述
该函数的返回值描述,如下表所示:
| 返回值 | 描述 |
|---|---|
| ESP_ERR_INVALID_ARG | 由于无效参数,创建 RGB LCD 面板失败 |
| ESP_ERR_NO_MEM | 由于内存不足,创建 RGB LCD 面板失败 |
| ESP_ERR_NOT_FOUND | 创建 RGB LCD 面板失败,因为没有找到一些必需的硬 件资源 |
| ESP_OK | 创建 RGB LCD 面板成功 |
表 33.3.2.2 函数 esp_lcd_new_rgb_panel ()返回值描述
1该函数使用 esp_lcd_rgb_panel_config_t 类型的结构体变量传入,该结构体的定义如下:
|
参数分组 |
参数名称 |
数据类型 |
说明与配置建议 |
示例值 (1024x600屏) |
|---|---|---|---|---|
|
时钟与总线 |
|
|
时钟源。通常使用默认值 |
|
|
|
|
像素时钟频率 (Hz)。根据屏幕分辨率和时序计算得出,是最关键的参数之一。必须与 |
|
|
|
|
|
数据总线宽度 (位)。常见为 16 (RGB565) 或 8 (RGB332)。必须与屏幕硬件匹配。 |
|
|
|
|
|
帧缓冲区数量。设置为 2 可实现双缓冲,避免屏幕撕裂。 |
|
|
|
|
|
弹跳缓冲区大小 (像素)。当帧缓冲区在PSRAM且CPU写入时,DMA从此内部缓冲区读取。建议设为 |
|
|
|
|
|
SRAM中DMA描述符的对齐要求。通常默认即可。 |
|
|
|
|
|
PSRAM中缓冲区的对齐要求。ESP32-S3的DMA需要64字节对齐。必须设置为 |
|
|
|
GPIO 配置 |
|
|
RGB数据线GPIO引脚数组。从低位到高位顺序定义。必须与硬件连接完全一致。 |
|
|
|
|
像素时钟 (PCLK) 信号线GPIO。 |
|
|
|
|
|
垂直同步 (VSYNC) 信号线GPIO。在DE模式下通常设为 |
|
|
|
|
|
水平同步 (HSYNC) 信号线GPIO。在DE模式下通常设为 |
|
|
|
|
|
数据使能 (DE) 信号线GPIO。现代屏幕大多使用此模式,必须配置。 |
|
|
|
|
|
显示屏使能信号GPIO。用于打开/关闭屏幕背光或电源。可选,不用则设 |
|
|
|
时序参数 |
|
|
像素时钟频率。必须与顶层的 |
|
|
|
|
屏幕水平分辨率 (像素)。 |
|
|
|
|
|
屏幕垂直分辨率 (行数)。 |
|
|
|
|
|
水平同步脉冲宽度 (HSYNC)。单位:PCLK周期。重要:对应数据手册中的 |
|
|
|
|
|
水平后廊 (HBP)。单位:PCLK周期。重要:对应数据手册中的 |
|
|
|
|
|
水平前廊 (HFP)。单位:PCLK周期。重要:对应数据手册中的 |
|
|
|
|
|
垂直同步脉冲宽度 (VSYNC)。单位:行数。重要:对应数据手册中的 |
|
|
|
|
|
垂直后廊 (VBP)。单位:行数。重要:对应数据手册中的 |
|
|
|
|
|
垂直前廊 (VFP)。单位:行数。重要:对应数据手册中的 |
|
|
|
|
|
像素时钟极性。True = 数据在时钟下降沿有效。必须根据屏幕数据手册设置。 |
|
|
|
|
|
HSYNC 空闲状态电平。 |
|
|
|
|
|
VSYNC 空闲状态电平。 |
|
|
|
|
|
DE 空闲状态电平。 |
|
|
|
标志位 |
|
|
帧缓冲区是否位于PSRAM。高分辨率屏必须为 |
|
|
|
|
是否无帧缓冲区模式。通常用于特殊用途,保持 |
|
|
|
|
|
是否使弹跳缓冲区缓存无效。通常保持 |
表 33.3.2.3 esp_lcd_rgb_panel_config_t 结构体参数值描述
完成上述结构体参数配置之后,可以将结构传递给 esp_lcd_new_rgb_panel () 函数,用以实例化 RGB。
(2)复位 RGB 屏幕
在创建 RGB 屏幕对象后需要进行 RGB 屏幕复位,该函数原型如下所示:
esp_err_t esp_lcd_panel_reset(esp_lcd_panel_handle_t panel);
该函数的形参描述如下表所示:
| 参数 | 描述 |
|---|---|
| panel | LCD 句柄, 由其他函数 API 创建 |
表 33.3.2.4 esp_lcd_panel_reset ()函数形参描述
该函数的返回值描述,如下表所示:
| 返回值 | 描述 |
|---|---|
| ESP_OK | 返回: 0,配置成功 |
表 33.3.2.5 函数 esp_lcd_panel_reset ()返回值描述
(3)初始化 RGB 屏幕
通过上两个步骤的配置,可以对屏幕进行初始化了,该函数原型如下所示:
esp_err_t esp_lcd_panel_init(esp_lcd_panel_handle_t panel);
该函数的形参描述如下表所示:
| 参数 | 描述 |
|---|---|
| panel | LCD 句柄, 由其他函数 API 创建 |
表 33.3.2.6 esp_lcd_panel_init ()函数形参描述
该函数的返回值描述,如下表所示:
| 返回值 | 描述 |
|---|---|
| ESP_OK | 返回: 0,配置成功 |
表 33.3.2.7 函数 esp_lcd_panel_init ()返回值描述
33.3.3 RGB-LCD 驱动解析
看StandardExampleIDF(v5.3.x)版本,在 IDF 版的 23_rgb 例程,23_rgb\components\BSP 路径下新增了一个 RGB 文件夹,分别用于存放 ltdc.c、 ltdc.h、rgblcd.h、rgblcd.c、ltdcfont.h 这五个文件。下面,将详细解析这三个文件的实现内容。
(1)rgblcd.h
/* RGBLCD引脚 */
#define GPIO_LCD_DE (GPIO_NUM_4)
#define GPIO_LCD_VSYNC (GPIO_NUM_NC)
#define GPIO_LCD_HSYNC (GPIO_NUM_NC)
#define GPIO_LCD_PCLK (GPIO_NUM_5)
#define GPIO_LCD_R3 (GPIO_NUM_45)
#define GPIO_LCD_R4 (GPIO_NUM_48)
#define GPIO_LCD_R5 (GPIO_NUM_47)
#define GPIO_LCD_R6 (GPIO_NUM_21)
#define GPIO_LCD_R7 (GPIO_NUM_14)
#define GPIO_LCD_G2 (GPIO_NUM_10)
#define GPIO_LCD_G3 (GPIO_NUM_9)
#define GPIO_LCD_G4 (GPIO_NUM_46)
#define GPIO_LCD_G5 (GPIO_NUM_3)
#define GPIO_LCD_G6 (GPIO_NUM_8)
#define GPIO_LCD_G7 (GPIO_NUM_18)
#define GPIO_LCD_B3 (GPIO_NUM_17)
#define GPIO_LCD_B4 (GPIO_NUM_16)
#define GPIO_LCD_B5 (GPIO_NUM_15)
#define GPIO_LCD_B6 (GPIO_NUM_7)
#define GPIO_LCD_B7 (GPIO_NUM_6)
/* LCD RGBLCD重要参数集 */
typedef struct
{
uint32_t pwidth; /* RGBLCD面板的宽度,固定参数,不随显示方向改变,如果为0,说明没有任何RGB屏接入 */
uint32_t pheight; /* RGBLCD面板的高度,固定参数,不随显示方向改变 */
uint16_t hsw; /* 水平同步宽度 */
uint16_t vsw; /* 垂直同步宽度 */
uint16_t hbp; /* 水平后廊 */
uint16_t vbp; /* 垂直后廊 */
uint16_t hfp; /* 水平前廊 */
uint16_t vfp; /* 垂直前廊 */
uint8_t activelayer; /* 当前层编号:0/1 */
uint8_t dir; /* 0,竖屏;1,横屏; */
uint16_t id; /* RGBLCD ID */
uint32_t pclk_hz; /* 设置像素时钟 */
uint16_t width; /* RGBLCD宽度 */
uint16_t height; /* RGBLCD高度 */
} _rgblcd_dev;
extern _rgblcd_dev rgbdev; /* 管理RGBLCD重要参数 */
/* 函数声明 */
esp_lcd_panel_handle_t rgblcd_init(void); /* 初始化RGBLCD */
void rgblcd_display_dir(uint8_t dir); /* 设置rgb方向 */
(2)rgblcd.c
代码中并没有适配7寸RGB1024*600,下面代码适配如下。同时调试时候遇到2个问题,导致无法正常显示:
- 错误地将
timings.hsync_pulse_width和timings.vsync_pulse_width设置错误(分别设置为vsw和hsw)正确设置hsw和vsw; -
rgbdev.pclk_hz设置像素时钟 51.2Mhz,修改为35M(再高也会影响显示)。
_rgblcd_dev rgbdev; /* 管理RGBLCD重要参数 */
esp_lcd_panel_handle_t panel_handle = NULL; /* RGBLCD句柄 */
/**
* @brief 初始化RGBLCD
* @param 无
* @retval RGBLCD句柄
*/
esp_lcd_panel_handle_t rgblcd_init(void)
{
rgbdev.id = lcddev.id; /* 读取LCD面板ID */
if (rgbdev.id == 0X4342) /* 4.3寸屏, 480*272 RGB屏 */
{
rgbdev.pwidth = 480; /* 面板宽度,单位:像素 */
rgbdev.pheight = 272; /* 面板高度,单位:像素 */
rgbdev.hsw = 4; /* 水平同步宽度 */
rgbdev.hbp = 43; /* 水平后廊 */
rgbdev.hfp = 8; /* 水平前廊 */
rgbdev.vsw = 4; /* 垂直同步宽度 */
rgbdev.vbp = 12; /* 垂直后廊 */
rgbdev.vfp = 8; /* 垂直前廊 */
rgbdev.pclk_hz = 9 * 1000 * 1000; /* 设置像素时钟 9Mhz */
}
else if (rgbdev.id == 0X4384)
{
rgbdev.pwidth = 800; /* 面板宽度,单位:像素 */
rgbdev.pheight = 480; /* 面板高度,单位:像素 */
rgbdev.hsw = 48; /* 水平同步宽度 */
rgbdev.hbp = 88; /* 水平后廊 */
rgbdev.hfp = 40; /* 水平前廊 */
rgbdev.vsw = 3; /* 垂直同步宽度 */
rgbdev.vbp = 32; /* 垂直后廊 */
rgbdev.vfp = 13; /* 垂直前廊 */
rgbdev.pclk_hz = 20 * 1000 * 1000; /* 设置像素时钟 20Mhz */
}
else if (rgbdev.id == 0x7084) /* ATK-MD0700R-800480 */
{
rgbdev.pwidth = 800; /* LCD面板的宽度 */
rgbdev.pheight = 480; /* LCD面板的高度 */
rgbdev.hsw = 1; /* 水平同步宽度 */
rgbdev.hbp = 46; /* 水平后廊 */
rgbdev.hfp = 210; /* 水平前廊 */
rgbdev.vsw = 1; /* 垂直同步宽度 */
rgbdev.vbp = 23; /* 垂直后廊 */
rgbdev.vfp = 22; /* 垂直前廊 */
rgbdev.pclk_hz = 20 * 1000 * 1000; /* 设置像素时钟 20Mhz */
}
else if (rgbdev.id == 0X7016)
{
rgbdev.pwidth = 1024; /* 面板宽度,单位:像素 */
rgbdev.pheight = 600; /* 面板高度,单位:像素 */
rgbdev.hbp = 140; /* 水平后廊 */
rgbdev.hfp = 160; /* 水平前廊 */
rgbdev.hsw = 20; /* 水平同步宽度 */
rgbdev.vbp = 20; /* 垂直后廊 */
rgbdev.vfp = 12; /* 垂直前廊 */
rgbdev.vsw = 3; /* 垂直同步宽度 */
// rgbdev.pclk_hz = 51200 * 1000; /* 设置像素时钟 51.2Mhz */
rgbdev.pclk_hz = 35 * 1000 * 1000;
}
/* 配置RGB参数 */
esp_lcd_rgb_panel_config_t panel_config = { /* RGBLCD配置结构体 */
.num_fbs = 2, /* 缓存区数量 */
.data_width = 16, /* 数据宽度为16位 */
.psram_trans_align = 64, /* 在PSRAM中分配的缓冲区的对齐 */
.clk_src = LCD_CLK_SRC_PLL160M, /* RGBLCD外设时钟源 */
.disp_gpio_num = GPIO_NUM_NC, /* 用于显示控制信号,不使用设为-1 */
.pclk_gpio_num = GPIO_LCD_PCLK, /* PCLK信号引脚 */
.hsync_gpio_num = GPIO_NUM_NC, /* HSYNC信号引脚,DE模式可不使用 */
.vsync_gpio_num = GPIO_NUM_NC, /* VSYNC信号引脚,DE模式可不使用 */
.de_gpio_num = GPIO_LCD_DE, /* DE信号引脚 */
.data_gpio_nums = { /* 数据线引脚 */
GPIO_LCD_B3, GPIO_LCD_B4, GPIO_LCD_B5, GPIO_LCD_B6, GPIO_LCD_B7,
GPIO_LCD_G2, GPIO_LCD_G3, GPIO_LCD_G4, GPIO_LCD_G5, GPIO_LCD_G6, GPIO_LCD_G7,
GPIO_LCD_R3, GPIO_LCD_R4, GPIO_LCD_R5, GPIO_LCD_R6, GPIO_LCD_R7,
},
.timings = { /* RGBLCD时序参数 */
.pclk_hz = rgbdev.pclk_hz, /* 像素时钟频率 */
.h_res = rgbdev.pwidth, /* 水平分辨率,即一行中的像素数 */
.v_res = rgbdev.pheight, /* 垂直分辨率,即帧中的行数 */
.hsync_back_porch = rgbdev.hbp, /* 水平后廊,hsync和行活动数据开始之间的PCLK数 */
.hsync_front_porch = rgbdev.hfp, /* 水平前廊,活动数据结束和下一个hsync之间的PCLK数 */
.hsync_pulse_width = rgbdev.hsw, /* 垂直同步宽度,单位:行数 */
.vsync_back_porch = rgbdev.vbp, /* 垂直后廊,vsync和帧开始之间的无效行数 */
.vsync_front_porch = rgbdev.vfp, /* 垂直前廊,帧结束和下一个vsync之间的无效行数 */
.vsync_pulse_width = rgbdev.vsw, /* 水平同步宽度,单位:PCLK周期 */
.flags = {
.pclk_active_neg = true, /* RGB数据在下降沿计时 */
},
},
.flags.fb_in_psram = true, /* 在PSRAM中分配帧缓冲区 */
// .bounce_buffer_size_px = (rgbdev.id == 0X4384 || rgbdev.id == 0x7084) ? 800 * 20 : 480 * 20, /* 解决写spiflash时,抖动问题 */
.bounce_buffer_size_px = rgbdev.pwidth * 10,
};
esp_lcd_new_rgb_panel(&panel_config, &panel_handle);/* 创建RGB对象 */
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); /* 复位RGB屏 */
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); /* 初始化RGB */
rgblcd_display_dir(1); /* 设置横屏 */
return panel_handle; /* RGBLCD句柄 */
}
(3)ltdc.h 文件
/* 注意:以RGBLCD为主,如RGBLCD和MIPI LCD插入到开发板上,则默认选择RGBLCD */
/* 首先读取RGBLCD ID,如没有接入RGBLCD,则读取MIPI LCD */
#define GPIO_LCD_ID1 (GPIO_NUM_14)
#define GPIO_LCD_ID2 (GPIO_NUM_18)
#define GPIO_LCD_ID3 (GPIO_NUM_6)
/* RGB_BL */
#define LCD_BL(x) do { x ? \
xl9555_pin_write(LCD_BL_IO, 1): \
xl9555_pin_write(LCD_BL_IO, 0); \
} while(0)
/* 常用颜色值 */
#define WHITE 0xFFFF /* 白色 */
#define BLACK 0x0000 /* 黑色 */
#define RED 0xF800 /* 红色 */
#define GREEN 0x07E0 /* 绿色 */
#define BLUE 0x001F /* 蓝色 */
#define MAGENTA 0XF81F /* 洋红色 */
#define YELLOW 0XFFE0 /* 黄色 */
#define CYAN 0X07FF /* 蓝绿色 */
/* 非常用颜色 */
#define BROWN 0XBC40 /* 棕色 */
#define BRRED 0XFC07 /* 棕红色 */
#define GRAY 0X8430 /* 灰色 */
#define DARKBLUE 0X01CF /* 深蓝色 */
#define LIGHTBLUE 0X7D7C /* 浅蓝色 */
#define GRAYBLUE 0X5458 /* 灰蓝色 */
#define LIGHTGREEN 0X841F /* 浅绿色 */
#define LGRAY 0XC618 /* 浅灰色(PANNEL),窗体背景色 */
#define LGRAYBLUE 0XA651 /* 浅灰蓝色(中间层颜色) */
#define LBBLUE 0X2B12 /* 浅棕蓝色(选择条目的反色) */
/* LCD重要参数集 */
typedef struct
{
uint16_t id; /* 读取ID */
uint32_t width; /* 面板的宽度,固定参数,不随显示方向改变 */
uint32_t height; /* 面板的高度,固定参数,不随显示方向改变 */
uint8_t dir; /* 0,竖屏(MIPI只能竖屏);1,横屏; */
uint8_t color_byte; /* 颜色格式 */
esp_lcd_panel_handle_t lcd_panel_handle; /* LCD控制句柄 */
esp_lcd_panel_io_handle_t lcd_dbi_io; /* LCD IO控制句柄 */
struct
{
int lcd_rst; /* 复位引脚 */
int lcd_bl; /* 背光引脚 */
} ctrl;
} _lcd_dev;
/* LCD参数 */
extern _lcd_dev lcddev; /* 管理LCD重要参数 */
(4) ltdc.c 文件
这个文件只列出关键函数,其他比较好理解,不再展示。
DRAM_ATTR void *lcd_buffer[2]; /* 指向屏幕双缓存 */
DRAM_ATTR uint8_t buffer_sw = 0; /* 当前使用的缓冲区索引 */
DRAM_ATTR uint8_t refresh_done_flag = 0; /* 缓存切换索引 */
DRAM_ATTR _lcd_dev lcddev; /* 管理LCD重要参数 */
uint32_t g_back_color = 0xFFFF; /* 背景色 */
/**
* @brief 读取RGB LCD ID
* @note 利用LCD RGB线的最高位(R7,G7,B7)来识别面板ID
* IO14 = R7(M0); IO8 = G7(M1); IO3 = B7(M2);
* M2:M1:M0
* 0 :0 :0 4.3 寸480*272 RGB屏,ID = 0X4342
* 0 :0 :1 7 寸800*480 RGB屏,ID = 0X7084
* 0 :1 :0 7 寸1024*600 RGB屏,ID = 0X7016
* 0 :1 :1 7 寸1280*800 RGB屏,ID = 0X7018
* 1 :0 :0 4.3 寸800*480 RGB屏,ID = 0X4348
* 1 :0 :1 10.1寸1280*800 RGB屏,ID = 0X1018
*
* @param 无
* @retval 0, 非法;
* 其他, LCD ID
*/
uint16_t lcd_panelid_read(void)
{
uint8_t idx = 0;
gpio_config_t gpio_init_struct = {0};
gpio_init_struct.intr_type = GPIO_INTR_DISABLE; /* 失能引脚中断 */
gpio_init_struct.mode = GPIO_MODE_INPUT; /* 输入输出模式 */
gpio_init_struct.pull_up_en = GPIO_PULLUP_ENABLE; /* 使能上拉 */
gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE; /* 失能下拉 */
gpio_init_struct.pin_bit_mask = 1ull << GPIO_LCD_R7 | 1ull << GPIO_LCD_G7 | 1ull << GPIO_LCD_B7;
gpio_config(&gpio_init_struct); /* 配置GPIO */
idx = (uint8_t)gpio_get_level(GPIO_LCD_R7); /* 读取M0 */
idx |= (uint8_t)gpio_get_level(GPIO_LCD_G7) << 1; /* 读取M1 */
idx |= (uint8_t)gpio_get_level(GPIO_LCD_B7) << 2; /* 读取M2 */
/* 正点原子其他的RGB LCD自行匹配 */
switch (idx)
{
case 0 :
return 0X4342; /* 4.3寸屏, 480*272分辨率 */
case 1 :
return 0X7084; /* 7寸屏, 800*480分辨率 */
case 2:
return 0X7016; /* 7寸屏, 1024*600分辨率 */
case 4:
return 0X4384; /* 4.3寸屏, 800*480分辨率 */
default :
return 0;
}
}
/**
* @brief 内部缓存刷新完成回调函数
* @param panel_io: RGBLCD IO的句柄
* @param edata: 事件数据类型
* @param user_ctx: 传入参数
* @retval 无
*/
IRAM_ATTR static bool lcd_rgb_panel_refresh_done_callback(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx)
{
refresh_done_flag = 1;
return false;
}
/**
* @brief 初始化LCD
* @param 无
* @retval 无
*/
void lcd_init(void)
{
lcddev.id = lcd_panelid_read(); /* 读取RGB LCD面板ID */
lcddev.ctrl.lcd_rst = GPIO_NUM_NC; /* 复位管脚 */
lcddev.ctrl.lcd_bl = GPIO_NUM_NC; /* 背光管脚 */
LCD_BL(0); /* 背光关闭 */
lcddev.lcd_panel_handle = rgblcd_init(); /* 初始化RGB LCD */
ESP_ERROR_CHECK(esp_lcd_rgb_panel_get_frame_buffer(lcddev.lcd_panel_handle, 2, &lcd_buffer[0], &lcd_buffer[1]));
const esp_lcd_rgb_panel_event_callbacks_t rgb_cbs = {
.on_bounce_frame_finish = lcd_rgb_panel_refresh_done_callback, /* 内部缓冲区刷新完成回调函数 */
};
ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(lcddev.lcd_panel_handle, &rgb_cbs, NULL));
lcd_clear(WHITE);
LCD_BL(1); /* 打开背光 */
}
/**
* @brief 清屏
* @param color :清屏颜色
* @retval 无
*/
IRAM_ATTR void lcd_clear(uint16_t color)
{
uint16_t *buffer = (uint16_t *)lcd_buffer[buffer_sw]; /* 将 void* 转换为 uint16_t* */
/* 制定缓存区填充颜色值 */
for (uint32_t i = 0; i < lcddev.width * lcddev.height; i++)
{
buffer[i] = color;
}
esp_lcd_panel_draw_bitmap(lcddev.lcd_panel_handle, 0, 0, lcddev.width, lcddev.height, buffer);
/* 清除传输完成标志 */
refresh_done_flag = 0;
do
{
/* 等待内部缓存刷新完成 */
vTaskDelay(1);
}
while (refresh_done_flag != 1);
/* 使用异或操作在 0 和 1 之间切换,目的是为了切换另一个缓冲区 */
buffer_sw ^= 1;
}
/**
* @brief 画点函数
* @param x,y :写入坐标
* @param color :颜色值
* @retval 无
*/
void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)
{
esp_lcd_panel_draw_bitmap(lcddev.lcd_panel_handle, x, y, x + 1, y + 1, (uint16_t *)&color);
}
33.3.4 CMakeLists.txt 文件
打开本实验 BSP 下的 CMakeLists.txt 文件,其内容如下所示:
set(src_dirs
LED
MYIIC
XL9555
RGBLCD)
set(include_dirs
LED
MYIIC
XL9555
RGBLCD)
set(requires
driver
esp_lcd)
idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})
component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)
33.3.5 实验应用代码
打开 main/main.c 文件,该文件定义了工程入口函数,名为 app_main。该函数代码如下。
/**
* @brief 程序入口
* @param 无
* @retval 无
*/
void app_main(void)
{
esp_err_t ret;
uint8_t x = 0;
ret = nvs_flash_init(); /* 初始化NVS */
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ESP_ERROR_CHECK(nvs_flash_init());
}
led_init(); /* LED初始化 */
myiic_init();
xl9555_init();
lcd_init(); /* LCD屏初始化 */
while (1)
{
switch (x)
{
case 0:
{
lcd_clear(WHITE);
break;
}
case 1:
{
lcd_clear(BLACK);
break;
}
case 2:
{
lcd_clear(BLUE);
break;
}
case 3:
{
lcd_clear(RED);
break;
}
case 4:
{
lcd_clear(MAGENTA);
break;
}
case 5:
{
lcd_clear(GREEN);
break;
}
case 6:
{
lcd_clear(CYAN);
break;
}
case 7:
{
lcd_clear(YELLOW);
break;
}
case 8:
{
lcd_clear(BRRED);
break;
}
case 9:
{
lcd_clear(GRAY);
break;
}
case 10:
{
lcd_clear(LGRAY);
break;
}
case 11:
{
lcd_clear(BROWN);
break;
}
}
lcd_show_string(10, 40, 240, 32, 32, "ESP32-S3", RED);
lcd_show_string(10, 80, 240, 24, 24, "RGBLCD TEST", RED);
lcd_show_string(10, 110, 240, 16, 16, "ATOM@ALIENTEK", RED);
x++;
if (x == 12)
{
x = 0;
}
LED0_TOGGLE();
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
main 函数功能主要是显示一些固定的字符,字体大小包括 32*16、 24*12、 16*8 和 12*6 四种,同时显示 RGB-LCD 驱动 IC 的型号,然后不停的切换背景颜色,每 1s 切换一次。
33.4 下载验证
在初始化完 RGB-LCD 屏幕后,便在 RGB-LCD 上显示一些本实验的相关信息,随后便每间隔 1000 毫秒就更换一次 RGB-LCD 屏幕显示的背景色。

图33.4.1 实验结果显示
更多推荐



所有评论(0)