引言

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)

  1. 安装库:

    • 打开 Arduino IDE。
    • "工具" -> "管理库..."。
    • 搜索并安装 "Adafruit GFX Library" 和 "Adafruit ILI9341"。
  2. 代码框架(竖屏示例):

    #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 组合的常见显示问题及其解决方案:

  1. 花屏 (Garbage Data):

    • 原因:

      • SPI 速度过快: ESP8266 的 SPI 速度可能超过 ILI9341 的承受范围。
      • 接线问题: 松动、过长或受干扰的连接。
      • 电源问题: 不稳定的电源或电压不足。
      • 初始化序列问题: 库通常会自动处理,但某些特殊屏幕可能需要手动调整。
    • 解决方案:

      • 降低 SPI 速度(首要): 使用 SPI.setFrequency(1000000); 将 SPI 速度设置为 1 MHz(或更低)。
      • 检查接线: 确保所有连接牢固、紧凑,远离干扰源。
      • 检查电源: 用万用表确认 ILI9341 的 VCC 引脚电压稳定在 3.3V。
      • 增加上电延时: 在 tft.begin(); 前加入 delay(500);
  2. 镜像 (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 值或旋转方向后, 务必完全断电重启!
  3. 分辨率错误/显示不全:

    • 原因:

      • 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 设置一致。

总结

通过掌握以上方法,您应该能够解决 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); // 简单延时
}

代码的关键点和解释:

  1. #define TFT_CS D8#define TFT_DC D1#define TFT_RST D2:

    • 这些是引脚定义,将 ESP8266 的 D8、D1 和 D2 引脚分别定义为 ILI9341 屏幕的 CS、DC 和 RST 引脚。
    • 请根据您的实际接线修改这些定义!
  2. Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);:

    • 创建一个 Adafruit_ILI9341 对象,用于控制 ILI9341 屏幕。
    • 将之前定义的引脚传递给构造函数。
  3. Serial.begin(115200);:

    • 初始化串口通信,波特率为 115200。这用于通过串口监视器进行调试。
  4. delay(500);:

    • 非常重要: 上电延时。在 ESP8266 和 ILI9341 上电后,需要一个短暂的延时(至少几百毫秒),以确保 ILI9341 控制器完全初始化并准备好接收命令。
  5. tft.begin();:

    • 初始化 ILI9341 屏幕。这会发送一系列初始化命令给 ILI9341 控制器。
  6. SPI.setFrequency(1000000);:

    • 非常重要: 设置 SPI 时钟频率为 1 MHz (1000000 Hz)。这是一个相对保守(慢)的值,可以最大程度地兼容不同的 ILI9341 屏幕和 ESP8266 板。
    • 如果 1 MHz 工作正常,您可以尝试逐渐增加这个值(例如,2 MHz、4 MHz、8 MHz 等),以找到您的硬件配置下的最高稳定速度。但请记住,过高的 SPI 速度会导致数据错误(花屏)。
  7. tft.setRotation(1);:

    • 设置屏幕的旋转方向。
      • 0: 竖屏(肖像模式),240x320
      • 1: 横屏(风景模式),320x240,您的代码中使用的就是这个
      • 2: 竖屏(肖像模式,180 度旋转)
      • 3: 横屏(风景模式,180 度旋转)
  8. 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)
  9. tft.writeCommand(ILI9341_RAMWR);:

    • 非常重要: 在设置完显示区域(CASET 和 PASET)后,必须发送 ILI9341_RAMWR (Memory Write) 命令。这告诉 ILI9341 控制器,接下来我们要开始写入像素数据到显存了。
  10. 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
  11. 文本显示:

    • 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 屏幕。如果您的屏幕仍然显示不正常,请务必:

  1. 仔细检查接线。
  2. 尝试不同的 madctl_data 值(0x48 或 0xC8)。
  3. 确保在更改 madctl_data 或 setRotation() 后,完全断电重启 ESP8266 和屏幕。
  4. 如果可以, 提供您的屏幕型号和购买链接, 这能帮助提供更具体的建议