ESP32idf使用1.83寸NV3030屏幕

使用的是中景园的屏幕1.83寸NV3030驱动芯片,实测可以跑满80M,但是根据数据手册算应该不支持的,但是实测没问题

数据手册里,写的周期最快是15.4ns一个bit,1/0.0000000154=64935064,应该是64M,不知道是不是我算错了,但是他确实能跑80M

中景园家的屏幕一般分两款,插接和焊接的

插接是不受dc脚控制,数据和命令是通过在每个字节前面加1个bit来区分数据还是命令

焊接是通过单独一个引脚拉高拉低来区分

本文使用的是焊接款

使用api查看推荐去液晶显示器 - ESP32-C3 - — ESP-IDF 编程指南 v5.2.2 文档 (espressif.com)查看

本文使用的是带lvgl的,所以没有任何显示字符或是数据的库,最好移植lvgl使用,后续可能会出一篇移植lvgl的文章

并且本文是参考了【2024最新版 ESP32教程(基于ESP-IDF)】ESP32入门级开发课程 更新中 中文字幕_哔哩哔哩_bilibili

的代码进行编写 ,视频使用的是st7789T3,我进行修改成nv3030B

在CMakeLists.txt添加(本代码还使用了lvgl,没用可以删掉)

file (GLOB_RECURSE SOURCES  ./*.c)

idf_component_register(

    SRCS ${SOURCES}

    INCLUDE_DIRS    "."

    REQUIRES  esp_driver_gpio freertos main  esp_timer  esp_lcd lvgl

)

文件lcd_library.c

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_commands.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_err.h"
#include "esp_log.h"
#include "lcd_library.h"
#include "lcd.h"

#define LCD_SPI_HOST    SPI2_HOST

static const char* TAG = "NV3030B";

//lcd操作句柄
static esp_lcd_panel_io_handle_t lcd_io_handle = NULL;

//刷新完成回调函数
static lcd_flush_done_cb    s_flush_done_cb = NULL;

//背光GPIO
static gpio_num_t   s_bl_gpio = -1;

static bool notify_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
    if(s_flush_done_cb)
        s_flush_done_cb(user_ctx);
    return false;
}


/** lcd初始化
 * @param st7789_cfg_t  接口参数
 * @return 成功或失败
*/
esp_err_t driver_hw_init(cfg_t* cfg)
{
    //初始化SPI
    spi_bus_config_t buscfg = {
        .sclk_io_num = cfg->clk,        //SCLK引脚
        .mosi_io_num = cfg->mosi,       //MOSI引脚
        .miso_io_num = -1,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .flags = SPICOMMON_BUSFLAG_MASTER , //SPI主模式
        .max_transfer_sz = cfg->width * 40 * sizeof(uint16_t),  //DMA单次传输最大字节,最大32768
    };
    ESP_ERROR_CHECK(spi_bus_initialize(LCD_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));

    s_flush_done_cb = cfg->done_cb; //设置刷新完成回调函数

    s_bl_gpio = cfg->bl;    //设置背光GPIO
    //初始化GPIO(BL)
    gpio_config_t bl_gpio_cfg = 
    {
        .pull_up_en = GPIO_PULLUP_DISABLE,          //禁止上拉
        .pull_down_en = GPIO_PULLDOWN_DISABLE,      //禁止下拉
        .mode = GPIO_MODE_OUTPUT,                   //输出模式
        .intr_type = GPIO_INTR_DISABLE,             //禁止中断
        .pin_bit_mask = (1<<cfg->bl)                //GPIO脚
    };
    gpio_config(&bl_gpio_cfg);


    //初始化复位脚
    if(cfg->rst > 0)
    {
        gpio_config_t rst_gpio_cfg = 
        {
            .pull_up_en = GPIO_PULLUP_DISABLE,          //禁止上拉
            .pull_down_en = GPIO_PULLDOWN_DISABLE,      //禁止下拉
            .mode = GPIO_MODE_OUTPUT,                   //输出模式
            .intr_type = GPIO_INTR_DISABLE,             //禁止中断
            .pin_bit_mask = (1<<cfg->rst)                //GPIO脚
        };
        gpio_config(&rst_gpio_cfg);
    }

    //创建基于spi的lcd操作句柄
    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = cfg->dc,         //DC引脚
        .cs_gpio_num = cfg->cs,         //CS引脚
        .pclk_hz = cfg->spi_fre,        //SPI时钟频率
        .lcd_cmd_bits = 8,              //命令长度
        .lcd_param_bits = 8,            //参数长度
        .spi_mode = 0,                  //使用SPI0模式
        .trans_queue_depth = 10,        //表示可以缓存的spi传输事务队列深度
        .on_color_trans_done = notify_flush_ready,   //刷新完成回调函数
        .user_ctx = cfg->cb_param,                                    //回调函数参数
        .flags = {    // 以下为 SPI 时序的相关参数,需根据 LCD 驱动 IC 的数据手册以及硬件的配置确定
        .sio_mode = 0,    // 通过一根数据线(MOSI)读写数据,0: Interface I 型,1: Interface II 型
        },
    };
    // Attach the LCD to the SPI bus
    ESP_LOGI(TAG,"create esp_lcd_new_panel");
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI_HOST, &io_config, &lcd_io_handle));
    
    //硬件复位
    if(cfg->rst > 0)
    {
        gpio_set_level(cfg->rst,0);
        vTaskDelay(pdMS_TO_TICKS(20));
        gpio_set_level(cfg->rst,1);
        vTaskDelay(pdMS_TO_TICKS(20));
    }
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xfd,(uint8_t[]){0x06,0x08},2); 
    esp_lcd_panel_io_tx_param(lcd_io_handle,0x61,(uint8_t[]){0x07,0x04},2); 
     esp_lcd_panel_io_tx_param(lcd_io_handle,0x62,(uint8_t[]){0x00,0x44,0x45},3); 
    esp_lcd_panel_io_tx_param(lcd_io_handle,0x63,(uint8_t[]){0x41,0x07,0x12,0x12},4); 
    esp_lcd_panel_io_tx_param(lcd_io_handle,0x64,(uint8_t[]){0x37},1); 
	//VSP
    esp_lcd_panel_io_tx_param(lcd_io_handle,0x65,(uint8_t[]){0x09,0x10,0x21},3); 
     esp_lcd_panel_io_tx_param(lcd_io_handle,0x66,(uint8_t[]){0x09,0x10,0x21},3);    
    esp_lcd_panel_io_tx_param(lcd_io_handle,0x67,(uint8_t[]){0x20,0x40},2);  
    esp_lcd_panel_io_tx_param(lcd_io_handle,0x68,(uint8_t[]){0x90,0x4c,0x7C,0x66},4);  
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xb1,(uint8_t[]){0x0F,0x08,0x01},3);  
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xB4,(uint8_t[]){0x01},1); 
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xB5,(uint8_t[]){0x02,0x02,0x0a,0x14},4); 
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xB6,(uint8_t[]){0x04,0x01,0x9f,0x00,0x02},5);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xdf,(uint8_t[]){0x11},1);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xE2,(uint8_t[]){0x13,0x00,0x00,0x30,0x33,0x3f},6);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xE5,(uint8_t[]){0x3f,0x33,0x30,0x00,0x00,0x13},6);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xE1,(uint8_t[]){0x00,0x57},2);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xE4,(uint8_t[]){0x58,0x00},2);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xE0,(uint8_t[]){0x01,0x03,0x0d,0x0e,0x0e,0x0c,0x15,0x19},8);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xE3,(uint8_t[]){0x1a,0x16,0x0C,0x0f,0x0e,0x0d,0x02,0x01},8);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xE6,(uint8_t[]){0x00,0xff},2);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xE7,(uint8_t[]){0x01,0x04,0x03,0x03,0x00,0x12},6);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xE8,(uint8_t[]){0x00,0x70,0x00},3);
     esp_lcd_panel_io_tx_param(lcd_io_handle,0xEC,(uint8_t[]){0x52},1);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xF1,(uint8_t[]){0x01,0x01,0x02},3);

    esp_lcd_panel_io_tx_param(lcd_io_handle,0xF6,(uint8_t[]){0x09,0x10,0x00,0x00},4);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0xfd,(uint8_t[]){0xfa,0xfc},2);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0x3a,(uint8_t[]){0x05},1);
    esp_lcd_panel_io_tx_param(lcd_io_handle,0x35,(uint8_t[]){0x00},1);


	if(USE_HORIZONTAL==0) esp_lcd_panel_io_tx_param(lcd_io_handle,0x36,(uint8_t[]){0x08},1);
	else if(USE_HORIZONTAL==1)esp_lcd_panel_io_tx_param(lcd_io_handle,0x36,(uint8_t[]){0xC8},1);
	else if(USE_HORIZONTAL==2)esp_lcd_panel_io_tx_param(lcd_io_handle,0x36,(uint8_t[]){0x78},1);
	else esp_lcd_panel_io_tx_param(lcd_io_handle,0x36,(uint8_t[]){0xA8},1);


    esp_lcd_panel_io_tx_param(lcd_io_handle,0x21,NULL,0);
	//LCD_WR_REG(0x21); 
   esp_lcd_panel_io_tx_param(lcd_io_handle,0x11,NULL,0); 
        vTaskDelay(pdMS_TO_TICKS(200));
    esp_lcd_panel_io_tx_param(lcd_io_handle,0x29,NULL,0); 
        vTaskDelay(pdMS_TO_TICKS(10));       
     lcd_backlight(1);//打开背光

    return ESP_OK;
}

/** lcd写入显示数据
 * @param x1,x2,y1,y2:显示区域
 * @return 无
*/
void flush(int x1,int x2,int y1,int y2,void *data)
{
        // define an area of frame memory where MCU can access
    if(x2 <= x1 || y2 <= y1)
    {
        if(s_flush_done_cb)
            s_flush_done_cb(NULL);
        return;
    }
    esp_lcd_panel_io_tx_param(lcd_io_handle, LCD_CMD_CASET, (uint8_t[]) {
        (x1 >> 8) & 0xFF,
        x1 & 0xFF,
        ((x2 - 1) >> 8) & 0xFF,
        (x2 - 1) & 0xFF,
    }, 4);
    esp_lcd_panel_io_tx_param(lcd_io_handle, LCD_CMD_RASET, (uint8_t[]) {
        (y1 >> 8) & 0xFF,
        y1 & 0xFF,
        ((y2 - 1) >> 8) & 0xFF,
        (y2 - 1) & 0xFF,
    }, 4);
    // transfer frame buffer
    size_t len = (x2 - x1) * (y2 - y1) * 2;
    esp_lcd_panel_io_tx_color(lcd_io_handle, LCD_CMD_RAMWR, data, len);
    return ;
}

/** 控制背光
 * @param enable 是否使能背光
 * @return 无
*/
void lcd_backlight(bool enable)
{
    if(enable)
    {
        gpio_set_level(s_bl_gpio,1);
    }
    else
    {
        gpio_set_level(s_bl_gpio,0);
    }
}

 lcd_library.h

#ifndef _LCD_LIBRARY_H_
#define _LCD_LIBRARY_H_
#include "driver/gpio.h"
#include "esp_err.h"
#define USE_HORIZONTAL 2 
#if USE_HORIZONTAL==0||USE_HORIZONTAL==1
#define LCD_W 240
#define LCD_H 280

#else
#define LCD_W 280
#define LCD_H 240
#endif

typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;

typedef void(*lcd_flush_done_cb)(void* param);

typedef struct
{
    gpio_num_t  mosi;       //数据
    gpio_num_t  clk;        //时钟
    gpio_num_t  cs;         //片选
    gpio_num_t  dc;         //命令
    gpio_num_t  rst;        //复位
    gpio_num_t  bl;         //背光
    uint32_t    spi_fre;    //spi总线速率
    uint16_t    width;      //宽
    uint16_t    height;     //长
    uint8_t     spin;       //选择方向(0不旋转,1顺时针旋转90, 2旋转180,3顺时针旋转270)
    lcd_flush_done_cb   done_cb;    //数据传输完成回调函数
    void*       cb_param;   //回调函数参数
}cfg_t;


/** 初始化
 * @param cfg_t  接口参数
 * @return 成功或失败
*/
esp_err_t driver_hw_init(cfg_t* cfg);

/**写入显示数据
 * @param x1,x2,y1,y2:显示区域
 * @return 无
*/
void flush(int x1,int x2,int y1,int y2,void *data);

/** 控制背光
 * @param enable 是否使能背光
 * @return 无
*/
void lcd_backlight(bool enable);
void lcd_init(void);
#endif

使用方法

 void lcd_init(void)
{
    cfg_t config;
    config.mosi = GPIO_NUM_7;
    config.clk = GPIO_NUM_6;
    config.cs = GPIO_NUM_10;
    config.dc = GPIO_NUM_8;
    config.rst = GPIO_NUM_9;
    config.bl = GPIO_NUM_5;
    //config.spi_fre = 40*1000*1000;       //SPI时钟频率
    config.spi_fre = 80*1000*1000;       //SPI时钟频率
    config.width = LCD_W;            //屏宽
    config.height = LCD_H;          //屏高
    config.spin = 1;                     //顺时针旋转90度
     config.done_cb = lv_port_flush_ready;    //数据写入完成回调函数
     config.cb_param = &disp_drv;         //回调函数参数

    driver_hw_init(&config);
}
void app_main(void)
{
lcd_init();
while(1)
{
vTaskDelay(pdMS_TO_TICKS(10));
flush(int x1,int x2,int y1,int y2,void *data);//在这里填充你的图片或者数据,推荐加lvgl来进行使用
 
}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值