文章目录[隐藏]
开发板:潘多拉开发板
系统版本:v4.0.3
LVGL版本:8.0.2
注:这篇文章就简单记录下编译成功,跑了一个 demo 的过程,至于是否完全移植成功,不确定哈,毕竟 LVGL 还没自学呢。。
一、创建目录
在 bsp/stm32/stm32l475-atk-pandora/board/ports 目录下创建一个 lvgl 目录,然后将 lvgl 的源码放进该目录。
目录结构如下所示。
├─lvgl
│ ├─lvgl-8.0.2
二、添加配置文件
将 lvgl-8.0.2/lv_conf_template.h 文件复制到 lvgl 同级目录下,并将其重命名为 lv_conf.h 。打开文件并将开头的 #if 0 更改为 #if 1 以使能其内容。
将 lv_drivers-6.1.1/lv_drv_conf_template.h 文件复制到 lv_drivers 同级目录下,并将其重命名为 lv_drv_conf.h 。打开文件并将开头的 #if 0 更改为 #if 1 以使能其内容。
这里需要注意一下 lv_conf.h 文件里面的宏,对于 8.0.2 版本来说,只需要修改下面这个宏就可以了,具体的数值根据你的 LCD 参数决定。
/* Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888) */
#define LV_COLOR_DEPTH 16
三、将主要的源码添加到工程中
在实际操作之前,我们需要知道有哪些代码是需要添加到工程里面的。
├─lvgl
│ ├─lvgl-8.0.2
│ │ ├─src (必须)
当然,这里只是添加了部分的源码,可以基本运行,如果要完整的源码,可以自行添加。
1、
在 bsp/stm32/stm32l475-atk-pandora/board/ports/lvgl、bsp/stm32/stm32l475-atk-pandora/board/ports/lvgl/lvgl-8.0.2/src 目录下创建一个内容和下面相同的 SConscript 文件,用于自动生成工程。
import os
from building import *
# get current dir path
cwd = GetCurrentDir()
# init src and inc vars
src = Glob('*.c')
inc = [cwd]
objs = DefineGroup('lvgl', src, depend = [], CPPPATH = inc)
list = os.listdir(cwd)
for item in list:
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
objs = objs + SConscript(os.path.join(item, 'SConscript'))
Return('objs')
2、
在 bsp/stm32/stm32l475-atk-pandora/board/ports/lvgl/lvgl-8.0.2 创建一个内容和下面相同的 SConscript 文件,用于自动生成工程。
import os
from building import *
# get current dir path
cwd = GetCurrentDir()
objs = []
list = os.listdir(cwd)
for item in list:
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
objs = objs + SConscript(os.path.join(item, 'SConscript'))
Return('objs')
3、
在 bsp/stm32/stm32l475-atk-pandora/board/ports/lvgl/lvgl-8.0.2/src 目录下的子目录 core、draw、font、hal、misc、widgets 中创建一个内容和下面相同的 SConscript 文件,用于自动生成工程。
from building import *
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp')+ Glob('*.a')
CPPPATH = [cwd, str(Dir('#'))]
# 因为是使用 keil 编译,所以要加上这句话
LOCAL_CCFLAGS = ' --c99 --gnu -g -W'
group = DefineGroup('lvgl', src, depend = [], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS)
Return('group')
4、
对于 bsp/stm32/stm32l475-atk-pandora/board/ports/lvgl/lvgl-8.0.2/src 目录下的子目录 extra 需要单独处理,因为它里面还有多个子目录。(所以下面的代码可维护性有点差)
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
src += Glob('./layouts/grid/*.c')
src += Glob('./layouts/flex/*.c')
src += Glob('./themes/basic/*.c')
src += Glob('./themes/default/*.c')
src += Glob('./themes/mono/*.c')
src += Glob('./widgets/animimg/*.c')
src += Glob('./widgets/calendar/*.c')
src += Glob('./widgets/chart/*.c')
src += Glob('./widgets/colorwheel/*.c')
src += Glob('./widgets/imgbtn/*.c')
src += Glob('./widgets/keyboard/*.c')
src += Glob('./widgets/led/*.c')
src += Glob('./widgets/list/*.c')
src += Glob('./widgets/meter/*.c')
src += Glob('./widgets/msgbox/*.c')
src += Glob('./widgets/span/*.c')
src += Glob('./widgets/spinbox/*.c')
src += Glob('./widgets/spinner/*.c')
src += Glob('./widgets/tabview/*.c')
src += Glob('./widgets/tileview/*.c')
src += Glob('./widgets/win/*.c')
CPPPATH = [cwd]
CPPPATH += [cwd + '/layouts']
CPPPATH += [cwd + '/layouts/grid']
CPPPATH += [cwd + '/layouts/flex']
CPPPATH += [cwd + '/themes']
CPPPATH += [cwd + '/themes/default']
CPPPATH += [cwd + '/themes/basic']
CPPPATH += [cwd + '/themes/mono']
CPPPATH += [cwd + '/widgets']
CPPPATH += [cwd + '/widgets/animimg']
CPPPATH += [cwd + '/widgets/calendar']
CPPPATH += [cwd + '/widgets/chart']
CPPPATH += [cwd + '/widgets/colorwheel']
CPPPATH += [cwd + '/widgets/imgbtn']
CPPPATH += [cwd + '/widgets/keyboard']
CPPPATH += [cwd + '/widgets/led']
CPPPATH += [cwd + '/widgets/list']
CPPPATH += [cwd + '/widgets/meter']
CPPPATH += [cwd + '/widgets/msgbox']
CPPPATH += [cwd + '/widgets/span']
CPPPATH += [cwd + '/widgets/spinbox']
CPPPATH += [cwd + '/widgets/spinner']
CPPPATH += [cwd + '/widgets/tabview']
CPPPATH += [cwd + '/widgets/tileview']
CPPPATH += [cwd + '/widgets/win']
# 因为是使用 keil 编译,所以要加上这句话
LOCAL_CCFLAGS = ' --c99 --gnu -g -W'
group = DefineGroup('lvgl', src, depend = [], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS)
Return('group')
到这里,可以使用 scons --target=mdk5 来生成 keil 工程,然后编译一次,如果编译通过,那就移植完成了,后面就是初始化了。
四、lvgl 初始化
对于 LVGL 的初始化,在 RT-Thread 中创建一个线程就可以了。
对于 LVGL 心跳来说,在 RT-Thread 中创建一个软定时器就可以了。(注意内核要开启软定时器线程)
其他的嘛,暂时没管。
初始化完成后,就可以使用 demo 命令来运行 demo 了。
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <fal.h>
#include <dfs_fs.h>
#include <dfs_posix.h>
#include <drv_lcd.h>
#include <lvgl.h>
/* defined the LED0 pin: PE7 */
#define LED0_PIN GET_PIN(E, 7)
static rt_thread_t led_tid = RT_NULL;
static rt_thread_t lvgl_tid = RT_NULL;
static rt_timer_t lvgl_timer = RT_NULL;
#define MY_DISP_HOR_RES 240
static void led_thread_entry(void *parameter)
{
rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
while (1)
{
rt_pin_write(LED0_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED0_PIN, PIN_LOW);
rt_thread_mdelay(500);
}
}
int thread_sample(void)
{
led_tid = rt_thread_create("led",
led_thread_entry,
RT_NULL,
256, /* stack size */
25, /* priority */
5); /* time slice */
if (led_tid != RT_NULL)
rt_thread_startup(led_tid);
return 0;
}
/* 这个函数定义在 lcd_drv.c 文件中,因为它使用了一些 lcd 驱动提供的函数 */
extern void lcd_lvgl_draw(rt_uint16_t x1, rt_uint16_t y1, rt_uint16_t x2, rt_uint16_t y2, rt_uint16_t* color);
/**
* void lcd_lvgl_draw(rt_uint16_t x1, rt_uint16_t y1, rt_uint16_t x2, rt_uint16_t y2, rt_uint16_t* color)
* {
* rt_uint16_t i,j;
* rt_uint16_t width = x2 - x1 + 1; /* 得到填充的宽度 */
* rt_uint16_t height = y2 - y1 + 1; /* 高度 */
*
* lcd_address_set(x1,y1,x2,y2);
* rt_pin_write(LCD_DC_PIN, PIN_HIGH);
*
* for(i = 0; i < height; i++)
* {
* for(j = 0; j < width; j++)
* {
* lcd_write_half_word(color[i*width+j]);
* }
* }
*
* }
**/
void my_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
lv_coord_t hres = disp_drv->rotated == 0 ? disp_drv->hor_res : disp_drv->ver_res;
lv_coord_t vres = disp_drv->rotated == 0 ? disp_drv->ver_res : disp_drv->hor_res;
if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1)
{
lv_disp_flush_ready(disp_drv);
return;
}
lcd_lvgl_draw(area->x1, area->y1, area->x2, area->y2, (rt_uint16_t*)color_p);
lv_disp_flush_ready(disp_drv);
}
lv_disp_draw_buf_t disp_buf;
lv_disp_drv_t disp_drv;
lv_disp_t *disp;
lv_color_t g_buf[MY_DISP_HOR_RES * 10];
static void lvgl_thread_entry(void *parameter)
{
/* lvgl 库初始化 */
lv_init();
/* 显示缓冲区 */
lv_disp_draw_buf_init(&disp_buf, g_buf, NULL, MY_DISP_HOR_RES * 10);
/* 在 LVGL 中注册显示设备驱动程序 */
lv_disp_drv_init(&disp_drv);
disp_drv.draw_buf = &disp_buf;
disp_drv.flush_cb = my_flush_cb;
disp_drv.hor_res = 240;
disp_drv.ver_res = 240;
disp = lv_disp_drv_register(&disp_drv);
while (1)
{
lv_task_handler();
rt_thread_mdelay(5); /* 官方手册是提议至少 5 ms */
}
}
static void lvgl_timeout(void *parameter)
{
lv_tick_inc(10); /* 因为一个时钟是 10ms */
}
int lvgl_sample(void)
{
lvgl_tid = rt_thread_create("lvgl",
lvgl_thread_entry,
RT_NULL,
4096, /* stack size */
12, /* priority */
5); /* time slice */
if (lvgl_tid != RT_NULL)
rt_thread_startup(lvgl_tid );
lvgl_timer = rt_timer_create("lvgl_timer",
lvgl_timeout,
RT_NULL,
1, /* 超时时间,单位是时钟节拍 */
RT_TIMER_FLAG_PERIODIC);
if (lvgl_timer != RT_NULL)
rt_timer_start(lvgl_timer );
return 0;
}
void fs_init(void)
{
fal_init();
fal_blk_device_create("filesystem");
if (dfs_mount("filesystem", "/", "elm", 0, 0) != 0)
{
if(dfs_mkfs("elm", "filesystem") == 0)
{
if (dfs_mount("filesystem", "/", "elm", 0, 0) != 0)
{
rt_kprintf("file system initialization failed!\n");
}
}
}
if (opendir("/mnt") == RT_NULL)
{
if (mkdir("mnt", 0x777) == -1)
return;
}
if(rt_device_find("sd0") == RT_NULL)
{
rt_kprintf("failed to find sd card device.\n");
return;
}
if (dfs_mount("sd0", "/mnt", "elm", 0, 0) != RT_EOK)
{
rt_kprintf("sd card mount to '/mnt' failed!\n");
}
}
/* 这个是官方例程,代码路径为:https://github.com/lvgl/lvgl/blob/master/examples/widgets/label/lv_example_label_1.c */
void demo(void)
{
lv_obj_t * label1 = lv_label_create(lv_scr_act());
lv_label_set_long_mode(label1, LV_LABEL_LONG_WRAP); /*Break the long lines*/
lv_label_set_recolor(label1, true); /*Enable re-coloring by commands in the text*/
lv_label_set_text(label1, "#0000ff Re-color# #ff00ff words# #ff0000 of a# label, align the lines to the center "
"and wrap long text automatically.");
lv_obj_set_width(label1, 150); /*Set smaller width to make the lines wrap*/
lv_obj_set_style_text_align(label1, LV_TEXT_ALIGN_CENTER, 0);
lv_obj_align(label1, LV_ALIGN_CENTER, 0, -40);
lv_obj_t * label2 = lv_label_create(lv_scr_act());
lv_label_set_long_mode(label2, LV_LABEL_LONG_SCROLL_CIRCULAR); /*Circular scroll*/
lv_obj_set_width(label2, 150);
lv_label_set_text(label2, "It is a circularly scrolling text. ");
lv_obj_align(label2, LV_ALIGN_CENTER, 0, 40);
}
MSH_CMD_EXPORT(demo, demo);
int main(void)
{
fs_init();
thread_sample();
lvgl_sample();
return RT_EOK;
}
五、实际运行效果
版权声明:本文为CSDN博主「Zeepunt」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/h451884098/article/details/119086173
暂无评论