ESP8266 与 ILI9341 TFT 屏幕实战:解决花屏、镜像、显示不全等问题
引言
ESP8266 以其低成本和 Wi-Fi 功能成为物联网项目的热门选择。ILI9341 TFT 液晶屏则以其适中的价格和良好的显示效果,成为 ESP8266 的理想搭档。然而,将两者结合使用时,经常会出现花屏、镜像、显示不全等问题。本文将深入剖析这些问题的原因,并提供详细的解决方案,助您轻松驾驭 ESP8266 + ILI9341 的组合。
硬件连接
正确连接 ESP8266 和 ILI9341 是首要任务。下表列出了典型连接方式:
ILI9341 引脚 | ESP8266 引脚 | 说明 |
---|---|---|
VCC | 3.3V | 电源 (3.3V) |
GND | GND | 地 |
CS | D8 | 片选 (Chip Select) |
RST/RESET | D2 | 复位 (Reset) |
DC/RS | D1 | 数据/命令 (Data/Command) |
SDI/MOSI | D7 | SPI 数据输入 (MOSI) |
SCK | D5 | SPI 时钟 (SCLK) |
LED | 3.3V | 背光 (或通过电阻,不连接屏幕不亮,见下文) |
SDO/MISO | D6 | (本例中未使用) |
重要提示:
- 电源: ESP8266 和 ILI9341 必须 使用 3.3V 电源。
- LED 背光: 部分 ILI9341 模块的 LED 引脚可直接接 3.3V,部分则需串联限流电阻(如 220Ω 或 330Ω)。请务必查阅您购买的屏幕模块的规格书!
- ESP8266 SPI 引脚: ESP8266 默认的 SPI 引脚为:
D5 (GPIO14)
-SCK
D7 (GPIO13)
-MOSI
D6 (GPIO12)
-MISO
(本例中未使用)
软件设置 (Arduino IDE)
-
安装库:
- 打开 Arduino IDE。
- "工具" -> "管理库..."。
- 搜索并安装 "Adafruit GFX Library" 和 "Adafruit ILI9341"。
-
代码框架(竖屏示例):
#include <SPI.h> #include <Adafruit_GFX.h> #include <Adafruit_ILI9341.h> // 引脚定义 (根据您的实际接线修改) #define TFT_CS D8 #define TFT_DC D1 #define TFT_RST D2 Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); void setup() { Serial.begin(115200); // 用于调试 Serial.println("ILI9341 初始化..."); delay(500); // **重要:** 上电延时,确保屏幕稳定 tft.begin(); // 初始化 ILI9341 SPI.setFrequency(1000000); // **重要:** 设置 SPI 速度 (1 MHz, 稳定) tft.setRotation(0); // 设置屏幕方向:竖屏 // 设置显示区域 (竖屏 240x320) uint8_t caset_data[] = {0x00, 0x00, 0x00, 0xEF}; // 列地址 0-239 tft.sendCommand(ILI9341_CASET, caset_data, 4); uint8_t raset_data[] = {0x00, 0x00, 0x01, 0x3F}; // 行地址 0-319 tft.sendCommand(ILI9341_PASET, raset_data, 4); tft.writeCommand(ILI9341_RAMWR); // 准备写入像素数据 // 设置 MADCTL (Memory Access Control) uint8_t madctl_data = 0xE8; // 竖屏常用值,可能需要调整 (见下文) tft.sendCommand(ILI9341_MADCTL, &madctl_data, 1); tft.fillScreen(ILI9341_BLACK); // 清屏 (黑色) // 显示一些文字 tft.setTextColor(ILI9341_WHITE); tft.setTextSize(2); tft.setCursor(20, 50); tft.println("Hello, ESP8266!"); tft.setTextSize(3); tft.setTextColor(ILI9341_YELLOW); tft.setCursor(40, 120); tft.print("ILI9341"); } void loop() { // (此处可以添加其他代码,例如读取传感器数据并显示) delay(1000); }
常见问题及解决方案
以下是 ESP8266 + ILI9341 组合的常见显示问题及其解决方案:
-
花屏 (Garbage Data):
-
原因:
- SPI 速度过快: ESP8266 的 SPI 速度可能超过 ILI9341 的承受范围。
- 接线问题: 松动、过长或受干扰的连接。
- 电源问题: 不稳定的电源或电压不足。
- 初始化序列问题: 库通常会自动处理,但某些特殊屏幕可能需要手动调整。
-
解决方案:
- 降低 SPI 速度(首要): 使用
SPI.setFrequency(1000000);
将 SPI 速度设置为 1 MHz(或更低)。 - 检查接线: 确保所有连接牢固、紧凑,远离干扰源。
- 检查电源: 用万用表确认 ILI9341 的 VCC 引脚电压稳定在 3.3V。
- 增加上电延时: 在
tft.begin();
前加入delay(500);
。
- 降低 SPI 速度(首要): 使用
-
-
镜像 (Mirroring) 和倒置 (Inversion):
-
原因: MADCTL (Memory Access Control) 寄存器设置不当。
-
解决方案:
- 理解 MADCTL: MADCTL 是一个 8 位寄存器,控制屏幕的扫描方向、行列顺序和颜色:
- Bit 7 (MY): 行地址顺序 (0: 从上到下, 1: 从下到上)
- Bit 6 (MX): 列地址顺序 (0: 从左到右, 1: 从右到左)
- Bit 5 (MV): 行/列交换 (0: 不交换, 1: 交换) <-- 竖屏/横屏的关键
- Bit 4 (ML): 垂直刷新 (0: 从上到下, 1: 从下到上)
- Bit 3 (RGB): 颜色顺序 (0: RGB, 1: BGR) <-- ILI9341 通常是 BGR
- Bits 2-0: 未使用
- 设置 MADCTL:
uint8_t madctl_data = 0x...; // 根据需要设置值 tft.sendCommand(ILI9341_MADCTL, &madctl_data, 1);
- 常用 MADCTL 值:
setRotation(0)
(竖屏):0x68
或0xE8
setRotation(1)
(横屏):0x48
或0xC8
- 重要:更改 MADCTL 值或旋转方向后, 务必完全断电重启!
- 理解 MADCTL: MADCTL 是一个 8 位寄存器,控制屏幕的扫描方向、行列顺序和颜色:
-
-
分辨率错误/显示不全:
-
原因:
- Adafruit_ILI9341 库未能自动识别屏幕的正确分辨率。
- MADCTL 设置错误。
-
解决方案:
- 强制设置显示区域 (CASET 和 PASET):
// 横屏 (320x240) uint8_t caset_data[] = {0x00, 0x00, 0x01, 0x3F}; // 列: 0-319 uint8_t raset_data[] = {0x00, 0x00, 0x00, 0xEF}; // 行: 0-239 // 竖屏 (240x320) // uint8_t caset_data[] = {0x00, 0x00, 0x00, 0xEF}; // 列: 0-239 // uint8_t raset_data[] = {0x00, 0x00, 0x01, 0x3F}; // 行: 0-319 tft.sendCommand(ILI9341_CASET, caset_data, 4); // 设置列地址 tft.sendCommand(ILI9341_PASET, raset_data, 4); // 设置行地址 tft.writeCommand(ILI9341_RAMWR); // 准备写入像素数据
- 结合 MADCTL 调整: 确保 MADCTL 设置与屏幕方向和 CASET/PASET 设置一致。
- 强制设置显示区域 (CASET 和 PASET):
-
总结
通过掌握以上方法,您应该能够解决 ESP8266 与 ILI9341 TFT 屏幕组合的绝大多数显示问题。记住,细心检查硬件、理解 MADCTL、正确设置显示区域是成功的关键。祝您的项目顺利!
横屏模式 (setRotation(1)) 代码,并加入了详细注释和可能需要的调整:
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
// ILI9341 引脚定义 (根据您的实际接线)
#define TFT_CS D8 // 片选
#define TFT_DC D1 // 数据/命令
#define TFT_RST D2 // 复位
// 创建 Adafruit_ILI9341 对象
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
void setup() {
Serial.begin(115200); // 初始化串口,用于调试
Serial.println("ILI9341 Test!");
delay(500); // **重要:** 上电延时,确保 ILI9341 稳定
tft.begin(); // 初始化 ILI9341 屏幕
SPI.setFrequency(1000000); // **重要:** 设置 SPI 时钟频率为 1 MHz (保守值)
tft.setRotation(1); // 设置屏幕为横屏模式 (1:横屏)
// ********** 设置显示区域 (横屏 320x240) **********
// CASET (Column Address Set) - 设置列地址范围
uint8_t caset_data[] = {0x00, 0x00, 0x01, 0x3F}; // 0x0000 到 0x013F (0-319)
tft.sendCommand(ILI9341_CASET, caset_data, 4);
// PASET (Page Address Set) - 设置行地址范围
uint8_t raset_data[] = {0x00, 0x00, 0x00, 0xEF}; // 0x0000 到 0x00EF (0-239)
tft.sendCommand(ILI9341_PASET, raset_data, 4);
tft.writeCommand(ILI9341_RAMWR); // **重要:** 发送 RAM Write 命令,准备写入像素数据
// ********** 设置 MADCTL (Memory Access Control) **********
uint8_t madctl_data;
// 对于 setRotation(1) (横屏),通常 0x48 或 0xC8 是正确的值
// 0x48: 正常
// 0xC8: 垂直翻转 (如果 0x48 显示上下颠倒,就用 0xC8)
madctl_data = 0x48; // 先尝试 0x48
tft.sendCommand(ILI9341_MADCTL, &madctl_data, 1);
delay(1000); // 更改 MADCTL 后短暂延时
// 清屏 (黑色)
tft.fillScreen(ILI9341_BLACK);
// 设置文本颜色 (白色)
tft.setTextColor(ILI9341_WHITE);
// 设置文本大小 (2)
tft.setTextSize(2);
// 设置光标位置 (x=20, y=50)
tft.setCursor(20, 50);
// 显示文字
tft.println("Hello, ESP8266!");
// 设置文本大小 (3)
tft.setTextSize(3);
// 设置文本颜色 (黄色)
tft.setTextColor(ILI9341_YELLOW);
// 设置光标位置 (x=40, y=120)
tft.setCursor(40, 120);
// 显示文字
tft.print("ILI9341");
delay(1000); // 观察显示效果
}
void loop() {
delay(1000); // 简单延时
}
代码的关键点和解释:
-
#define TFT_CS D8
,#define TFT_DC D1
,#define TFT_RST D2
:- 这些是引脚定义,将 ESP8266 的 D8、D1 和 D2 引脚分别定义为 ILI9341 屏幕的 CS、DC 和 RST 引脚。
- 请根据您的实际接线修改这些定义!
-
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
:- 创建一个
Adafruit_ILI9341
对象,用于控制 ILI9341 屏幕。 - 将之前定义的引脚传递给构造函数。
- 创建一个
-
Serial.begin(115200);
:- 初始化串口通信,波特率为 115200。这用于通过串口监视器进行调试。
-
delay(500);
:- 非常重要: 上电延时。在 ESP8266 和 ILI9341 上电后,需要一个短暂的延时(至少几百毫秒),以确保 ILI9341 控制器完全初始化并准备好接收命令。
-
tft.begin();
:- 初始化 ILI9341 屏幕。这会发送一系列初始化命令给 ILI9341 控制器。
-
SPI.setFrequency(1000000);
:- 非常重要: 设置 SPI 时钟频率为 1 MHz (1000000 Hz)。这是一个相对保守(慢)的值,可以最大程度地兼容不同的 ILI9341 屏幕和 ESP8266 板。
- 如果 1 MHz 工作正常,您可以尝试逐渐增加这个值(例如,2 MHz、4 MHz、8 MHz 等),以找到您的硬件配置下的最高稳定速度。但请记住,过高的 SPI 速度会导致数据错误(花屏)。
-
tft.setRotation(1);
:- 设置屏幕的旋转方向。
0
: 竖屏(肖像模式),240x3201
: 横屏(风景模式),320x240,您的代码中使用的就是这个2
: 竖屏(肖像模式,180 度旋转)3
: 横屏(风景模式,180 度旋转)
- 设置屏幕的旋转方向。
-
CASET
和PASET
(设置显示区域):uint8_t caset_data[] = {0x00, 0x00, 0x01, 0x3F}; // 0-319 (列) tft.sendCommand(ILI9341_CASET, caset_data, 4); uint8_t raset_data[] = {0x00, 0x00, 0x00, 0xEF}; // 0-239 (行) tft.sendCommand(ILI9341_PASET, raset_data, 4);
ILI9341_CASET
(Column Address Set):设置要显示的列的起始和结束地址。ILI9341_PASET
(Page Address Set):设置要显示的行的起始和结束地址。- 对于横屏模式 (
setRotation(1)
),我们设置:- 列:0-319 (0x0000 - 0x013F)
- 行:0-239 (0x0000 - 0x00EF)
-
tft.writeCommand(ILI9341_RAMWR);
:- 非常重要: 在设置完显示区域(
CASET
和PASET
)后,必须发送ILI9341_RAMWR
(Memory Write) 命令。这告诉 ILI9341 控制器,接下来我们要开始写入像素数据到显存了。
- 非常重要: 在设置完显示区域(
-
MADCTL
(Memory Access Control):uint8_t madctl_data = 0x48; // 尝试 0x48,如果不行,尝试 0xC8 tft.sendCommand(ILI9341_MADCTL, &madctl_data, 1);
MADCTL
是一个非常重要的寄存器,它控制着屏幕的扫描方向、行/列地址顺序以及颜色顺序(RGB 或 BGR)。- 对于
setRotation(1)
(横屏),通常0x48
或0xC8
是正确的值。0x48
: 正常(没有垂直翻转)0xC8
: 垂直翻转(如果0x48
显示上下颠倒,就用0xC8
)
- 如果您的屏幕显示仍然有问题(例如,上下镜像),请尝试将
0x48
改为0xC8
。
-
文本显示:
tft.fillScreen(ILI9341_BLACK);
: 清屏为黑色。tft.setTextColor(ILI9341_WHITE);
: 设置文本颜色为白色。tft.setTextSize(2);
: 设置文本大小为 2。tft.setCursor(20, 50);
: 设置光标位置(x=20, y=50)。tft.println("Hello, ESP8266!");
: 显示一行文字。tft.setTextSize(3);
,tft.setTextColor(ILI9341_YELLOW);
,tft.setCursor(40, 120);
,tft.print("ILI9341");
: 显示另一行文字。
总结:
这段代码提供了一个坚实的基础,用于在横屏模式下使用 ESP8266 和 ILI9341 屏幕。如果您的屏幕仍然显示不正常,请务必:
- 仔细检查接线。
- 尝试不同的
madctl_data
值(0x48
或0xC8
)。 - 确保在更改
madctl_data
或setRotation()
后,完全断电重启 ESP8266 和屏幕。 - 如果可以, 提供您的屏幕型号和购买链接, 这能帮助提供更具体的建议
本文作者: 永生
本文链接: https://yys.zone/detail/?id=383
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
发表评论
评论列表 (0 条评论)
暂无评论,快来抢沙发吧!