以下是针对「无复位引脚 + CS 引脚硬件永久拉低」场景的完整可运行代码,适配 ESP-IDF 框架,以主流的 ST7789 240x240 LCD 为例(其他型号如 ILI9341 仅需替换面板初始化函数),核心是「禁用软件控制 CS / 复位引脚 + 软件指令复位 + 高频时序补偿」:
完整代码(关键注释 + 适配逻辑)
#include "driver/spi_master.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
// ====================== 硬件配置(根据实际接线修改) ======================
#define LCD_SPI_HOST SPI3_HOST // SPI主机(HSPI)
#define LCD_DC_GPIO GPIO_NUM_39 // DC/RS引脚(必须接)
#define LCD_SCK_GPIO GPIO_NUM_14 // SPI时钟引脚
#define LCD_MOSI_GPIO GPIO_NUM_13 // SPI数据引脚(仅输出,MISO可省)
#define LCD_PCLK_HZ 40 * 1000 * 1000// SPI时钟频率(80MHz易出错,先40MHz)
#define LCD_WIDTH 240 // LCD宽度
#define LCD_HEIGHT 240 // LCD高度
#define LCD_COLOR_INVERT true // 颜色反转(根据面板调整)
#define LCD_SWAP_XY false // XY轴交换(根据面板调整)
#define LCD_MIRROR_X false // X轴镜像(根据面板调整)
#define LCD_MIRROR_Y false // Y轴镜像(根据面板调整)
static const char *TAG = "LCD_NO_RST_NO_CS";
esp_lcd_panel_io_handle_t panel_io = NULL;
esp_lcd_panel_handle_t panel = NULL;
// ====================== 核心初始化函数 ======================
static void lcd_init_no_rst_no_cs(void)
{
// 1. 初始化SPI总线(必须先初始化总线,再初始化面板IO)
spi_bus_config_t bus_cfg = {
.sclk_io_num = LCD_SCK_GPIO, // SPI时钟引脚
.mosi_io_num = LCD_MOSI_GPIO, // SPI数据输出引脚
.miso_io_num = -1, // 无MISO(仅写LCD,无需读)
.quadwp_io_num = -1, // 禁用四线SPI
.quadhd_io_num = -1, // 禁用四线SPI
.max_transfer_sz = LCD_WIDTH * 2, // 最大传输大小(16位色,每行字节数)
};
ESP_ERROR_CHECK(spi_bus_initialize(LCD_SPI_HOST, &bus_cfg, SPI_DMA_CH_AUTO));
// 2. 配置LCD面板IO(核心:禁用CS/复位引脚)
esp_lcd_panel_io_spi_config_t io_config = {
.cs_gpio_num = GPIO_NUM_NC, // 禁用软件控制CS(硬件永久低电平)
.dc_gpio_num = LCD_DC_GPIO, // DC引脚(必须配置)
.spi_mode = 2, // SPI模式(根据LCD手册,ST7789常用模式2)
.pclk_hz = LCD_PCLK_HZ, // SPI时钟频率
.trans_queue_depth = 10, // 传输队列深度(增大避免阻塞)
.lcd_cmd_bits = 8, // 命令位宽(多数LCD为8)
.lcd_param_bits = 8, // 参数位宽(多数LCD为8)
// 关键:高频SPI时序补偿(无CS引脚需增加补偿)
.cs_ena_pretrans = 2, // 传输前补偿2个bit-cycle
.cs_ena_posttrans = 2, // 传输后补偿2个bit-cycle
// 关键:CS低电平有效(硬件永久低电平,必须显式配置)
.flags = {
.cs_high_active = 0, // CS低电平有效(核心!)
.dc_high_on_cmd = 0, // DC低电平=命令,高电平=数据(ST7789默认)
.dc_low_on_data = 1, // DC低电平=数据(与上一行匹配)
.lsb_first = 0, // 高位先传输
},
};
// 创建SPI面板IO
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI_HOST, &io_config, &panel_io));
// 3. 配置LCD面板(核心:禁用复位引脚,依赖软件复位)
esp_lcd_panel_dev_config_t panel_cfg = {
.reset_gpio_num = GPIO_NUM_NC, // 禁用硬件复位引脚(无RST引脚)
.bits_per_pixel = 16, // 16位色(RGB565,嵌入式主流)
};
// 初始化ST7789面板(替换为对应型号:ILI9341用esp_lcd_new_panel_ili9341)
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_cfg, &panel));
// 4. 软件复位(无RST引脚,依赖指令复位)+ 延长稳定时间
ESP_LOGI(TAG, "Software reset LCD (no RST pin)");
esp_lcd_panel_reset(panel); // 内部发送软件复位指令(如ST7789的0x01)
vTaskDelay(pdMS_TO_TICKS(200)); // 延长稳定时间(无RST引脚需≥200ms)
// 5. 面板初始化 + 显示配置
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, LCD_COLOR_INVERT));
ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, LCD_SWAP_XY));
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, LCD_MIRROR_X, LCD_MIRROR_Y));
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, true)); // 开启显示
ESP_LOGI(TAG, "LCD init success (no RST, no CS)");
}
// ====================== 测试函数:显示纯色 ======================
static void lcd_test_draw_color(uint16_t color)
{
uint16_t *buf = (uint16_t *)malloc(LCD_WIDTH * sizeof(uint16_t));
if (buf == NULL) {
ESP_LOGE(TAG, "Malloc buffer failed");
return;
}
// 填充纯色
for (int i = 0; i < LCD_WIDTH; i++) {
buf[i] = color;
}
// 逐行绘制(覆盖整个屏幕)
for (int y = 0; y < LCD_HEIGHT; y++) {
ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel, 0, y, LCD_WIDTH, y+1, buf));
}
free(buf);
ESP_LOGI(TAG, "Draw color 0x%04X success", color);
}
// ====================== App Main ======================
void app_main(void)
{
// 初始化LCD(无RST/CS引脚)
lcd_init_no_rst_no_cs();
// 循环显示不同颜色,验证显示正常
while (1) {
lcd_test_draw_color(0xF800); // 红色(RGB565)
vTaskDelay(pdMS_TO_TICKS(1000));
lcd_test_draw_color(0x07E0); // 绿色
vTaskDelay(pdMS_TO_TICKS(1000));
lcd_test_draw_color(0x001F); // 蓝色
vTaskDelay(pdMS_TO_TICKS(1000));
lcd_test_draw_color(0xFFFF); // 白色
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
关键适配点(必看!)
1. 核心配置说明(无 RST/CS 场景)
| 配置项 | 取值 / 原因 |
|---|---|
cs_gpio_num = GPIO_NUM_NC |
禁用软件控制 CS,完全依赖硬件永久低电平 |
reset_gpio_num = GPIO_NUM_NC |
禁用硬件复位引脚,依赖软件指令复位 |
cs_ena_pretrans/posttrans = 2 |
补偿 SPI 时序(无 CS 引脚时,高频下需 ≥2) |
flags.cs_high_active = 0 |
明确 CS 低电平有效(硬件永久低电平,必须显式配置) |
| 复位后延时 200ms | 无 RST 引脚时,软件复位指令需要更长时间生效(默认 120ms→ 延长到 200ms) |
2. 不同 LCD 型号适配
- ILI9341:将
esp_lcd_new_panel_st7789替换为esp_lcd_new_panel_ili9341,SPI 模式改为 0(ILI9341 常用模式 0); - ST7735:替换为
esp_lcd_new_panel_st7735,调整LCD_WIDTH/HEIGHT为 128x160; - **SSD1306(OLED)**:需改用 I2C 配置,
cs_gpio_num仍设为GPIO_NUM_NC,复位引脚同理。
3. 高频 SPI 适配(如需 80MHz)
若要将 LCD_PCLK_HZ 改为 80MHz,需进一步增加时序补偿:
.io_config.cs_ena_pretrans = 3; // 80MHz下补偿3个bit-cycle(37.5ns)
.io_config.cs_ena_posttrans = 3;
常见问题排查(无 RST/CS 场景)
- 显示乱码 / 无显示:
- 降低 SPI 频率到 20MHz 验证;
- 检查
spi_mode是否与 LCD 手册一致(模式 0/2 是主流); - 确认
dc_high_on_cmd/dc_low_on_data配置(DC 引脚电平是否区分命令 / 数据)。
- 软件复位失效:
-
延长复位后延时到 300ms;
-
手动发送复位指令(替代
esp_lcd_panel_reset):const uint8_t sw_reset_cmd = 0x01; // ST7789复位指令 ESP_ERROR_CHECK(esp_lcd_panel_io_tx_param(panel_io, sw_reset_cmd, NULL, 0)); vTaskDelay(pdMS_TO_TICKS(200));
-
- 颜色反转 / 镜像错误:
-
调整
LCD_COLOR_INVERT/LCD_MIRROR_X/Y/LCD_SWAP_XY参数; -
部分面板需配置
esp_lcd_panel_set_gap调整偏移:esp_lcd_panel_set_gap(panel, 0, 0); // X/Y偏移,根据面板调整
-
核心总结
该代码的核心设计是:
- 禁用软件控制:通过
GPIO_NUM_NC让驱动放弃 CS / 复位引脚的控制; - 时序补偿:针对无 CS 引脚的硬件设计,增加 SPI 时序补偿;
- 软件复位兜底:无 RST 引脚时,延长复位后延时保证指令生效;
- 极简依赖:仅依赖 DC/SCK/MOSI 三个引脚(无 CS/RST),适配硬件极简设计。
可直接烧录测试,若显示异常,优先降低 SPI 频率、调整 SPI 模式和时序补偿参数。

注意事项:
上电后至少给显示器100ms复位信号,可通过增加RC复位电路的电容值实现。🤒