STM32 F4移植LVGL 9.4.0版本教程(Keil工程,裸机)

一、下载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);
  	}
}

效果如下

相关推荐
Shylock_Mister2 小时前
STM32低功耗模式解析与应用指南
stm32·单片机·嵌入式硬件
小曹要微笑13 小时前
STM32各系列时钟树详解
c语言·stm32·单片机·嵌入式硬件·算法
炸膛坦客14 小时前
Cortex-M3-STM32F1 开发:(三十)HAL 库开发 ➤ 通用定时器 2/3/4/5 的时钟源寄存器设置,以及中断实验
stm32·单片机·嵌入式硬件
d111111111d15 小时前
STM32外设学习-I2C(细节)--学习笔记
笔记·stm32·单片机·嵌入式硬件·学习
chuwengeileyan115 小时前
stm32 光敏电阻 光控灯
stm32·单片机·嵌入式硬件
花落已飘17 小时前
STM32 SDIO接口介绍
stm32·单片机·嵌入式硬件
DIY机器人工房19 小时前
嵌入式面试题:了解软件SPI和软件I2C吗?说一说。
stm32·单片机·嵌入式硬件
三品吉他手会点灯1 天前
stm32f103学习笔记-17-STM32 中断应用总结
笔记·stm32·单片机·嵌入式硬件·学习
NEU-UUN1 天前
4.2.STM32-OLED显示屏
stm32·单片机·嵌入式硬件