LVGL的PC端移植和STM32F429阿波罗开发板移植

LVGL介绍

一款开源GUI库,适合嵌入式开发,对资源要求小。适用单片机开发和其他嵌入式开发,最主要是的是UI界面美观深得我心

LVGL开发环境

PC:win10操作系统,在VS上进行仿真
硬件:阿波罗开发板F429

LVGL的GitHub的代码介绍

由于本人对GIT使用不是很熟练,所以都是直接从git上下载代码后自己移植,不能像大佬们一样直接使用git命令直接从github上把代码搞下来。
登录网址
https://github.com/lvgl/lv_sim_visual_studio
下载这个VS工程
下载完成后发现lv_sim_visual_studio-master\LVGL.Simulator这个目录下的freetype,lv_demo,lv_drivers,lv_lib_freetype,lvgl。这几个源码文件里面没有任何内容。
其实这是一个空的LVGL8.1 VS空项目。后面我们只需要进入github上面这个工程里面把这几个最新的项目也下载下来复制进去就可以了。
在这里插入图片描述在这里插入图片描述点击进去和刚刚下载VS空工程一样下载这几个缺失的源码。
下载完成后,将刚下载的freetype,lv_demo,lv_drivers,lv_lib_freetype,lvgl。这5个文件夹下的内容复制到工程中相对应的空文件夹下去。
之后就可以打开VS工程文件
在这里插入图片描述换位x64方案解决平台,这个根据个人电脑。
然后编译,直接成功相当丝滑。
在这里插入图片描述工程中LVGL.Simulator.cpp是mian函数所在位置,可以在源码中切换其他的demo例程。

LVGL8.1 在F429上面的移植

准备

实现屏幕显示函数,和触屏函数
我先前已经在LVGL上面实现了LTDC和触摸屏驱动
话不多说开始在单片机上面移植
然后复制刚刚PC上文件夹中的 lvgl 和 lvgl_demo两个文件下的全部内容到工程中
然后将下面几个文件改名去掉后缀。
在这里插入图片描述这个是配置文件。
还有Littel_VGL\GUI\lvgl\examples\porting下的
在这里插入图片描述这几个是接口文件,indev设备输入接口文件,disp显示接口文件
还有demo_conf文件也删除掉后缀
然后将lvgl_scr中的文件和demo中的文件添加到STM32的项目中
打开lv_conf.h 文件中的条件编译 0 改为1
打开lv_demo_conf.h的条件编译 0改为1

将lv_printf.h


//#if defined(__has_include) && __has_include(<inttypes.h>)//屏蔽
    #include<inttypes.h>
    /* platform-specific printf format for int32_t, usually "d" or "ld" */
    #define LV_PRId32 PRId32
//#else//屏蔽
    /* hope this is correct for ports without __has_include or without inttypes.h */
//    #define LV_PRId32 "d"//屏蔽
//#endif    //屏蔽


然后编译缺什么加什么 缺.h路径就加路径 缺函数就去相应的src源码文件夹下添加对应的.c文件

在这里插入图片描述类似这种
在这里插入图片描述把一些没必要的警告屏蔽掉

编译没有错误后
打开lv_port_disp.h的条件编译 0改为1
打开lv_port_indev.h的条件编译 0改为1
打开lv_port_disp.c的条件编译 0改为1
打开lv_port_indev.c的条件编译 0改为1
最后需要实现几个接口

	lv_tick_inc(1);//lvgl 的 1ms 心跳  在定时器中调用
	lv_port_disp_init();						//lvgl显示接口初始化,放在lv_init()的后面
	lv_port_indev_init();						//lvgl输入接口初始化,放在lv_init()的后面
	

修改lv_port_disp.c文件中的

void lv_port_disp_init(void)
{
    /*-------------------------
     * Initialize your display
     * -----------------------*/
		static lv_disp_draw_buf_t disp_buf;
    disp_init();

    /*-----------------------------
     * Create a buffer for drawing
     *----------------------------*/

    /**
     * LVGL requires a buffer where it internally draws the widgets.
     * Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display.
     * The buffer has to be greater than 1 display row
     *
     * There are 3 buffering configurations:
     * 1. Create ONE buffer:
     *      LVGL will draw the display's content here and writes it to your display
     *
     * 2. Create TWO buffer:
     *      LVGL will draw the display's content to a buffer and writes it your display.
     *      You should use DMA to write the buffer's content to the display.
     *      It will enable LVGL to draw the next part of the screen to the other buffer while
     *      the data is being sent form the first buffer. It makes rendering and flushing parallel.
     *
     * 3. Double buffering
     *      Set 2 screens sized buffers and set disp_drv.full_refresh = 1.
     *      This way LVGL will always provide the whole rendered screen in `flush_cb`
     *      and you only need to change the frame buffer's address.
     */

    /* Example for 1) */
//    static lv_disp_draw_buf_t draw_buf_dsc_1;
//    static lv_color_t buf_1[MY_DISP_HOR_RES * 10];                          /*A buffer for 10 rows*/
//    lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10);   /*Initialize the display buffer*/

    /* Example for 2) */
//    static lv_disp_draw_buf_t draw_buf_dsc_2;
//    static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10];                        /*A buffer for 10 rows*/
//    static lv_color_t buf_2_2[MY_DISP_HOR_RES * 10];                        /*An other buffer for 10 rows*/
//    lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10);   /*Initialize the display buffer*/
			lv_disp_draw_buf_init(&disp_buf, color_buf, color_buf2, COLOR_BUF_SIZE);   /*Initialize the display buffer*/  双缓冲 刷屏
    /* Example for 3) also set disp_drv.full_refresh = 1 below*/
//    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];            /*A screen sized buffer*/
//    static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES];            /*An other screen sized buffer*/
//    lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2, MY_DISP_VER_RES * LV_VER_RES_MAX);   /*Initialize the display buffer*/

    /*-----------------------------------
     * Register the display in LVGL
     *----------------------------------*/

    static lv_disp_drv_t disp_drv;                         /*Descriptor of a display driver*/
    lv_disp_drv_init(&disp_drv);                    /*Basic initialization*/

    /*Set up the functions to access to your display*/

    /*Set the resolution of the display*/
    disp_drv.hor_res = LCD_WIDTH;//自己显示屏的分辨率
    disp_drv.ver_res = LCD_HEIGHT;//自己显示屏的分辨率

    /*Used to copy the buffer's content to the display*/
    disp_drv.flush_cb = disp_flush;

    /*Set a display buffer*/
    disp_drv.draw_buf = &disp_buf;

    /*Required for Example 3)*/
    //disp_drv.full_refresh = 1

    /* Fill a memory array with a color if you have GPU.
     * Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL.
     * But if you have a different GPU you can use with this callback.*/
    //disp_drv.gpu_fill_cb = gpu_fill;

    /*Finally register the driver*/
    lv_disp_drv_register(&disp_drv);
}

实现disp_flush函数

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*/


//    /*IMPORTANT!!!
//     *Inform the graphics library that you are ready with the flushing*/
			//用DMA2D实现刷屏的刷屏函数
			LTDC_Color_Fill(area->x1,area->y1,area->x2,area->y2,(uint16_t*)color_p);
    /* IMPORTANT!!!
     * Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);	
	
}

修改lv_port_indev.c函数

因为我们用的是touchpad 触摸屏 所以这个文件中源码的 鼠标mouse和键盘keypad 以及其他encoder都要删掉

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
     */

    static lv_indev_drv_t indev_drv;

    /*------------------
     * Touchpad
     * -----------------*/

    /*Initialize your touchpad if you have*/
    touchpad_init();

    /*Register a touchpad input device*/
    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);

}

实现touchpad_read函数

static void 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(Dev_Now.Touch&TP_PRES_DOWN)//触摸按下了  这是我在触摸屏处理函数触摸按下的标记位。
		{
			last_x = Dev_Now.X[0];
			last_y = Dev_Now.Y[0];//赋值坐标
			data->point.x = last_x;
			data->point.y = last_y;
			data->state = LV_INDEV_STATE_PR;//按下状态
		}else{
			data->point.x = last_x;
			data->point.y = last_y;
			data->state = LV_INDEV_STATE_REL;//松开状态
		}
    /*Return `false` because we are not buffering and no more data to read*/
   // return false;
}

在项目中调用所有需要用到lvgl库函数实现demo例程

修改lv_conf.h中的配置宏定义
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH     16

/*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/
#  define LV_MEM_SIZE    (64U * 1024U)          /*[bytes]*/增加lvgl所需的RAM 因为widgets例程需要控件比较大

/*1: Show CPU usage and FPS count in the right bottom corner*/
#define LV_USE_PERF_MONITOR     1

/*1: Show the used memory and the memory fragmentation in the left bottom corner
 * Requires LV_MEM_CUSTOM = 0*/
#define LV_USE_MEM_MONITOR      1
在lv_demo_conf.h打开widgets例程宏定义
/*Show some widget*/
#define LV_USE_DEMO_WIDGETS        1
#if LV_USE_DEMO_WIDGETS
#define LV_DEMO_WIDGETS_SLIDESHOW  1
#endif
在主循环之前调用
	lv_init();											//lvgl系统初始化
	lv_port_disp_init();						//lvgl显示接口初始化,放在lv_init()的后面
	lv_port_indev_init();						//lvgl输入接口初始化,放在lv_init()的后面
	lv_demo_widgets();						//demo例程
在定时器中调用
lv_tick_inc(1);//lvgl 的 1ms 心跳
在主循环中调用
			GT911_Scan(0);//触摸扫描函数  你也就可以放在touchpad_read中调用
			lv_task_handler();//LittleVGL必须要调用的任务处理函数		

然后再次编译,有错误到错误处看看那里的字体未定义 就打开宏定义
然后看还有什么警告和错误 lv_printf();这样的串口输出函数对总体不影响就可以直接屏蔽
之后基本没有什么错误了。

然后再次编译编译成功后下载到阿波罗开发板中
在这里插入图片描述移植成功 然后就可以 开始开心的进行LVGL的自定义UI界面设计了

其中各个控件的使用方法可以参考
百问网的文档和LVGL官方源文档。还有正点原子阿波罗开发板。以及正点原子讲师熊老师的视频
[1]: http://lvgl.100ask.org/8.1/intro/index.html
[2]: https://docs.lvgl.io/8.1/

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
阿波罗STM32F429开发板是一款基于STM32F429ZIT6芯片的开发板,具有丰富的外设和接口,适合用于嵌入式系统开发、物联网设备等应用场景。本文将介绍如何使用阿波罗STM32F429开发板实现一个简单的电子时钟。 1. 硬件准备 阿波罗STM32F429开发板 TFT液晶屏 DS3231实时时钟芯片 面包板、杜邦线等 2. 硬件连接 将DS3231实时时钟芯片连接到开发板的I2C接口上,连接液晶屏的引脚到开发板的GPIO引脚上,具体连接方法可以参考阿波罗STM32F429开发板的文档。 3. 软件设计 在Keil MDK中创建一个新的工程,选择适合的STM32F429芯片型号,并添加相应的头文件和库文件。 首先,需要初始化DS3231实时时钟芯片,获取当前时间并显示在液晶屏上。可以使用STM32的I2C库函数进行操作,具体代码如下: // 初始化I2C接口 I2C_HandleTypeDef hi2c1; hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } // 获取时间 uint8_t time[7]; HAL_I2C_Mem_Read(&hi2c1, DS3231_ADDR, DS3231_TIME_REG, 1, time, 7, 1000); // 解析时间 uint8_t year = (time[6] >> 4) * 10 + (time[6] & 0x0F); uint8_t month = (time[5] >> 4) * 10 + (time[5] & 0x0F); uint8_t day = (time[4] >> 4) * 10 + (time[4] & 0x0F); uint8_t hour = (time[2] >> 4) * 10 + (time[2] & 0x0F); uint8_t minute = (time[1] >> 4) * 10 + (time[1] & 0x0F); uint8_t second = (time[0] >> 4) * 10 + (time[0] & 0x0F); // 显示时间 char str[20]; sprintf(str, "%02d:%02d:%02d", hour, minute, second); LCD_ShowString(30, 50, (uint8_t *)str, BLACK, WHITE); 接下来,需要实现一个定时器,每秒钟更新一次时间。可以使用STM32的定时器和中断函数进行操作,具体代码如下: // 初始化定时器 TIM_HandleTypeDef htim6; htim6.Instance = TIM6; htim6.Init.Prescaler = 8399; htim6.Init.CounterMode = TIM_COUNTERMODE_UP; htim6.Init.Period = 999; htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim6) != HAL_OK) { Error_Handler(); } // 启动定时器 HAL_TIM_Base_Start_IT(&htim6); // 定时器中断处理函数 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM6) { // 获取时间 uint8_t time[7]; HAL_I2C_Mem_Read(&hi2c1, DS3231_ADDR, DS3231_TIME_REG, 1, time, 7, 1000); // 解析时间 uint8_t hour = (time[2] >> 4) * 10 + (time[2] & 0x0F); uint8_t minute = (time[1] >> 4) * 10 + (time[1] & 0x0F); uint8_t second = (time[0] >> 4) * 10 + (time[0] & 0x0F); // 显示时间 char str[20]; sprintf(str, "%02d:%02d:%02d", hour, minute, second); LCD_ShowString(30, 50, (uint8_t *)str, BLACK, WHITE); } } 4. 测试 编译程序并烧录到阿波罗STM32F429开发板,连接好DS3231实时时钟芯片和液晶屏后,上电即可看到电子时钟在液晶屏上显示当前时间,并每秒钟更新一次时间。 总结 本文介绍了如何使用阿波罗STM32F429开发板实现一个简单的电子时钟,通过I2C接口读取DS3231实时时钟芯片的时间并显示在液晶屏上,通过定时器每秒钟更新一次时间。这只是一个简单的例子,开发者可以根据自己的需要扩展更多功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值