前言
移植了好多天,过程真是痛苦,功夫不负有心人,移植成功的时候是真的爽。
网上资料看了好多,视频一遍遍看配置,用的屏幕不同,方法各异吧。
LVGL是一个免费的开源图形库,提供了创建嵌入式GUI所需的一切,具有易于使用的图形元素、漂亮的视觉效果和低内存占用。
移植视频主要参考的是正点原子的和普中的(开发板是普中的,可以对应上)。普中视频:【普中官方】LVGL-GUI嵌入式图形系统视频教程——F1和F4都适用
移植准备
手里有之前吃灰很久的普中STM32F103ZET6的开发板,就拿来做练习吧。
需要提前准备好的资料:LVGL8.3的源码,可执行的stm32f103zet6的触摸屏实验源码,基本定时器实验源码。
先将触摸屏实验代码烧录进板子,确保程序正常,屏幕可显示可触摸。
在移植前,先将基本定时器实验中的time添加到触摸屏实验代码中。
接下来就可以开始移植了。
移植
第一步,在触摸屏实验代码路径下新建lvgl文件夹。
第二步,将下载下来的lvgl源码文件中examples、src文件夹和lv_conf_template.h、lvgl.h复制到上面新建的文件夹中
第三步,将复制的lv_conf_tempate.h重命名为lv_conf.h,将example/portting文件下的lv_port_disp_template的.c和.h、lv_port_indev_template的.c和.h重命名为lv_port_disp和lv_port_indev.
第四步,在keil中打开工程文件,添加文件
在Groups中添加lvgl、lvgl_port、lvgl_demo(可加可不加);
然后给新建的分组中添加对应文件,lvgl下添加src中的文件,lvgl_port中添加examples\porting下的文件。
添加src文件时比较繁琐,需要有耐心,慢慢添加不要遗漏。
将提前放进去的time定时器文件也添加进工程中。
第五步,修改配置文件。
打开time.c文件,添加头文件“lvgl.h",在定时器回调函数中添加“心跳”函数lv_tick_inc(1);
。
将lv_conf.h打开,将if 0修改为if 1, 同时将文件名修改为LV_CONF_H。
这里的值也可以修改,原值太大运行占用内存太大。
修改lv_port_disp.c和.h文件,同样将#if 0修改为#if 1,添加自己对应的屏幕驱动头文件,并修改屏幕分辨率为自己屏幕大小的数值(这里的值范围大点也可以)。别忘了.h也要将#if 0修改为#if 1。
放开编译后.h文件可能会报错,将lvgl.h的包含路径修改一下。
接下来就可以修改显示相关代码了,先将lv_port_disp.c中这里的代码注释掉。
将这里的屏幕分辨率修改为屏幕实际的尺寸,我这里屏幕驱动中屏幕尺寸定义了结构体,所以这样用。
在这里修改填充函数为屏幕驱动中的填充函数。
屏幕我这里用的的是240*320的ILI9325,参考正点原子的配置视频配置完一直没有显示,后边在看普中的LVGL移植视频才发现针对这个屏幕要在lv_port_disp.c中添加这段代码(这里卡了好几天解决不了)。
void lcd_draw_fast_rgb_color(int16_t sx, int16_t sy, int16_t ex, int16_t ey, uint16_t *color)
{
uint16_t w = ex - sx + 1;
uint16_t h = ey - sy + 1;
LCD_Set_Window(sx, sy, w, h);
uint32_t drew_size = w * h;
for (uint32_t i = 0; i < drew_size; i++)
{
LCD_WriteData_Color(color[i]);
}
}
屏幕测试
在main.c中添加头文件“time.h",“lvgl.h”,“lv_port_disp.h”,
在main函数中添加初始化函数
TFTLCD_Init();
TIM3_Init(999, 71); // 1ms 这里根据自己定时器进行设置
lv_init();
lv_port_disp_init();
在while(1)循环中添加lv_task_handler();
在main函数中添加测试代码
lv_obj_t* switch_obj = lv_switch_create(lv_scr_act());
lv_obj_set_size(switch_obj, 90, 40);
// lv_obj_set_pos(switch_obj, 50, 40);
lv_obj_align(switch_obj, LV_ALIGN_CENTER, 0, 0);
屏幕上可以显示了。
添加触摸
和修改显示文件一样将lv_port_indev的#if 0修改为#if 1,添加触摸屏头文件"touch.h"。只保留触摸代码,其他代码一律暂时屏蔽掉。
static void touchpad_init(void);
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool touchpad_is_pressed(void);
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y);
lv_indev_t * indev_touchpad;
void lv_port_indev_init(void)
{
static lv_indev_drv_t indev_drv;
/*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);
}
static void touchpad_init(void)
{
/*Your code comes here*/
}
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static lv_coord_t last_x = 0;
static lv_coord_t last_y = 0;
/*Save the pressed coordinates and the state*/
if(touchpad_is_pressed()) {
touchpad_get_xy(&last_x, &last_y);
data->state = LV_INDEV_STATE_PR;
}
else {
data->state = LV_INDEV_STATE_REL;
}
/*Set the last pressed coordinates*/
data->point.x = last_x;
data->point.y = last_y;
}
/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
/*Your code comes here*/
tp_dev.scan(0);
if (tp_dev.sta & TP_PRES_DOWN)
{
return true;
}
return false;
}
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
/*Your code comes here*/
(*x) = tp_dev.x[0];
(*y) = tp_dev.y[0];
}
修改完触摸代码后,在main.c中添加头文件"lv_port_indev.h",在main函数中添加触摸初始化代码
TP_Init(); // 放在lv_init()之前
lv_port_indev_init(); // 放在lv_init()之后
到此LVGL就算移植完了,接下来就可以练习了。