esp-idf(lcd屏幕篇)


ESP 芯片可以产生市面上常见 LCD 所需的各种时序,例如 SPI LCD、I2C LCD、并行 LCD(Intel 8080)、RGB/SRGB LCD、MIPI DSI LCD 等。esp_lcd esp_lcd 提供了一个抽象的驱动框架以统一的方式支持它们。
本次以立创实战派开发板为例,屏幕为SPI接口,使用ST7789驱动

LCD 通常由两个主要平面组成:

控制平面 :此平面允许我们读取和写入 LCD 设备控制器的内部寄存器。主机通常使用此平面执行诸如初始化 LCD 电源和执行伽马校准等任务。

数据平面 :数据平面负责将像素数据传输到 LCD 设备

1.头文件

#include "hal/lcd_types.h"

#include "esp_lcd_types.h"

#include "esp_lcd_panel_io.h"

#include "esp_lcd_panel_ops.h"

#include "esp_lcd_panel_vendor.h"

2.常用初始化案例

首先是打开屏幕背光,在这里我们可以使用LEDC功能输出pwm控制屏幕背光,并设置背光亮度百分比

//初始化LEDC 控制屏幕背光
esp_err_t bsp_display_brightness_init(void)
{
     //准备并应用led PWM定时器配置
     ledc_timer_config_t ledc_timer = {
        .speed_mode       = LEDC_LOW_SPEED_MODE, 	//速度模式(值必须为 LEDC_LOW_SPEED_MODE)
        .duty_resolution  = LEDC_TIMER_10_BIT,		//PWM 占空比分辨率
        .timer_num        = 1,			        	//定时器索引
        .freq_hz          = 5000, 	            	// PWM 信号频率(Hz)
        .clk_cfg          = LEDC_AUTO_CLK			//时钟源
    };
    ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));

    // 准备并应用LEDC PWM通道配置
    ledc_channel_config_t ledc_channel = {
        .speed_mode     = LEDC_LOW_SPEED_MODE,	//高速模式(仅在esp32上存在)或低速模式
        .channel        = LCD_LEDC_CH,			//LEDC通道
        .timer_sel      = 1,			//选择通道的定时器源
        .intr_type      = LEDC_INTR_DISABLE,	//配置中断
        .gpio_num       = BSP_LCD_BACKLIGHT,  		//LEDC输出的GPIO
        .duty           = 0, 					// LEDC通道占空比
        .hpoint         = 0,						//LEDC通道hpoint值
      	.flags.output_invert = 1				//启用(1)或禁用(0)gpio输出反相
    };
    ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));

    return ESP_OK;
}


//设置屏幕背光亮度  参数为百分比
esp_err_t bsp_display_brightness_set(int brightness_percent)
{
    if (brightness_percent > 100) {
        brightness_percent = 100;
    } else if (brightness_percent < 0) {
        brightness_percent = 0;
    }

    ESP_LOGI(TAG, "Setting LCD backlight: %d%%", brightness_percent);

    //将百分比转换为10位PWM占空比值(LEDC分辨率设为10位,所以100%对应1023)
    uint32_t duty_cycle = (1023 * brightness_percent) / 100;
    ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH, duty_cycle));
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH));

    return ESP_OK;
}

//背光熄灭
esp_err_t bsp_display_backlight_off(void)
{
    return bsp_display_brightness_set(0);
}

//背光最亮
esp_err_t bsp_display_backlight_on(void)
{
    return bsp_display_brightness_set(100);
}

接下来就是初始化屏幕
首先初始化控制时序(SPI),接着LCD控制器的IO,LCD面板初始化(ST7789驱动芯片),最后配置面板和错误处理

//定义lcd面板
static esp_lcd_panel_handle_t panel_handle = NULL;

esp_lcd_panel_io_handle_t io_handle = NULL; 

esp_err_t bsp_display_new(void)
{
    esp_err_t ret = ESP_OK;
    // 背光初始化
    ESP_RETURN_ON_ERROR(bsp_display_brightness_init(), TAG, "Brightness init failed");
    // 初始化SPI总线
    ESP_LOGD(TAG, "Initialize SPI bus");
    const spi_bus_config_t buscfg = {
        .sclk_io_num = BSP_LCD_SPI_CLK,			//clk
        .mosi_io_num = BSP_LCD_SPI_MOSI,		//mosi
        .miso_io_num = GPIO_NUM_NC,				//miso,这里指向空,没使用
        .quadwp_io_num = GPIO_NUM_NC,			
        .quadhd_io_num = GPIO_NUM_NC,
        .max_transfer_sz = BSP_LCD_H_RES * BSP_LCD_V_RES * sizeof(uint16_t),	//最大传输大小(以字节为单位)
    };
    ESP_RETURN_ON_ERROR(spi_bus_initialize(BSP_LCD_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed");
    // 液晶屏控制IO初始化
    ESP_LOGD(TAG, "Install panel IO");
    const esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = BSP_LCD_DC,			//设置 DC 信号线的 gpio 编号(某些 LCD 称之为 RS 线)
        .cs_gpio_num = BSP_LCD_SPI_CS,		//设置 CS 信号线的 gpio 编号
        .pclk_hz = BSP_LCD_PIXEL_CLOCK_HZ,	//设置像素时钟的频率(以 Hz 为单位)
        .lcd_cmd_bits = LCD_CMD_BITS,		//设置 LCD 控制器芯片识别的命令的位宽。这是芯片特定的
        .lcd_param_bits = LCD_PARAM_BITS,	//设置 LCD 控制器芯片识别参数的位宽。这是芯片特定的
        .spi_mode = 2,						//设置 SPI 模式
        .trans_queue_depth = 10,			//设置 SPI 事务队列的深度
    };
    //初始化LCD控制器的SPI接口
    ESP_GOTO_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)BSP_LCD_SPI_NUM, &io_config, &io_handle), err, TAG, "New panel IO failed");
    // 初始化液晶屏驱动芯片ST7789
    ESP_LOGD(TAG, "Install LCD driver");
    const esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = BSP_LCD_RST,					//复位引脚
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,		//RGB 子像素排列顺序
        .bits_per_pixel = BSP_LCD_BITS_PER_PIXEL,		//每个像素的位数(通常为 16,即 RGB565)
    };
    ESP_GOTO_ON_ERROR(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle), err, TAG, "New panel failed");
    //配置LCD面板
    esp_lcd_panel_reset(panel_handle);  // 液晶屏复位
    lcd_cs(0);  // 拉低CS引脚
    esp_lcd_panel_init(panel_handle);  // 初始化配置寄存器
    esp_lcd_panel_invert_color(panel_handle, true); // 颜色反转
    esp_lcd_panel_swap_xy(panel_handle, true);  // 显示翻转 
    esp_lcd_panel_mirror(panel_handle, true, false); // 镜像

    return ret;
//错误处理
err:
    if (panel_handle) {
        esp_lcd_panel_del(panel_handle);	//释放ST7789驱动芯片占用的资源
    }
    if (io_handle) {
        esp_lcd_panel_io_del(io_handle);	//关闭SPI通信接口,释放DMA通道和GPIO引脚
    }
    spi_bus_free(BSP_LCD_SPI_NUM);			//解除SPI总线占用
    return ret;
}

3.案例

结合上述初始化,下面显示函数直接照搬即可

// LCD显示初始化
esp_err_t bsp_lcd_init(void)
{
    esp_err_t ret = ESP_OK;

    
    ret = bsp_display_new(); // 液晶屏驱动初始化
    lcd_set_color(0x0000); // 设置整屏背景黑色
    ret = esp_lcd_panel_disp_on_off(panel_handle, true); // 打开液晶屏显示
    ret = bsp_display_backlight_on(); // 打开背光显示

    return  ret;
}



// 显示图片
void lcd_draw_pictrue(int x_start, int y_start, int x_end, int y_end, const unsigned char *gImage)
{
    // 分配内存 分配了需要的字节大小 且指定在外部SPIRAM中分配
    size_t pixels_byte_size = (x_end - x_start)*(y_end - y_start) * 2;
    uint16_t *pixels = (uint16_t *)heap_caps_malloc(pixels_byte_size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
    if (NULL == pixels)
    {
        ESP_LOGE(TAG, "Memory for bitmap is not enough");
        return;
    }
    memcpy(pixels, gImage, pixels_byte_size);  // 把图片数据拷贝到内存
    esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_end, y_end, (uint16_t *)pixels); // 显示整张图片数据
    heap_caps_free(pixels);  // 释放内存
}

// 设置液晶屏颜色
void lcd_set_color(uint16_t color)
{
    // 分配内存 这里分配了液晶屏一行数据需要的大小
    uint16_t *buffer = (uint16_t *)heap_caps_malloc(BSP_LCD_H_RES * sizeof(uint16_t), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
    
    if (NULL == buffer)
    {
        ESP_LOGE(TAG, "Memory for bitmap is not enough");
    }
    else
    {
        for (size_t i = 0; i < BSP_LCD_H_RES; i++) // 给缓存中放入颜色数据
        {
            buffer[i] = color;
        }
        for (int y = 0; y < 240; y++) // 显示整屏颜色
        {
            esp_lcd_panel_draw_bitmap(panel_handle, 0, y, 320, y+1, buffer);
        }
        free(buffer); // 释放内存
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值