一、下载LVGL9.4.0源码

二、删除不必要的文件,只保留以下文件
| 文件 | 作用 |
|---|---|
| lv_conf_template.h | lvgl配置文件 |
| lv_version.h | lvgl版本 |
| lvgl_private.h | 私有头文件包含 |
| 文件夹 | 作用 |
|---|---|
| src | lvgl源码 |
| examples/porting | 示例代码,只保留porting文件夹 |
| demos | lvgl测试程序,可有可无 |
最终保留图示,将lvgl文件夹复制至keil工程目录(不要破坏目录结构),重命名lv_conf_templete.h为lv_conf.h

三、添加至STM32F4项目工程
1、添加头文件路径,只需要根目录、src目录和porting目录即可

2、添加源文件
*** 注:添加src目录内.c源文件(包含子目录)(除去src/draw/nxp 和 src/draw/reneasa,恩智浦和瑞萨平台的)***

3、修改examples\porting文件夹内的文件名,删除templete
注:需同步修改.c文件的头文件包含名称

四、修改相关文件
1、打开lv_conf.h 启用头lvgl配置文件

2、打开lv_port_disp.c源文件以及头文件的宏定义,启用disp显示接口
注:添加屏幕分辨率,以及包含屏幕驱动头文件

注:将原先的lvgl.h头文件路径进行修改

五、添加屏幕驱动
1、选择屏幕刷新缓缓冲的方式,随便选一个,其它两个注释掉
c
void lv_port_disp_init(void)
{
/*-------------------------
* Initialize your display
* -----------------------*/
disp_init();
/*------------------------------------
* Create a display and set a flush_cb
* -----------------------------------*/
lv_display_t * disp = lv_display_create(MY_DISP_HOR_RES, MY_DISP_VER_RES);
lv_display_set_flush_cb(disp, disp_flush);
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_0);
/* Example 1
* One buffer for partial rendering*/
// LV_ATTRIBUTE_MEM_ALIGN
// static uint8_t buf_1_1[MY_DISP_HOR_RES * 10 * BYTE_PER_PIXEL]; /*A buffer for 10 rows*/
// lv_display_set_buffers(disp, buf_1_1, NULL, sizeof(buf_1_1), LV_DISPLAY_RENDER_MODE_PARTIAL);
/* Example 2
* Two buffers for partial rendering
* In flush_cb DMA or similar hardware should be used to update the display in the background.*/
LV_ATTRIBUTE_MEM_ALIGN
static uint8_t buf_2_1[MY_DISP_HOR_RES * 10 * BYTE_PER_PIXEL];
LV_ATTRIBUTE_MEM_ALIGN
static uint8_t buf_2_2[MY_DISP_HOR_RES * 10 * BYTE_PER_PIXEL];
lv_display_set_buffers(disp, buf_2_1, buf_2_2, sizeof(buf_2_1), LV_DISPLAY_RENDER_MODE_PARTIAL);
/* Example 3
* Two buffers screen sized buffer for double buffering.
* Both LV_DISPLAY_RENDER_MODE_DIRECT and LV_DISPLAY_RENDER_MODE_FULL works, see their comments*/
// LV_ATTRIBUTE_MEM_ALIGN
// static uint8_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES * BYTE_PER_PIXEL];
// LV_ATTRIBUTE_MEM_ALIGN
// static uint8_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES * BYTE_PER_PIXEL];
// lv_display_set_buffers(disp, buf_3_1, buf_3_2, sizeof(buf_3_1), LV_DISPLAY_RENDER_MODE_DIRECT);
}
2、添加屏幕初始化代码
c
static void disp_init(void)
{
/*You code here*/
register_lcd_driver(&lcd_dev);
lcd_dev.ops.init(&lcd_dev);
lcd_dev.ops.set_dispaly_dir(&lcd_dev,ROTATE_0_DEGREES);
}
3、添加屏幕画点API
c
static void disp_flush(lv_display_t * disp_drv, const lv_area_t * area, uint8_t * px_map)
{
if(disp_flush_enabled) {
/*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, *px_map)*/ //画点API
px_map++;
}
}
}
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
lv_display_flush_ready(disp_drv);
}
//这是我的
static void disp_flush(lv_display_t * disp_drv, const lv_area_t * area, uint8_t * px_map) {
if (!disp_flush_enabled) return;
int32_t x, y;
for (y = area->y1; y <= area->y2; y++) {
lcd_dev.ops.user_ops.set_coord.start_y = y;
for (x = area->x1; x <= area->x2; x++) {
lcd_dev.ops.user_ops.set_coord.start_x = x;
uint16_t color = (px_map[1] << 8) | px_map[0];
lcd_dev.ops.user_ops.set_color = color;
lcd_dev.ops.draw_pixel(&lcd_dev);
px_map += 2;
}
}
lv_display_flush_ready(disp_drv);
}
4、为LVGL提供tick计数,以及任务处理函数周期调用
c
//LV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period)
//在1ms周期中断调用lv_tick_inc(t);,直接丢tick中断就行了
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
tick_inc(1);
HAL_IncTick();
}
//在while循环调用
lv_task_handler();
写个HELLO STM32测试下
c
#include "lvgl.h"
#include "lv_port_disp.h"
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
HAL_Init();
SystemClock_Config();
lv_init();
lv_port_disp_init();
// 1. 获取当前活动屏幕(默认屏幕)
lv_obj_t * scr = lv_scr_act();
// 画个标签:居中显示
lv_obj_t * label = lv_label_create(scr);
lv_label_set_text(label, "HELLO STM32");
lv_obj_set_style_text_font(label, &lv_font_montserrat_14, 0);
lv_obj_center(label); // 居中
// 再画个标签:放在屏幕左上角 (50, 100)
lv_obj_t * label1 = lv_label_create(scr);
lv_label_set_text(label1, "HELLO LVGL");
lv_obj_set_style_text_font(label1, &lv_font_montserrat_14, 0);
lv_obj_set_pos(label1, 100, 100); // 绝对定位到 (50,100)
// 画个方块
lv_obj_t * test_rect = lv_obj_create(lv_scr_act());
lv_obj_set_size(test_rect, 50, 50);
lv_obj_set_style_bg_color(test_rect, lv_palette_main(LV_PALETTE_RED), 0);
lv_obj_align(test_rect, LV_ALIGN_TOP_LEFT, 0, 0);
// 再画一个
lv_obj_t * test_rect1 = lv_obj_create(lv_scr_act());
lv_obj_set_size(test_rect1, 60, 60);
lv_obj_set_style_bg_color(test_rect1, lv_palette_main(LV_PALETTE_YELLOW), 0);
lv_obj_align(test_rect1, LV_ALIGN_BOTTOM_RIGHT, 0, 0);
while (1)
{
lv_task_handler();
HAL_Delay(5);
}
}
效果如下
