引言

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. 如果可以, 提供您的屏幕型号和购买链接, 这能帮助提供更具体的建议

加入wifi功能

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <map>
#include <vector>

const char* ssid = "yang1234"; //  请替换为你的 Wi-Fi SSID
const char* password = "y123456789"; //  请替换为你的 Wi-Fi 密码

#define TFT_CS   D8
#define TFT_DC   D1
#define TFT_RST  D2

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
ESP8266WebServer server(80);

struct LineData {
    String text;
    uint16_t color;
    uint8_t size;
    int16_t y;
};

std::map<int, LineData> lines;

// --- 图片数据结构 ---
struct ImageData {
    std::vector<uint16_t> pixels;
    int16_t width;
    int16_t height;
    int16_t y_offset; // 图片的 Y 轴偏移量
};

ImageData image;

// 全局变量,控制是否使用 GBR 格式
bool useGBR = true; //  GBR 格式

void handleSet();
void handleImage(); // 新增图片处理函数
void handleNotFound();
void updateDisplay();
void connectToWiFi();
uint16_t parseColor(String colorString);

void setup() {
    Serial.begin(115200);
    tft.begin();
    SPI.setFrequency(1000000);
    tft.setRotation(0);

    uint8_t caset_data[] = {0x00, 0x00, 0x00, 0xEF};
    tft.sendCommand(ILI9341_CASET, caset_data, 4);
    uint8_t raset_data[] = {0x00, 0x00, 0x01, 0x3F};
    tft.sendCommand(ILI9341_PASET, raset_data, 4);
    tft.writeCommand(ILI9341_RAMWR);

    uint8_t madctl_data = 0xE8;
    tft.sendCommand(ILI9341_MADCTL, &madctl_data, 1);

    tft.fillScreen(ILI9341_BLACK);
    connectToWiFi();

    server.on("/set", HTTP_POST, handleSet);
    server.on("/image", HTTP_POST, handleImage); //  处理图片请求
    server.onNotFound(handleNotFound);
    server.begin();
    Serial.println("HTTP server started");
    updateDisplay();
}

void loop() {
    server.handleClient();
}

void connectToWiFi() {
    WiFi.begin(ssid, password);
    Serial.print("Connecting to Wi-Fi");
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("\nConnected! IP address:");
    Serial.println(WiFi.localIP());
    Serial.print("请在Python脚本中将 esp8266_ip  替换为: ");
    Serial.println(WiFi.localIP());
}

void handleSet() {
    lines.clear();

    for (int i = 0; i < 100; i++) {
        String lineKey = "line" + String(i);

        if (server.hasArg(lineKey)) {
            LineData line;
            line.text = server.arg(lineKey);

            String colorKey = "color" + String(i);
            if (server.hasArg(colorKey)) {
                line.color = parseColor(server.arg(colorKey));
            } else {
                line.color = ILI9341_WHITE;
            }

            String sizeKey = "size" + String(i);
            if (server.hasArg(sizeKey)) {
                int size = server.arg(sizeKey).toInt();
                line.size = (size >= 1 && size <= 7) ? size : 2;
            } else {
                line.size = 2;
            }

            lines[i] = line;
        }
    }

    updateDisplay();
    server.send(200, "text/plain", "OK");
}

// --- 处理图片上传 ---
void handleImage() {
    if (server.hasArg("width") && server.hasArg("height") && server.hasArg("data")) {
        int width = server.arg("width").toInt();
        int height = server.arg("height").toInt();
        String data = server.arg("data");

        if (width > 0 && height > 0 && data.length() > 0) {
            image.width = width;
            image.height = height;
            image.pixels.clear();
            image.pixels.reserve(width * height); // 预留空间

            // 将接收到的字符串数据转换为像素数据
            for (int i = 0; i < data.length(); i += 4) { // 假设每像素 4 字符 (16进制)
                if (i + 4 <= data.length()) {
                    String hexColor = data.substring(i, i + 4);
                    unsigned long colorValue = strtoul(hexColor.c_str(), NULL, 16);
                    image.pixels.push_back(colorValue);
                }
            }
            image.y_offset = 0; // 默认图片 Y 轴偏移量为 0
            if (server.hasArg("y_offset")) {
                 image.y_offset = server.arg("y_offset").toInt();
            }


            updateDisplay(); // 更新显示
            server.send(200, "text/plain", "Image OK");
        } else {
            server.send(400, "text/plain", "Invalid image parameters");
        }
    } else {
        server.send(400, "text/plain", "Image parameters missing");
    }
}


void handleNotFound() {
    server.send(404, "text/plain", "404 Not Found");
}

void updateDisplay() {
    tft.fillScreen(ILI9341_BLACK);
    int16_t yPos = 20;

    for (auto& [lineNum, line] : lines) {
        line.y = yPos;

         // --- 左对齐 ---
        int16_t xPos = 20; // 左边距为 20 像素

        tft.setCursor(xPos, line.y);
        tft.setTextColor(line.color);
        tft.setTextSize(line.size);
        tft.println(line.text);

        yPos += line.size * 6 * (tft.getRotation() % 2 == 0 ? 1 : 2) + 15; // 15 像素行间距
    }

    // --- 显示图片 ---
    if (!image.pixels.empty()) {
        int16_t startY = yPos + image.y_offset; // 图片的起始 Y 坐标,在文字下方
        for (int y = 0; y < image.height; y++) {
            for (int x = 0; x < image.width; x++) {
                if (x < tft.width() && (startY + y) < tft.height()) { // 边界检查
                     tft.drawPixel(x, startY + y, image.pixels[y * image.width + x]);
                }
            }
        }
    }
}

uint16_t parseColor(String colorString) {
    if (colorString == "red")       return ILI9341_RED;
    if (colorString == "green")     return ILI9341_GREEN;
    if (colorString == "blue")      return ILI9341_BLUE;
    if (colorString == "yellow")    return ILI9341_YELLOW;
    if (colorString == "cyan")      return ILI9341_CYAN;
    if (colorString == "magenta")   return ILI9341_MAGENTA;
    if (colorString == "white")     return ILI9341_WHITE;
    if (colorString == "black")     return ILI9341_BLACK;
    if (colorString == "orange")    return ILI9341_ORANGE;

    if (colorString.startsWith("#") && colorString.length() == 7) {
        long number = strtol(colorString.substring(1).c_str(), NULL, 16);
        uint8_t r = (number >> 16) & 0xFF;
        uint8_t g = (number >> 8) & 0xFF;
        uint8_t b = number & 0xFF;
        uint16_t color565;

        if (useGBR) {
            // GBR 转换:  G(5) B(6) R(5)
            color565 = ((g & 0xF8) << 8) | ((b & 0xFC) << 3) | (r >> 3);
            Serial.println("Using GBR conversion");
        } else {
            // RGB565 转换 (默认)
            color565 = tft.color565(r, g, b);
             Serial.println("Using RGB conversion");
        }

        // --- 串口调试输出 ---
        Serial.print("Color String: ");
        Serial.println(colorString);
        Serial.print("R: "); Serial.println(r);
        Serial.print("G: "); Serial.println(g);
        Serial.print("B: "); Serial.println(b);
        Serial.print("565 Color: "); Serial.println(color565);

        return color565;
    }
    return ILI9341_WHITE;
}

 

ESP8266_ILI9341 项目的 README 文件。它采用了您提供的优秀模板的结构和风格,旨在让任何接手此项目的人都能一目了然。


ESP8266 智能双控触摸屏 (v4.5)

这是一个高度可靠功能完备的 ESP8266 物联网(IoT)控制器。它以一块 ILI9341 触摸屏为核心,通过一个简洁的双按钮界面,实现了对两个独立网络设备(Home Assistant 实体和任意 HTTP 设备)的远程控制。

项目集成了优雅的网页日志系统OTA 在线更新功能,并采用了一个经过优化的软件待机模式,在保证绝对可靠唤醒的前提下,通过关闭屏幕关闭Wi-Fi并降低CPU频率,实现了显著的功耗降低。

[此处应有项目运行时的照片]

✨ 核心功能

  • 📱 双按钮触摸界面: 在屏幕上提供两个清晰独立的触摸按钮,分别控制两个不同的智能设备。
  • 🌐 双设备网络遥控:
    • 通过 Home Assistant API 控制一个设备(例如开关灯光)。
    • 通过发送 HTTP GET 请求 控制另一个设备(例如其他ESP模块或任何支持URL控制的设备)。
  • 💤 智能软件待机: 经过优化的低功耗模式,比常规待机功耗更低。
    • 一分钟无操作后,自动 关闭Wi-Fi关闭屏幕控制器及背光,并将CPU降频至80MHz 以最大限度节省能源。
  • 👆 触摸唤醒: 在待机模式下,任何触摸都会立即可靠地唤醒设备,恢复全部功能。
  • 📋 网页事件日志:
    • 通过浏览器访问 /logs 页面,可查看带有精确时间戳的设备事件历史。
    • 日志内容包括:系统启动待机/唤醒Wi-Fi连接状态触摸坐标按钮触发动作等。
  • ☁️ OTA 在线更新: 无需连接数据线,通过网页即可上传新固件进行更新。
  • 🕒 NTP 自动校时: 自动从网络时间服务器同步时间,确保日志时间戳的准确性。

🛠️ 硬件清单

  1. 主控: ESP8266 开发板 (例如 NodeMCU Wemos D1 Mini)。
  2. 显示屏: ILI9341 TFT 触摸屏模块 (2.4寸 240x320 SPI接口 带XPT2046触摸控制器)。
  3. 电源: 5V MicroUSB 电源。
  4. 杜邦线 若干。

🔌 硬件接线

组件/功能 ESP8266 引脚 (GPIO) 连接到屏幕模块引脚 功能描述
TFT 显示 15 (D8) CS 屏幕片选
  5 (D1) DC / RS 屏幕数据/命令选择
  4 (D2) RST 屏幕复位
触摸 0 (D3) T_CS 触摸芯片片选
SPI (共享) 14 (D5) SCK / T_CLK 并联到屏幕和触摸的时钟线
  12 (D6) MISO / T_DO 并联到屏幕和触摸的数据输出
  13 (D7) MOSI / T_DIN 并联到屏幕和触摸的数据输入
电源 3V3 VCC 为屏幕和触摸模块供电
  GND GND 公共地线

背光控制 (两种方案可选)

  • 方案一 (推荐,支持待机):

    • 将 ESP8266 的 D0 (GPIO 16) 引脚连接到屏幕模块的 LED (或 BL) 引脚。本项目的代码基于此方案编写。
  • 方案二 (极简,屏幕常亮):

    • 将屏幕模块的 LED 引脚直接连接到 ESP8266 的 3.3V 引脚。如果采用此方案,您可以将代码中所有与 TFT_LED 相关的行删除。

⚙️ 软件与配置

1. 准备 Arduino IDE

  • 安装 Arduino IDE: 从 官方网站 下载并安装。
  • 配置 ESP8266 开发板环境:
    • 打开 文件 -> 首选项
    • 在 "附加开发板管理器网址" 中,填入: http://arduino.esp8266.com/stable/package_esp8266com_index.json
    • 打开 工具 -> 开发板 -> 开发板管理器,搜索 esp8266 并安装。
  • 安装所需库:
    • 打开 工具 -> 管理库
    • 搜索并安装以下所有库:
      • Adafruit GFX Library
      • Adafruit ILI9341
      • XPT2046_Touchscreen
      • ArduinoJson
      • NTPClient by Fabrice Weinberg

2. 配置固件

用 Arduino IDE 打开项目代码 (.ino 文件),所有您需要修改的配置项都集中在文件的最顶部。

a. 配置 WiFi:

const char* ssid = "你的WiFi名称"
const char* password = "你的WiFi密码"

b. 配置 Home Assistant 和 HTTP 设备:

const char* ha_host = "192.168.31.22"
const int ha_port = 8123
const char* ha_token = "你的HA长期访问令牌"
const char* ha_entity_id = "switch.你的HA实体ID"

const char* led_on_url = "http://你的设备IP/开灯指令"
const char* led_off_url = "http://你的设备IP/关灯指令"

c. (重要!) 配置触摸屏校准:
每个触摸屏都有细微差异。请使用我们之前的校准程序获取您屏幕的专属 min/max 坐标,并替换 handleTouch() 函数中的以下两行:

// 示例值,请务必替换为您自己的校准值
int screen_x = map(p.y 295 3750 0 240) 
int screen_y = map(p.x 358 3810 0 320)

🚀 使用方法

  1. 上传代码: 在 Arduino IDE 中选择您的开发板型号 (例如 NodeMCU 1.0) 和端口,然后点击上传。
  2. 获取 IP 地址: 上传成功后,打开 工具 -> 串口监视器 (波特率设为 115200),等待 ESP8266 连接上 WiFi 后,会打印出设备的 IP 地址。
  3. 开始使用:
    • 屏幕控制: 直接点击屏幕上的按钮即可控制设备。设备将在无操作1分钟后自动进入待机模式(屏幕熄灭),再次触摸即可唤醒。
    • 网页访问:
      • 在浏览器中输入获取到的 IP 地址,可以访问主页。
      • 点击主页上的 “查看事件日志” 按钮,或直接访问 http://[IP地址]/logs 来查看详细的操作历史。
      • 若要更新固件,请访问 http://[IP地址]/update