Bootstrap

stm32f103zet6部署lvgl到3.5寸 480x320 spi屏幕 芯片为ILI9488 SKU:MSP3520

lvgl又叫littlevgl

lvgl部署在spi屏幕

要结合正点原子lvgl视频第五讲开始配合着看

完整工程:https://download.csdn.net/download/2301_80317247/90422906

这块屏幕的sd接口是可以外接的

接下来根据教程我们为屏幕部署lvgl

以正点原子lvgl初始工程为基础,添加替换成自己的lcd文件驱动

自己的LCD驱动文件:

还有一些定义需要适配比如#define u8 unsigned char...

24Cxx是触摸校准时要用来记录是否之前校准过和初次校准保存校准标志和校准数据

IIC是24c02的驱动底层

LCD是spi上层的屏幕驱动画点画方块等

SPI是屏幕驱动底层spi结构

TOUCH是触摸屏幕的底层和接口函数

GUI是LCD高级函数,就是把LCD底层画点画块改成写字画图等高级函数接口、包含字体文件

然后你要确定你的lcd相关文件是否与正点原子的重名然后是否缺少什么定义,但又不能乱定义不然会出现(200): error: #29: expected an expression error: #40: expected an identifier报错,怎么解决我博客里也有

然后删掉原来正点原子的lcd驱动函数

再把里面的路径改的更详细点因为煞笔正点偏要把路径写他么复杂跟正常人的不一样

eg:
#include "./BSP/LED/led.h"    正常应该是     #include "led.h"

就因为它的包含路径偷懒

他不具体到最简路径所以才那么复杂"./BSP/LED/led.h“要加路径,但正常的是到最简路径,所以你添加后直接编译就会报很多错误,类似于你没有该文件等等,所以我们具体到最简路径就可以避免老是去添加那么多路径:

然后就是根据正点原子的视频更改属于你自己的LCD配置

从第五讲开始因为第四讲是添加文件夹导入lvgl文件啥的,我们用的是正点原子lvgl初始工程已经移植好了只需要改LCD底层就好

我们所有的操作都是仿照正点原子来修改

首先你要改到你的LCD屏幕在这个工程里能正常写字,说明你的LCD能驱动了才能进行lvgl改造

不然你LCD都驱动不了你咋知道报错是你的LCD驱动问题还是lvgl移植问题

因为我对自己比较自信所以直接进行移植没有验证LCD驱动

首先是代码hal与标准库的转换,因为我的LCD驱动是厂家给的标准库正点的Lvgl是hal的所以要先转换,我前几个是自己手把手转换的,后来太累我直接去报错的地方看到有标准库代码就把他复制到ai转成hal

文心一言再不济这点小事哈是没错的

然后就是改动porting也就是lvgl外放接口函数配置

重点就这两个

把他改了:

首先是lv_port_disp_template.c

有外部sram就选择外部没有就选内部,你选外部看完我这篇文章还要继续看正点的lvgl内存配置,因为mymalloc.c外部内部使用不一样

记得引用你的gui  lcd头文件不然用不了借口函数

然后就是宽度高度,看你选择横还是竖屏,这个在屏幕初始化可以调整后面再讲

接下来重点改装这两

disp初始化修改为:

这里的横竖屏如果你的宽高是数字而不是结构体那么就只能横就是横竖就是竖,因为角度转动宽高都会不同

接下来修改disp_flush

配置lcd_draw_fast_rgb_color(area->x1,area->y1,area->x2,area->y2,(uint16_t*)color_p);
画指定区域roi图像的函数

借助的原理是你set  windows后从初始点开始(左上点)一直写rgb565他会自增并遇到windows边界自动换行

LCD_SetWindows(0,0,480-1,320-1);//恢复显示窗口为全屏    

我这里嫌他麻烦直接自己写的480  320 这样有个坏处你同屏幕不同大小或旋转后就用不了了

这个函数替代我推荐你去看你自己的高级驱动函数再根据lvgl给的例子去改,因为我之前按名字改真是笨,你不同板子屏幕驱动函数怎么可能一样

后来我去看我自己板子的驱动函数发现lvgl的原理是得到要添加的组建大小然后设置一个数组把这个组件的样子撞到这个数组里面返回一个数组地址,那你要显示就是在特定地点显示一张图片数组这跟我显示QQ图片一样,所以我直接套用改装

void Gui_Drawbmp16(u16 x,u16 y,const unsigned char *p) //显示40*40 QQ图片
{
  	int i; 
	unsigned char picH,picL; 
	LCD_SetWindows(x,y,x+40-1,y+40-1);//窗口设置
    for(i=0;i<40*40;i++)
	{	
	 	picL=*(p+i*2);	//数据低位在前
		picH=*(p+i*2+1);				
		Lcd_WriteData_16Bit(picH<<8|picL);  						
	}	
	LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复显示窗口为全屏	

}

最后:

void lcd_draw_fast_rgb_color(int16_t sx, int16_t sy,int16_t ex, int16_t ey, uint16_t *color)
{
	int i; 
	unsigned char picH,picL;
    uint16_t w = ex-sx+1;
    uint16_t h = ey-sy+1;
	LCD_SetWindows(sx,sy,ex,ey);//窗口设置
    for(i=0;i<w*h;i++)
	{	
//	 	picL=*(color+i*2);	//数据低位在前
//		picH=*(color+i*2+1);				
		Lcd_WriteData_16Bit(*(color+i));  						
	}	
	LCD_SetWindows(0,0,480-1,320-1);//恢复显示窗口为全屏	
}

完整:

/**
 * @file lv_port_disp_templ.c
 *
 */

 /*Copy this file as "lv_port_disp.c" and set this value to "1" to enable content*/
#if 1

/*********************
 *      INCLUDES
 *********************/
#include "lv_port_disp_template.h"
#include "../../lvgl.h"
/* 导入lcd驱动头文件 */
#include "./BSP/LCD/lcd.h"

/*********************
 *      DEFINES
 *********************/
#define USE_SRAM        0       /* 使用外部sram为1,否则为0 */
#ifdef USE_SRAM
#include "./MALLOC/malloc.h"
#endif

#define MY_DISP_HOR_RES (480)   /* 屏幕宽度 */
#define MY_DISP_VER_RES (320)   /* 屏幕高度 */

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
/* 显示设备初始化函数 */
static void disp_init(void);

/* 显示设备刷新函数 */
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
/* GPU 填充函数(使用GPU时,需要实现) */
//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
//        const lv_area_t * fill_area, lv_color_t color);

/**********************
 *  STATIC VARIABLES
 **********************/

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/
/**
 * @brief       LCD加速绘制函数
 * @param       (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex - sx + 1) * (ey - sy + 1)
 * @param       color:要填充的颜色
 * @retval      无
 */
void lcd_draw_fast_rgb_color(int16_t sx, int16_t sy,int16_t ex, int16_t ey, uint16_t *color)
{
	int i; 
	unsigned char picH,picL;
    uint16_t w = ex-sx+1;
    uint16_t h = ey-sy+1;
	LCD_SetWindows(sx,sy,ex,ey);//窗口设置
    for(i=0;i<w*h;i++)
	{	
//	 	picL=*(color+i*2);	//数据低位在前
//		picH=*(color+i*2+1);				
		Lcd_WriteData_16Bit(*(color+i));  						
	}	
	LCD_SetWindows(0,0,480-1,320-1);//恢复显示窗口为全屏	
//	uint16_t i, j;
//    uint16_t xlen = 0;
//    xlen = ex - sx + 1;

//    for (i = sy; i <= ey; i++)
//    {
//        LCD_SetCursor(sx, i);      /* 设置光标位置 */
//        LCD_WriteRAM_Prepare();    /* 开始写入GRAM */

//        for (j = 0; j < xlen; j++)
//        {
//            Lcd_WriteData_16Bit(color[j]);   /* 显示颜色 */
//        }
//    }
//    uint16_t w = ex-sx+1;
//    uint16_t h = ey-sy+1;

//    LCD_SetWindows(sx, sy, w, h);
//    uint32_t draw_size = w * h;
//    LCD_WriteRAM_Prepare();

//    for(uint32_t i = 0; i < draw_size; i++)
//    {
//        Lcd_WriteData_16Bit(color[i]);
//    }
}

/**
 * @brief       初始化并注册显示设备
 * @param       无
 * @retval      无
 */
void lv_port_disp_init(void)
{
    /*-------------------------
     * 初始化显示设备
     * -----------------------*/
    disp_init();

    /*-----------------------------
     * 创建一个绘图缓冲区
     *----------------------------*/

    /**
     * LVGL 需要一个缓冲区用来绘制小部件
     * 随后,这个缓冲区的内容会通过显示设备的 `flush_cb`(显示设备刷新函数) 复制到显示设备上
     * 这个缓冲区的大小需要大于显示设备一行的大小
     *
     * 这里有3中缓冲配置:
     * 1. 单缓冲区:
     *      LVGL 会将显示设备的内容绘制到这里,并将他写入显示设备。
     *
     * 2. 双缓冲区:
     *      LVGL 会将显示设备的内容绘制到其中一个缓冲区,并将他写入显示设备。
     *      需要使用 DMA 将要显示在显示设备的内容写入缓冲区。
     *      当数据从第一个缓冲区发送时,它将使 LVGL 能够将屏幕的下一部分绘制到另一个缓冲区。
     *      这样使得渲染和刷新可以并行执行。
     *
     * 3. 全尺寸双缓冲区
     *      设置两个屏幕大小的全尺寸缓冲区,并且设置 disp_drv.full_refresh = 1。
     *      这样,LVGL将始终以 'flush_cb' 的形式提供整个渲染屏幕,您只需更改帧缓冲区的地址。
     */

    /* 单缓冲区示例) */
    static lv_disp_draw_buf_t draw_buf_dsc_1;
#if USE_SRAM
    static lv_color_t buf_1 = mymalloc(SRAMEX, MY_DISP_HOR_RES * MY_DISP_VER_RES);              /* 设置缓冲区的大小为屏幕的全尺寸大小 */
    lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * MY_DISP_VER_RES);     /* 初始化显示缓冲区 */
#else
    static lv_color_t buf_1[MY_DISP_HOR_RES * 10];                                              /* 设置缓冲区的大小为 10 行屏幕的大小 */
    lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10);                  /* 初始化显示缓冲区 */
#endif

    /* 双缓冲区示例) */
//    static lv_disp_draw_buf_t draw_buf_dsc_2;
//    static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10];                                            /* 设置缓冲区的大小为 10 行屏幕的大小 */
//    static lv_color_t buf_2_2[MY_DISP_HOR_RES * 10];                                            /* 设置另一个缓冲区的大小为 10 行屏幕的大小 */
//    lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10);             /* 初始化显示缓冲区 */

    /* 全尺寸双缓冲区示例) 并且在下面设置 disp_drv.full_refresh = 1 */
//    static lv_disp_draw_buf_t draw_buf_dsc_3;
//    static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES];                               /* 设置一个全尺寸的缓冲区 */
//    static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES];                               /* 设置另一个全尺寸的缓冲区 */
//    lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2, MY_DISP_HOR_RES * MY_DISP_VER_RES);/* 初始化显示缓冲区 */

    /*-----------------------------------
     * 在 LVGL 中注册显示设备
     *----------------------------------*/

    static lv_disp_drv_t disp_drv;                  /* 显示设备的描述符 */
    lv_disp_drv_init(&disp_drv);                    /* 初始化为默认值 */

    /* 建立访问显示设备的函数  */

    /* 设置显示设备的分辨率
     * 这里为了适配正点原子的多款屏幕,采用了动态获取的方式,
     * 在实际项目中,通常所使用的屏幕大小是固定的,因此可以直接设置为屏幕的大小 */
    disp_drv.hor_res = 480;
    disp_drv.ver_res = 320;

    /* 用来将缓冲区的内容复制到显示设备 */
    disp_drv.flush_cb = disp_flush;

    /* 设置显示缓冲区 */
    disp_drv.draw_buf = &draw_buf_dsc_1;

    /* 全尺寸双缓冲区示例)*/
    //disp_drv.full_refresh = 1

    /* 如果您有GPU,请使用颜色填充内存阵列
     * 注意,你可以在 lv_conf.h 中使能 LVGL 内置支持的 GPUs
     * 但如果你有不同的 GPU,那么可以使用这个回调函数。 */
    //disp_drv.gpu_fill_cb = gpu_fill;

    /* 注册显示设备 */
    lv_disp_drv_register(&disp_drv);
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

/**
 * @brief       初始化显示设备和必要的外围设备
 * @param       无
 * @retval      无
 */
static void disp_init(void)
{
    /*You code here*/
    LCD_Init();         /* 初始化LCD */
    LCD_direction(1); /* 设置横屏 */
}

/**
 * @brief       将内部缓冲区的内容刷新到显示屏上的特定区域
 *   @note      可以使用 DMA 或者任何硬件在后台加速执行这个操作
 *              但是,需要在刷新完成后调用函数 'lv_disp_flush_ready()'
 *
 * @param       disp_drv    : 显示设备
 *   @arg       area        : 要刷新的区域,包含了填充矩形的对角坐标
 *   @arg       color_p     : 颜色数组
 *
 * @retval      无
 */
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    /* LVGL 官方给出的一个打点刷新屏幕的例子,但这个效率是最低效的 */

//    int32_t x;
//    int32_t y;
//    for(y = area->y1; y <= area->y2; y++) {
//        for(x = area->x1; x <= area->x2; x++) {
//            /*Put a pixel to the display. For example:*/
//            /*put_px(x, y, *color_p)*/
//            color_p++;
//        }
//    }

//    /* 在指定区域内填充指定颜色块 */
//    lcd_color_fill(area->x1, area->y1, area->x2, area->y2, (uint16_t *)color_p);
    lcd_draw_fast_rgb_color(area->x1,area->y1,area->x2,area->y2,(uint16_t*)color_p);

    /* 重要!!!
     * 通知图形库,已经刷新完毕了 */
    lv_disp_flush_ready(disp_drv);
}

/* 可选: GPU 接口 */

/* 如果你的 MCU 有硬件加速器 (GPU) 那么你可以使用它来为内存填充颜色 */
/**
 * @brief       使用 GPU 进行颜色填充
 *   @note      如有 MCU 有硬件加速器 (GPU),那么可以用它来为内存进行颜色填充
 *
 * @param       disp_drv    : 显示设备
 *   @arg       dest_buf    : 目标缓冲区
 *   @arg       dest_width  : 目标缓冲区的宽度
 *   @arg       fill_area   : 填充的区域
 *   @arg       color       : 颜色数组
 *
 * @retval      无
 */
//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
//                    const lv_area_t * fill_area, lv_color_t color)
//{
//    /*It's an example code which should be done by your GPU*/
//    int32_t x, y;
//    dest_buf += dest_width * fill_area->y1; /*Go to the first line*/

//    for(y = fill_area->y1; y <= fill_area->y2; y++) {
//        for(x = fill_area->x1; x <= fill_area->x2; x++) {
//            dest_buf[x] = color;
//        }
//        dest_buf+=dest_width;    /*Go to the next line*/
//    }
//}


#else /*Enable this file at the top*/

/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif

再修改indev触摸文件

lv_port_indev_template.c

首先

/* 导入驱动头文件 */
#include "./BSP/TOUCH/touch.h"

因为我们只有触摸屏所以其他不管全部屏蔽掉

触摸就是改这三个接口

配置初始化函数,没啥好讲的根据原来的逻辑换成你自己的函数就行 

完整:

/**
 * @file lv_port_indev_templ.c
 *
 */

 /*Copy this file as "lv_port_indev.c" and set this value to "1" to enable content*/
#if 1

/*********************
 *      INCLUDES
 *********************/
#include "lv_port_indev_template.h"
#include "../../lvgl.h"

/* 导入驱动头文件 */
#include "./BSP/TOUCH/touch.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/

/* 触摸屏 */
static void touchpad_init(void);
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool touchpad_is_pressed(void);
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y);

/* 鼠标 */
//static void mouse_init(void);
//static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
//static bool mouse_is_pressed(void);
//static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y);

/* 键盘 */
//static void keypad_init(void);
//static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
//static uint32_t keypad_get_key(void);

/* 编码器 */
//static void encoder_init(void);
//static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
//static void encoder_handler(void);

/* 按钮 */
//static void button_init(void);
//static void button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
//static int8_t button_get_pressed_id(void);
//static bool button_is_pressed(uint8_t id);

/**********************
 *  STATIC VARIABLES
 **********************/
lv_indev_t * indev_touchpad;    // 触摸屏
//lv_indev_t * indev_mouse;       // 鼠标
//lv_indev_t * indev_keypad;      // 键盘
//lv_indev_t * indev_encoder;     // 编码器
//lv_indev_t * indev_button;      // 按钮

/* 编码器相关 */
//static int32_t encoder_diff;
//static lv_indev_state_t encoder_state;

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

/**
 * @brief       初始化并注册输入设备
 * @param       无
 * @retval      无
 */
void lv_port_indev_init(void)
{
    /**
     * 
     * 在这里你可以找到 LittlevGL 支持的出入设备的实现示例:
     *  - 触摸屏
     *  - 鼠标 (支持光标)
     *  - 键盘 (仅支持按键的 GUI 用法)
     *  - 编码器 (支持的 GUI 用法仅包括: 左, 右, 按下)
     *  - 按钮 (按下屏幕上指定点的外部按钮)
     *
     *  函数 `..._read()` 只是示例
     *  你需要根据具体的硬件来完成这些函数
     */

    static lv_indev_drv_t indev_drv;

    /*------------------
     * 触摸屏
     * -----------------*/

    /* 初始化触摸屏(如果有) */
    TP_Init(); 
	touchpad_init();
    /* 注册触摸屏输入设备 */
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touchpad_read;
    indev_touchpad = lv_indev_drv_register(&indev_drv);

    /*------------------
     * 鼠标
     * -----------------*/

    /* 初始化鼠标(如果有) */
//    mouse_init();

    /* 注册鼠标输入设备 */
//    lv_indev_drv_init(&indev_drv);
//    indev_drv.type = LV_INDEV_TYPE_POINTER;
//    indev_drv.read_cb = mouse_read;
//    indev_mouse = lv_indev_drv_register(&indev_drv);

    /* 设置光标,为了简单起见,现在设置为一个 HOME 符号 */
//    lv_obj_t * mouse_cursor = lv_img_create(lv_scr_act());
//    lv_img_set_src(mouse_cursor, LV_SYMBOL_HOME);
//    lv_indev_set_cursor(indev_mouse, mouse_cursor);

    /*------------------
     * 键盘
     * -----------------*/

//    /* 初始化键盘(如果有) */
//    keypad_init();

//    /* 注册键盘输入设备 */
//    lv_indev_drv_init(&indev_drv);
//    indev_drv.type = LV_INDEV_TYPE_KEYPAD;
//    indev_drv.read_cb = keypad_read;
//    indev_keypad = lv_indev_drv_register(&indev_drv);

//    /* 接着你需要用 `lv_group_t * group = lv_group_create()` 来创建组
//     * 用 `lv_group_add_obj(group, obj)` 往组中添加物体
//     * 并将这个输入设备分配到组中,以导航到它:
//     * `lv_indev_set_group(indev_keypad, group);` */

    /*------------------
     * 编码器
     * -----------------*/

//    /* 初始化编码器(如果有) */
//    encoder_init();

//    /* 注册编码器输入设备 */
//    lv_indev_drv_init(&indev_drv);
//    indev_drv.type = LV_INDEV_TYPE_ENCODER;
//    indev_drv.read_cb = encoder_read;
//    indev_encoder = lv_indev_drv_register(&indev_drv);

//    /* 接着你需要用 `lv_group_t * group = lv_group_create()` 来创建组
//     * 用 `lv_group_add_obj(group, obj)` 往组中添加物体
//     * 并将这个输入设备分配到组中,以导航到它:
//     * `lv_indev_set_group(indev_keypad, group);` */

    /*------------------
     * 按钮
     * -----------------*/

//    /* 初始化按钮(如果有) */
//    button_init();

//    /* 注册按钮输入设备 */
//    lv_indev_drv_init(&indev_drv);
//    indev_drv.type = LV_INDEV_TYPE_BUTTON;
//    indev_drv.read_cb = button_read;
//    indev_button = lv_indev_drv_register(&indev_drv);

//    /* 为按钮分配屏幕上的点
//     * 以此来用按钮模拟点击屏幕上对应的点 */
//    static const lv_point_t btn_points[2] = {
//            {10, 10},   /*Button 0 -> x:10; y:10*/
//            {40, 100},  /*Button 1 -> x:40; y:100*/
//    };
//    lv_indev_set_button_points(indev_button, btn_points);
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

/*------------------
 * 触摸屏
 * -----------------*/

/**
 * @brief       初始化触摸屏
 * @param       无
 * @retval      无
 */
static void touchpad_init(void)
{
    /*Your code comes here*/
    TP_Init();
    
    /* 电阻屏坐标矫正 */
    if (key_scan(0) == KEY0_PRES)           /* KEY0按下,则执行校准程序 */
    {
        LCD_Clear(WHITE);                   /* 清屏 */
        TP_Adjust();                        /* 屏幕校准 */
        TP_Save_Adjdata();
    }
}

/**
 * @brief       图形库的触摸屏读取回调函数
 * @param       indev_drv   : 触摸屏设备
 *   @arg       data        : 输入设备数据结构体
 * @retval      无
 */
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
	tp_dev.scan(0); 
    static lv_coord_t last_x = 0;
    static lv_coord_t last_y = 0;
	
    /* 保存按下的坐标和状态 */
	
    if(touchpad_is_pressed())
    {
		if(tp_dev.x<lcddev.width&&tp_dev.y<lcddev.height)
        touchpad_get_xy(&last_x, &last_y);
        data->state = LV_INDEV_STATE_PR;
    } 
    else
    {
        data->state = LV_INDEV_STATE_REL;
    }

    /* 设置最后按下的坐标 */
    data->point.x = last_x;
    data->point.y = last_y;
}

/**
 * @brief       获取触摸屏设备的状态
 * @param       无
 * @retval      返回触摸屏设备是否被按下
 */
static bool touchpad_is_pressed(void)
{
    /*Your code comes here*/
    

    if (tp_dev.sta&TP_PRES_DOWN)
    {
        return true;
    }

    return false;
}

/**
 * @brief       在触摸屏被按下的时候读取 x、y 坐标
 * @param       x   : x坐标的指针
 *   @arg       y   : y坐标的指针
 * @retval      无
 */
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
//	TP_Read_XY(x, y);
    /*Your code comes here*/
//	TP_Read_XY(&tp_dev.x,&tp_dev.y);
    (*x) = tp_dev.x;
    (*y) = tp_dev.y;
//	TP_Read_XY((u16 *)x,(u16 *)y);
}

/*------------------
 * 鼠标
 * -----------------*/

/**
 * @brief       初始化鼠标
 * @param       无
 * @retval      无
 */
//static void mouse_init(void)
//{
//    /*Your code comes here*/
//    tp_dev.init();
//    /* 电阻屏如果发现显示屏XY镜像现象,需要坐标矫正 */
//    if (0 == (tp_dev.touchtype & 0x80))
//    {
//        tp_adjust();
//        tp_save_adjust_data();
//    }
//}

/**
 * @brief       图形库的鼠标读取回调函数
 * @param       indev_drv   : 鼠标设备
 *   @arg       data        : 输入设备数据结构体
 * @retval      无
 */
//static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
//{
//    /* 获取当前的 x、y 坐标 */
//    mouse_get_xy(&data->point.x, &data->point.y);

//    /* 获取是否按下或释放鼠标按钮 */
//    if(mouse_is_pressed()) {
//        data->state = LV_INDEV_STATE_PR;
//    } else {
//        data->state = LV_INDEV_STATE_REL;
//    }
//}

/**
 * @brief       获取鼠标设备是否被按下
 * @param       无
 * @retval      返回鼠标设备是否被按下
 */
//static bool mouse_is_pressed(void)
//{
//    /*Your code comes here*/
//    tp_dev.scan(0);
//    
//    if (tp_dev.sta & TP_PRES_DOWN)
//    {
//        return true;
//    }
//    
//    return false;
//}

/**
 * @brief       当鼠标被按下时,获取鼠标的 x、y 坐标
 * @param       x   : x坐标的指针
 *   @arg       y   : y坐标的指针
 * @retval      无
 */
//static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y)
//{
//    /*Your code comes here*/

//    (*x) = tp_dev.x[0];
//    (*y) = tp_dev.y[0];
//}

/*------------------
 * 键盘
 * -----------------*/

///**
// * @brief       初始化键盘
// * @param       无
// * @retval      无
// */
//static void keypad_init(void)
//{
//    /*Your code comes here*/
//}

///**
// * @brief       图形库的键盘读取回调函数
// * @param       indev_drv : 键盘设备
// *   @arg       data      : 输入设备数据结构体
// * @retval      无
// */
//static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
//{
//    static uint32_t last_key = 0;

    /* 这段代码是 LVGL 给出的例子,这里获取坐标好像是多余的 */
    /*Get the current x and y coordinates*/
    mouse_get_xy(&data->point.x, &data->point.y);

//    /* 获取按键是否被按下,并保存键值 */
//    uint32_t act_key = keypad_get_key();
//    if(act_key != 0) {
//        data->state = LV_INDEV_STATE_PR;

//        /* 将键值转换成 LVGL 的控制字符 */
//        switch(act_key) {
//        case 1:
//            act_key = LV_KEY_NEXT;
//            break;
//        case 2:
//            act_key = LV_KEY_PREV;
//            break;
//        case 3:
//            act_key = LV_KEY_LEFT;
//            break;
//        case 4:
//            act_key = LV_KEY_RIGHT;
//            break;
//        case 5:
//            act_key = LV_KEY_ENTER;
//            break;
//        }

//        last_key = act_key;
//    } else {
//        data->state = LV_INDEV_STATE_REL;
//    }

//    data->key = last_key;
//}

///**
// * @brief       获取当前正在按下的按键
// * @param       无
// * @retval      0 : 按键没有被按下
// */
//static uint32_t keypad_get_key(void)
//{
//    /*Your code comes here*/

//    return 0;
//}

/*------------------
 * 编码器
 * -----------------*/

///**
// * @brief       初始化编码器
// * @param       无
// * @retval      无
// */
//static void encoder_init(void)
//{
//    /*Your code comes here*/
//}


///**
// * @brief       图形库的编码器读取回调函数
// * @param       indev_drv : 编码器设备
// *   @arg       data      : 输入设备数据结构体
// * @retval      无
// */
//static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
//{

//    data->enc_diff = encoder_diff;
//    data->state = encoder_state;
//}

///**
// * @brief       在中断中调用此函数以处理编码器事件(旋转、按下)
// * @param       无
// * @retval      无
// */
//static void encoder_handler(void)
//{
//    /*Your code comes here*/

//    encoder_diff += 0;
//    encoder_state = LV_INDEV_STATE_REL;
//}

/*------------------
 * 按钮
 * -----------------*/


///**
// * @brief       初始化按钮
// * @param       无
// * @retval      无
// */
//static void button_init(void)
//{
//    /*Your code comes here*/
//}

///**
// * @brief       图形库的按钮读取回调函数
// * @param       indev_drv : 按钮设备
// *   @arg       data      : 输入设备数据结构体
// * @retval      无
// */
//static void button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
//{

//    static uint8_t last_btn = 0;

//    /* 获取被按下按钮的ID */
//    int8_t btn_act = button_get_pressed_id();

//    if(btn_act >= 0) {
//        data->state = LV_INDEV_STATE_PR;
//        last_btn = btn_act;
//    } else {
//        data->state = LV_INDEV_STATE_REL;
//    }

//    /* 保存最后被按下按钮的ID */
//    data->btn_id = last_btn;
//}

///**
// * @brief       获取被按下按钮的ID
// * @param       无
// * @retval      被按下按钮的ID
// */
//static int8_t button_get_pressed_id(void)
//{
//    uint8_t i;

//    /* 检查那个按键被按下(这里给出的示例适用于两个按钮的情况) */
//    for(i = 0; i < 2; i++) {
//        /* 返回被按下按钮的ID */
//        if(button_is_pressed(i)) {
//            return i;
//        }
//    }

//    /* 没有按钮被按下 */
//    return -1;
//}

///**
// * @brief       检查指定ID的按钮是否被按下
// * @param       无
// * @retval      按钮是否被按下
// */
//static bool button_is_pressed(uint8_t id)
//{

//    /*Your code comes here*/

//    return false;
//}

#else /*Enable this file at the top*/

/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif

最后工程链接:https://download.csdn.net/download/2301_80317247/90422906

记录遇到的问题:

1.

屏幕如果触摸有问题,刚开始我认为是代码的问题,但在我仔细的检查调试,并用历程进行重新新的调整之后,我发现根本就不是这样的它会出现的问题,只是因为我没有进行校准,也就是我之前没有开启过校准,所以它没有在24C02里面记录我前面校准的数据,他没有校准过,它也不提醒你要校准,它不像正点原子,你没有在ATC02里面设置校准已校准标志,它如果没有这个标志,它就提醒你要校准,我这个驱动代码,它没有的这个,是厂家给我的驱动程序,所以他没有提醒我校准,我也没试过校准,导致它只能检测到我有按下,但是它不能得到我精确的一个点在哪里,所以出现了问题就是厂家给我的驱动函数里面没有提示我要不要校准这是我用久了这里原子屏幕所出现的问题

解决办法就是在代码里面添加一个像正点原子一样检查我的24c零二里面有没有检测标志如果没有检测标志的话就证明我从来没有校准过那就初始化校准一次

    if (key_scan(0))           /* KEY0按下,则执行校准程序 */
    {
		LCD_Clear(WHITE);//清屏
		TP_Adjust();  //屏幕校准 
		TP_Save_Adjdata();
    }

2.

出现电阻屏幕不准就先检测你的屏幕驱动代码有没问题,用历程代码检测,没问题就检测at24c02处没处问题,并检测你是否有校准过,或者直接校准一次

;