esp32 ——lcd篇

硬件

开发板上的液晶屏是2.0寸的IPS高清液晶屏,分辨率240*320,显示非常清晰。液晶屏驱动芯片ST7789,采用SPI通信方式与ESP32-C3连接。开发板上的触摸屏是电容触摸屏,用手指就可以触摸,支持双指触摸。触摸芯片型号是FT6336,使用I2C接口与ESP32-C3连接,I2C地址为0x38。

环境

esp-idf 5.3.1

lcd显示

spi总线初始化

#define PIN_NUM_MISO -1
#define PIN_NUM_MOSI 5
#define PIN_NUM_CLK 3

#define LCD_HOST  SPI2_HOST
#define EXAMPLE_LCD_H_RES 240

esp_err_t spi_bus_master_init(void)
{
    esp_err_t ret;
    spi_bus_config_t buscfg = {
        //spi总线使用的引脚
        .miso_io_num = PIN_NUM_MISO,
        .mosi_io_num = PIN_NUM_MOSI,
        .sclk_io_num = PIN_NUM_CLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        //在一次spi传输中最多传输80行像素
        .max_transfer_sz = EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t)
    };
    //使用dma的传输方式
    ret = spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);
    return ret;
}

SPI总线分配LCD IO设备句柄

esp_err_t esp_spi_lcd_init_io(esp_lcd_panel_io_handle_t *io_handle)
{   
    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = LCD_PIN_NUM_LCD_DC, // 数据/命令选择引脚
        .cs_gpio_num = LCD_PIN_NUM_LCD_CS, // 片选引脚
        .pclk_hz = LCD_LCD_PIXEL_CLOCK_HZ, // 像素时钟频率
        .lcd_cmd_bits = LCD_LCD_CMD_BITS, // 命令位数
        .lcd_param_bits = LCD_LCD_PARAM_BITS, // 参数位数
        .spi_mode = 0,//spi模式CPOL, CPHA
        .trans_queue_depth = 10, // 传输队列深度
    };
    // 将 LCD 连接到 SPI 总线
    return esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, io_handle);
}

安装LCD控制器驱动

配置参数调用 esp_lcd_new_panel_st7789() 来创建 LCD 面板的句柄,这个句柄后续会用于控制显示屏的显示内容。io_handle是上一步骤中获得的从spi总线分配的lcd io句柄。

esp_err_t esp_spi_lcd_panel_init(esp_lcd_panel_handle_t *panel_handle,const esp_lcd_panel_io_handle_t io_handle)
{
    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = LCD_PIN_NUM_RST,     // 复位引脚,设为-1表示不使用硬件复位
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,  // RGB颜色元素的顺序
        .bits_per_pixel = 16,    // 每像素16位色深,即RGB565格式
    };
    // 为 ST7789 创建 LCD 面板句柄,并指定 SPI IO 设备句柄
    return esp_lcd_new_panel_st7789(io_handle, &panel_config, panel_handle);
}

LCD面板初始化

    /* 复位LCD面板 */
    ESP_LOGI(TAG,"esp lcd reset");
    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));

    /* 初始化LCD面板 */
    ESP_LOGI(TAG,"esp lcd init");
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));

    /* 打开LCD显示 */
    ESP_LOGI(TAG,"esp lcd display on");
    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
    
    /* 反转LCD颜色 */
    ESP_LOGI(TAG,"esp lcd invert color");
    ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));

    /* 初始化LCD背光 */
    ESP_LOGI(TAG,"esp lcd backlight init");
    ESP_ERROR_CHECK(esp_lcd_backlight_init());

    /* 打开LCD背光 */
    ESP_LOGI(TAG,"esp lcd backlight on");
    esp_lcd_backlight_on();

lcd触摸

下载FT5x06控制器组件。

idf.py add-dependency "espressif/esp_lcd_touch_ft5x06^1.0.4"

由于使用的是idf5.3.1,有些api不适用,需要对FT5x06控制器组件代码进行修改。        

        managed_components中的代码,需要先把managed_components中的组件放到自己的components中才可以修改,否则你改了之后,一编译,就会恢复原来的样子,就白改了。所以我们先在spi_lcd_touch文件夹中新建一个文件,命名为components。

        然后把managed_components文件夹中的espressif__esp_lcd_touch_ft5x06文件夹剪切到components文件夹中。注意,是剪切,不是复制。

修改组件

FTx06创建i2c设备句柄

这里使用i2c_master的方式进行i2c通信。

//添加部分
const i2c_device_config_t i2c_dev_ft5x06_config = {
    .dev_addr_length = I2C_ADDR_BIT_LEN_7,
    .device_address = 0x38,
    .scl_speed_hz = 10000,
};
static i2c_master_dev_handle_t i2c_ft5x06_dev; 
//添加部分

//传入参数多了i2c_master_bus_handle_t 
esp_err_t esp_lcd_touch_new_i2c_ft5x06(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *out_touch,i2c_master_bus_handle_t bus_handle)
{
    esp_err_t ret = ESP_OK;

    assert(config != NULL);
    assert(out_touch != NULL);

    //添加部分
    ESP_LOGI(TAG,"add ft5x06 to  i2c bus");
    i2c_master_bus_add_device(bus_handle, &i2c_dev_ft5x06_config, &i2c_ft5x06_dev);
    //添加部分

修改触摸读写函数


/**
 * @brief 通过I2C写入数据到FT5x06触摸芯片
 * @param tp 触摸屏句柄
 * @param reg 寄存器地址
 * @param data 要写入的数据
 * @return esp_err_t 错误码
 */
static esp_err_t touch_ft5x06_i2c_write(esp_lcd_touch_handle_t tp, uint8_t reg, uint8_t data)
{
    assert(tp != NULL);

    // *INDENT-OFF*
    /* 写入数据 */
    uint8_t write_buf[2] = {reg, data};
    return i2c_master_transmit(i2c_ft5x06_dev, write_buf, sizeof(write_buf), -1);
    // *INDENT-ON*
}

/**
 * @brief 通过I2C从FT5x06触摸芯片读取数据
 * @param tp 触摸屏句柄
 * @param reg 寄存器地址
 * @param data 数据缓冲区指针
 * @param len 要读取的数据长度
 * @return esp_err_t 错误码
 */
static esp_err_t touch_ft5x06_i2c_read(esp_lcd_touch_handle_t tp, uint8_t reg, uint8_t *data, uint8_t len)
{
    assert(tp != NULL);
    assert(data != NULL);
    return i2c_master_transmit_receive(i2c_ft5x06_dev,&reg,1,data,len,-1);

}

使用示例

在官方esp_lcd_touch_ft5x06组件中有使用的示例。

i2c_master初始化

#define SCL_IO_PIN GPIO_NUM_1
#define SDA_IO_PIN GPIO_NUM_0
#define PORT_NUMBER -1  //-1 meansauto detect port number

/**
 * @brief 初始化I2C主机总线
 * @param bus_handle I2C总线句柄指针
 * @return esp_err_t 错误码
 */
esp_err_t i2c_master_init(i2c_master_bus_handle_t* bus_handle){ 
    /* I2C总线配置 */
    i2c_master_bus_config_t i2c_bus_config = {
        .clk_source = I2C_CLK_SRC_DEFAULT,      // 使用默认时钟源
        .i2c_port = PORT_NUMBER,                // I2C端口号
        .scl_io_num = SCL_IO_PIN,              // SCL引脚
        .sda_io_num = SDA_IO_PIN,              // SDA引脚
        .glitch_ignore_cnt = 7,                 // 忽略毛刺计数
        .flags.enable_internal_pullup = true,   // 使能内部上拉
    };
    
    /* 创建新的I2C主机总线 */
    ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, bus_handle));
    return ESP_OK;
}

触摸配置

    /* 配置触摸屏参数 */
    esp_lcd_touch_config_t tp_cfg = {
        .x_max = 320,                    /* X轴最大分辨率 */
        .y_max = 240,                    /* Y轴最大分辨率 */
        .rst_gpio_num = -1,              /* 复位引脚,不使用 */
        .int_gpio_num = -1,              /* 中断引脚,不使用 */
        .levels = {
            .reset = 0,                  /* 复位电平 */
            .interrupt = 0,              /* 中断电平 */
        },
        .flags = {
            .swap_xy = 0,                /* 是否交换XY轴 */
            .mirror_x = 0,               /* 是否镜像X轴 */
            .mirror_y = 0,               /* 是否镜像Y轴 */
        },
    };

    /* 创建触摸屏句柄并初始化FT5x06触摸芯片 */
    esp_lcd_touch_handle_t tp;
    //esp_lcd_panel_io_handle_t io_handle;
    esp_lcd_touch_new_i2c_ft5x06(io_handle, &tp_cfg, &tp,i2c_master_handle);

lvgl移植

选择组件

idf.py add-dependency "espressif/esp_lvgl_port^1.4.0"

参考官方示例:

/* 显示屏宽度 */
#define DISP_WIDTH 240
/* 显示屏高度 */
#define DISP_HEIGHT 320
/* LVGL显示设备句柄 */
static lv_disp_t * disp_handle;

/**
 * @brief 初始化LVGL端口
 * @param io_handle LCD面板IO句柄
 * @param panel_handle LCD面板句柄
 * @param _disp_handle LVGL显示设备句柄指针
 * @return esp_err_t 错误码
 */
esp_err_t u_esp_lvgl_port_init(esp_lcd_panel_io_handle_t io_handle,esp_lcd_panel_handle_t panel_handle,lv_disp_t **_disp_handle)
{
    /* 使用默认配置初始化LVGL */
    const lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG();
    esp_err_t err = lvgl_port_init(&lvgl_cfg);
    if (err != ESP_OK) {
        return err;
    }

    /* 配置LVGL显示设备参数 */
    const lvgl_port_display_cfg_t disp_cfg = {
        .io_handle = io_handle,              /* LCD面板IO句柄 */
        .panel_handle = panel_handle,        /* LCD面板句柄 */
        .buffer_size = 320*sizeof(uint16_t)*14*2, /* 显示缓冲区大小 */
        .double_buffer = true,               /* 使用双缓冲 */
        .hres = DISP_WIDTH,                 /* 水平分辨率 */
        .vres = DISP_HEIGHT,                /* 垂直分辨率 */
        .monochrome = false,                /* 非单色显示 */
        //.color_format = LV_COLOR_FORMAT_RGB565, /* RGB565颜色格式 */
        .rotation = {
            .swap_xy = false,               /* 不交换XY轴 */
            .mirror_x = false,              /* 不镜像X轴 */
            .mirror_y = false,              /* 不镜像Y轴 */
        },
        .flags = {
            .buff_dma = true,              /* 使用DMA传输显示缓冲 */
            //.swap_bytes = false,         /* 不交换字节序 */
        }
    };
    /* 添加显示设备并获取句柄 */
    disp_handle = lvgl_port_add_disp(&disp_cfg);
    *_disp_handle = disp_handle;
    return ESP_OK;
}

main函数中执行:

    lv_disp_t *disp_handle;
    ESP_ERROR_CHECK(u_esp_lvgl_port_init(io_handle,panel_handle,&disp_handle));

lvgl触摸输入配置

    /* 配置LVGL触摸设备参数 */
    const lvgl_port_touch_cfg_t touch_cfg = {
        .disp = disp_handle,  /* LVGL显示设备句柄 */
        .handle = tp,         /* 触摸屏句柄 */
    };
    /* 添加触摸设备并获取句柄 */
    lv_indev_t* touch_handle = lvgl_port_add_touch(&touch_cfg);

参考文章

Docs

espressif/esp_lvgl_port • v1.4.0• ESP Component Registry

LCD - ESP32 - — ESP-IDF 编程指南 release-v5.3 文档

### ESP32与TFT LCD使用教程 #### 初始化设置 为了使ESP32能够成功连接并控制TFT屏幕,初始化过程至关重要。当采用Arduino IDE作为开发平台时,需安装特定库文件来简化这一流程。对于1.8寸TFT屏幕而言,`TFT_eSPI`库是一个理想的选择[^1]。 ```cpp #include <TFT_eSPI.h> // Hardware-specific library TFT_eSPI tft = TFT_eSPI(); // Invoke custom library, pins defined in User_Setup.h ``` 这段代码展示了如何引入必要的硬件专用库以及创建一个名为`tft`的对象实例,该对象负责处理后续所有的显示操作。 #### 显示基本图形和文本 一旦完成了上述准备工作之后,就可以利用预定义函数轻松地向屏幕上绘制各种形状或是输出字符串了: ```cpp void setup() { tft.init(); tft.fillScreen(TFT_BLACK); tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.setTextSize(2); tft.setCursor(0, 0); tft.println("Hello World!"); } void loop() {} ``` 此部分程序实现了屏幕清空、颜色设定、字体大小调整等功能,并最终打印了一条消息到指定位置上。 #### 高级应用案例——生成二维码 除了基础功能外,在某些应用场景下可能还需要更复杂的数据可视化能力。例如,可以借助第三方插件实现动态生成QR Code图像并在TFT设备上呈现出来。这里给出一段简化的示例代码片段用于说明这个概念[^2]: ```cpp // 假设已存在一个有效的WiFi网络连接 String ssid = "yourSSID"; String password = "yourPassword"; QRCODE_t qrcode; qrcode_init(&qrcode, QRECLEVEL_L, 4); char qrData[100]; sprintf(qrData,"WIFI:S:%s;P:%s;;",ssid.c_str(),password.c_str()); tft.setRotation(1); draw_qrcode(tft.getViewport().x, tft.getViewport().y, &qrcode, (uint8_t*)qrData,strlen(qrData)); ``` 请注意实际编码过程中还需考虑更多细节问题,比如内存管理等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值