TFT-LCD移植LVGL详细过程记录
TFT-LCD移植LVGL
LVGL(轻量级和通用图形库)是一个免费和开源的图形库,它提供了创建嵌入式GUI所需的一切,具有易于使用的图形元素,美丽的视觉效果和低内存占用。
LVGL更多介绍:https://zhuanlan.zhihu.com/p/406294618
本次实验将LVGL移植到STM32F103ZET6中,并编译通过,记录一下移植过程
在CubeMX中修改栈大小
因为LVGL要求MCU的堆栈最少是2K,2K = 2048 = 0x800,所以要在CubeMX中修改堆栈大小,为什么不直接在代码中修改呢,因为在代码中修改的话,而CubeMX中没有修改,下一次用CubeMX生成工程后又会覆盖掉代码中修改的地方,所以需要在CubeMX中修改
使用上次TFT-LCD触摸的文件,打开后在下图位置中修改,最小堆栈大小设置为0x800,然后生成工程代码
在keil工程里也可查看修改的位置
在keil中选择C99模式
LVGL要求开启C99模式,在C/C++选项中勾选即可
去官网或Github下载LVGL的源码和例程
官网地址:https://lvgl.io/
Github下载地址:https://github.com/lvgl
打开会比较慢,多试几次
下载好源码和例程,这里用V7版本的
建立LVGL的文件夹
LVGL官方代码里是相对路径,所以一定要按步骤建好文件夹
在工程目录下新建一个GUI的文件夹
GUI文件夹里再建三个子文件夹
lvgl:放源码,将下载的源码 lvgl-release-v7压缩包复制到该文件夹,并解压缩
lvgl_driver:放显示和触摸的驱动
在解压完的源码文件中,有个examples的文件夹,点击打开
再打开porting文件夹
这些就是显示和触摸的驱动文件
将显示和触摸的.c和.h文件拷贝到 lvgl_driver文件夹中,因为没有用到文件系统,所以可以不用拷贝,需要将文件名的_template去掉,不然后面加入keil工程后编译会出错
lvgl_example:放例程,将官方例程 lv_examples-release-v7复制到该文件夹并解压缩
将配置文件剪切到GUI根目录
打开lvgl的文件夹,找到 lv_conf_template.h文件
剪切粘贴到GUI文件夹的目录下,并修改文件名,将_template去掉
然后打开 lv_conf.h 文件,修改预编译选项,将0改为1,然后保存
打开 lvgl_examples 的文件夹,找到 lv_ex_conf_template.h 文件
剪切粘贴到GUI文件夹的目录下,同样要修改文件名,将_template去掉
同理,将 lv_ex_conf.h 的预编译选项的0改为1,保存
至此,LVGL的工程文件夹已经创建好
keil工程创建lvgl的文件夹
打开lvgl->src,将下面文件夹里的.c文件全都添加到keil工程的lvgl文件夹中
添加完的lvgl文件夹如下
然后编译一次,没有出现错误,发现有警告,这些警告是源码里的,尽量不要去修改源码
发现是111的警告,可以在keil里设置,屏蔽这些警告,需要在C/C++选项中的下图位置添加这条语句:–diag_suppress=111
然后再次编译,发现没有出现警告
修改配置文件
打开lv_disp.c源文件,找到 lv_conf.h文件,这个就是配置文件,要修改屏幕的最大分辨率,因为手上屏幕是240x320的,所以水平分辨率改为240,垂直分辨率保持默认
往下一点就是颜色格式设置和总线位数设置,颜色格式默认RGB565的,所以不用改,手上屏幕是16位总线的,所以总线位数也不用改,这需要根据具体屏幕硬件来设置
LVGL显示界面需要内存,如果显示的东西多,则需要的内存就大,下面这里就是设置分给LVGL内存的大小,如果显示的内容多,则32可改为其他值,这里使用默认
191行的是设置是否使用GPU,默认是1开启,改为0,选择不使用
211行是设置是否使用文件系统,默认是1使用,改为0,选择不使用
最后编译一次,没有错误则进行下一步
定时器中断回调函数中调用 LVGL 心跳函数 lv_tick_inc
首先包含lvgl的头文件路径
在MyApplication.h头文件中添加 lvgl.h 头文件
在定时器中断回调函数中调用lvgl的心跳函数 lv_tick_inc(),定时器每隔一定时间就调用该函数,控制 lvgl 刷新界面,lv_tick_inc函数需要传入参数,参数就是定时器定时时间,比如定时5ms,那就传入5,定时1ms,那就传入1
修改显示驱动
在keil工程中新创建一个驱动的文件夹 lvgl_driver,并添加显示驱动源文件 lv_port_disp.c,
打开lv_port_disp.c文件,修改预编译选项,0改为1,修改引入头文件的名称,lv_port_disp_template.h 改为 lv_port_disp.h
打开 lv_port_disp.h头文件,预编译0改为1,"lvgl/lvgl.h"改为 “…/lvgl/lvgl.h”,编译器才能找到该头文件路径
再回到 lv_port_disp.c 源文件中,找到 disp_init() 函数,这里可以放自己写的TFT-LCD屏幕驱动
当然使用自己的函数需要引入对应的头文件
执行完disp_init函数后,会进行缓存的定义,lvgl给出了三种定义的方法,如下图,方法1最简单,方法2使用了双重缓存,方法3是根据屏幕大小定义缓存,这次使用比较简单的第1种方法,把另外两种注释掉即可
第一种方法中的缓存大小 LV_HOR_RES_MAX * 10 改为 LV_HOR_RES_MAX * LV_HOR_RES_MAX / 10,设置缓存大一点
再往下就是设置当前屏幕的尺寸大小的,将水平的480改为240,跟屏幕匹配;前面源码里设置的是屏幕最大的分辨率,这里设置的尺寸大小不能大于前面设置的最大分辨率
接下来修改disp_flush函数,下面是该函数没有被修改过的,可以看出该函数的功能就是设置一个窗口,然后往窗口里写入像素点的值,写入的操作默认被注释掉了,写完一个像素点后,像素点指针加1,继续写下一个像素点
/* Flush the content of the internal buffer the specific area on the display* You can use DMA or any hardware acceleration to do this operation in the background but* 'lv_disp_flush_ready()' has to be called when finished. */
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/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++; //像素点指针加1}}/* IMPORTANT!!!* Inform the graphics library that you are ready with the flushing*/lv_disp_flush_ready(disp_drv);
}
修改后的disp_flush函数如下,挂起STM32的systick时钟是为了提高GUI的刷新速度,在写完像素点数据后,再开启systick时钟
/* Flush the content of the internal buffer the specific area on the display* You can use DMA or any hardware acceleration to do this operation in the background but* 'lv_disp_flush_ready()' has to be called when finished. */
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/uint16_t x,y;//挂起systick,提高GUI刷新速率HAL_SuspendTick();//设置窗口,参数:X轴起始位,Y轴起始位,长度,宽度TFT_LCD.LCD_SetWindows(area->x1,area->y1,area->x2-area->x1+1,area->y2-area->y1+1); 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)*/LCD_Write_DATA(color_p->full); //调用函数写入像素点数据color_p++;}}/* IMPORTANT!!!* Inform the graphics library that you are ready with the flushing*/lv_disp_flush_ready(disp_drv);//恢复systickHAL_ResumeTick();
}
修改触摸驱动
在lvgl_driver文件夹中,添加触摸驱动源文件 lv_port_indev.c
然后与显示驱动一样,修改源文件的预编译选项,修改引入头文件的名称
lv_port_indev.h头文件也是修改预编译选项,修改引入的头文件路径
然后回到 lv_port_indev.c源文件中,里面是一些功能的驱动函数,如触摸、鼠标、键盘、编码器和按钮功能,需要什么功能根据实际情况选择,本次移植使用简单点的触摸功能,其他功能函数都可删掉
修改后的lv_port_indev.c源文件,用lvgl自带的初始化函数,然后对touchpad_read函数进行修改
/*** @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.h"
#include "MyApplication.h"static bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);void lv_port_indev_init(void)
{/* Here you will find example implementation of input devices supported by LittelvGL:* - Touchpad* - Mouse (with cursor support)* - Keypad (supports GUI usage only with key)* - Encoder (supports GUI usage only with: left, right, push)* - Button (external buttons to press points on the screen)** The `..._read()` function are only examples.* You should shape them according to your hardware*/lv_indev_drv_t indev_drv;/*------------------* Touchpad* -----------------*//*Register a touchpad input device*/lv_indev_drv_init(&indev_drv);indev_drv.type = LV_INDEV_TYPE_POINTER;indev_drv.read_cb = touchpad_read;lv_indev_drv_register(&indev_drv);
}/*********************** STATIC FUNCTIONS**********************//* Will be called by the library to read the touchpad */
static bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{//当前坐标static uint16_t last_x = 0;static uint16_t last_y = 0;//如果触摸导致坐标更新if(Touch.Touch_Flag == TRUE){ Touch.Touch_Flag = FALSE;//把新坐标Touch.LCD_X和Touch.LCD_Y赋给lvgl的坐标结构体的x和ydata->point.x = Touch.LCD_X;data->point.y = Touch.LCD_Y;//更改状态,lvgl获取坐标data->state = LV_INDEV_STATE_PR;//更新当前坐标last_x = data->point.x;last_y = data->point.y;}else //如果没有触摸{//把上一次坐标赋给lvgl坐标结构体的x和ydata->point.x = last_x;data->point.y = last_y;//更改状态,lvgl获取坐标data->state = LV_INDEV_STATE_REL;}return false;
}#else /* Enable this file at the top *//* This dummy typedef exists purely to silence -Wpedantic. */
typedef int keep_pedantic_happy;
#endif
系统运行主函数中判断屏幕是否被触摸,如果触摸了,则更新标志位
/** @name Run* @brief 系统运行* @param None* @retval None
*/
static void Run()
{ //获取坐标板坐标if(Touch.Scan() == TRUE){//通过该标志位知道屏幕是否被触摸更新坐标Touch.Touch_Flag = TRUE;}
}
包含lvgl的头文件
在自己工程的公共头文件MyApplication.h中添加lvgl的头文件
在设置中添加头文件路径,包括源文件路径和驱动路径
显示驱动和触摸驱动都是有初始化函数的,但它们的头文件都没有声明初始化函数,如果要调用这些函数的话是会有警告的,所以要先进行声明
在自己的初始化函数中调用lvgl的初始化函数lv_init(),显示驱动函数lv_port_disp_init(),触摸驱动函数lv_port_indev_init()
把前面触摸屏扫描函数中在LCD屏幕上显示触摸屏的坐标值的语句删除
移植基本完成,进行编译,没有报错
TFT-LCD移植LVGL详细过程记录相关推荐
- VS调试dll详细过程记录
VS调试dll详细过程记录 还可以参考博客: https://blog.csdn.net/u014738665/article/details/79779632 在我们写的程序中有时候调用dll,并且 ...
- wintogo详细过程记录
wintogo详细过程记录 大概步骤 详细过程 大概步骤 下载win10镜像 用DAEMON Tools Lite软件加载win10镜像 用wintogo软件制作win10系统 安装启动win10系统 ...
- arduino tft 方向_ESP32在Arduino环境下玩转 LVGL,ESP32移植LVGL详细教程
微信关注 "DLGG创客DIY"设为"星标",重磅干货,第一时间送达. ❝ 转载自慕容流年 https://me.csdn.net/qq_41868901 ❞ ...
- STM32 移植FreeModbus详细过程
modbus是一个非常好的串口协议(当然也能用在网口上),它简洁.规范.强大.可以满足大部分的工业.嵌入式需求.我写的这个四个寄存器都可以用(输入寄存器.保持寄存器.线圈寄存器.离散寄存器).不像别的 ...
- Ubuntu搭建DTN2仿真平台(详细过程记录)
基于Ubuntu搭建DTN2仿真平台 软件安装 软件下载 安装过程 基础运用 软件安装 编译安装 dtn2 之前要保证 gcc 编译器是 3.3 版本以上(但其实如果用低于4.9版本的gcc编译mak ...
- 2440移植Mplayer详细过程(最简便的方法)以及报错解决
移植环境(红色粗字体字为修改后内容,蓝色粗体字为特别注意内容) 1,开发板:韦东山JZ2440 2,linux 版本:linux-3.4.2 3,系统版本:Ubuntu9.10 4,交叉编译环境:ar ...
- 在Windows 10(Win10)下安装“NVIDIA图形驱动程序”、“NVIDIA控制面板”、CUDA Toolkit、cuDNN Archive的详细过程记录
目标:安装CUDA Toolkit和cuDNN Archive 目录 一. 安装NVIDIA驱动程序和NVIDIA 控制面板 二.安装CUDA Toolkit 三.安装cuDNN Archive 一. ...
- STM32F767ZI-NUCLEO移植运行micropython过程记录
注意,本教程移植microPython是通过烧写hex文件实现的,网上其他教程很多是介绍使用USB DFU方式(设备boot0至高电平,通过DfuSeDemo烧写),由于自己还不熟没有使用这种方式,后 ...
- Houdini湖边小屋-屋顶细分详细过程记录
b站UP主七里雪凝的湖边小屋教程--P3/P4[Houdini]萌新的<湖边小屋>教程拆解与实现,殊途同归!_哔哩哔哩_bilibili 目录 内容概括 详细步骤 1 [Facet节点]让 ...
最新文章
- 微信朋友圈里的十五种类型,笑死了!
- 【剑指offer-Java版】33把数组排成最小的数
- python自学什么书比较好-有什么好的自学 Python 的书籍推荐?
- 对页面制定区域进行打印,以及打印不显示页脚URL的方法
- Codeforces 920D Tanks (看题解)
- 一步一步使用Ext JS MVC与Asp.Net MVC 3开发简单的CMS后台管理系统之完成登录功能...
- easyUI 添加CheckBox选择到DataGrid
- 学习组合模式,转载一段有关组合模式的详解
- SpringMVC框架----SessionAttribute注解
- https://en.wikipedia.org/wiki/Linux Foundation
- 输入三角形的三c语言程序,输入三角形的三边 a,b,c,计算三角形的面积的公式是 C++...
- springcloud配置负载均衡 及方式_Springcloud-Ribbon负载均衡NODO
- wsdl文件 服务器地址,webservice 的wsdl文件详解
- SL8530A DC-DC 2.6V~100V宽输入电压升压型LED面板RGB调光恒流驱动芯片
- P1004 方格取数
- 高通---IGV:从安装到使用
- 2020,好看视频的创作生态棋局
- @03Python基础语法
- 防沉迷与身份证系统挂钩 网游要实名认证
- 我国火箭回收历程介绍