lvgl移植

lvgl配置&移植

  1. 硬件条件

    名称最低配置推荐配置
    处理器16,32,64 bit
    时钟>16MHz>48MHz
    ROM>64KB>180KB
    静态RAM>2KB>4KB
    Stack>2KB>8KB
    Heap>2KB>8KB
    显示缓存>1*行像素>10*行像素
    编译器C99及以上
  2. 准备工作

    基于lvgl v7.11.0进行移植,目前已经发布了lvgl8,
    注意lvgl 的大版本之间不兼容。

    一般选取稳定版本,即vx.xx.0 版本。

    LVGL开源库下载地址:https://github.com/lvgl/lvgl/releases/tag/v7.11.0

    LVGL官方Demo:https://github.com/lvgl/lv_examples/tree/v7.11.0

  3. 显示移植

    下载得到lvgl v7.11.0的目录如下:
    在这里插入图片描述
    其中,lvgl_conf_template.h是lvgl库的配置,里面有各种宏的定义。
    lvgl.h 中包含了lvgl库中的所有头文件。

    在项目工程文件下创建一个lvgl的文件夹,
    将lvgl v7.11.0的目录下的src文件夹、lv_conf_template.h、lvgl.h文件复制到lvgl文件夹,
    并将lv_conf_template.h改名为lv_conf.h,变成自己的配置文件,进行个性化的配置。

    在项目工程文件下再创建一个lvgl_driver的文件夹,存放lvgl的驱动部分。
    将lvgl v7.11.0的目录下./example/porting中的文件拷贝到lvgl_driver文件夹。
    其中disp为显示驱动,indev为交互驱动,fs为文件系统驱动。
    将文件名中的_template去掉。
    在这里插入图片描述

    打开每一个上述驱动文件,将其中的条件编译```#if 0``使能,以及修改部分名称。

    对于.c文件

        /**
        * @file lv_port_disp_templ.c
        *
        */
    
        /*Copy this file as "lv_port_disp.c" and set this value to "1" to enable content*/
        #if 0       //**将这里的 0 改成  1***
    
        /*********************
        *      INCLUDES
        *********************/
        #include "lv_port_disp_template.h"  //将这里的头文件名称去掉 _template
    
    

    对于.h 文件

        /**
        * @file lv_port_disp_templ.h
        *
        */
    
        /*Copy this file as "lv_port_disp.h" and set this value to "1" to enable content*/
        #if 0       //将这里的 0 改成 1
    
        #ifndef LV_PORT_DISP_TEMPL_H   //将这里的_TEMPL去掉,不去问题也不大
        #define LV_PORT_DISP_TEMPL_H   //将这里的_TEMPL去掉
    
        #ifdef __cplusplus
        extern "C" {
        #endif
    

    回到上述配置文件 lvgl_conf.h,同样需要将其条件编译```#if 0``使能。

    在这个文件中,可以根据自己的屏幕配置屏幕的水平像素、垂直像素、颜色色深等(查找 LV_HOR_RES_MAX、LV_VER_RES_MAX、LV_COLOR_DEPTH进行修改)。

    还可以配置数据堆的大小(LV_MEM_SIZE),是否使用GPU(LV_USE_GPU,单片机一般没有GPU,所以改为0不使用)、是否使用文件系统(LV_USE_FILESYSTEM)。

    可以再仔细查看本配置文件配置了哪些内容,根据自己需求进行修改。

    在使用lvgl前,需要对lvgl进行初始化,需要添加lv_init();

        #include "lvgl.h"
        #include "lv_port_indev.h"
        #include "lv_port_disp.h"
        int main(void)
        {	
            lv_init();              //初始化lvgl
            lv_port_disp_init();    //注册显示设备
            lv_port_indev_init();   //注册交互设备,支持键盘、触摸屏、按键、编码器等
            //lv_port_fs_init();    //初始化文件系统
            //根据需求自行添加
        }
    

    在进行显示前,需要注册显示设备,即添加lv_port_disp_init();

    lv_port_disp_init();函数中,会对屏幕进行初始化,
    disp_init();,我们需要根据自己的屏幕在这个函数中添加屏幕的初始化函数,例如ILI9341_Init();对LCD屏幕的显示驱动进行初始化。

    在下面lvgl提供了三个显示缓冲区的模板,根据需要选择一个模板即可。
    实际只需要在disp_drv.buffer = &draw_buf_dsc_1;修改1或2或3。

    1为10行的一个buffer,2为10行的双buffer,3为所有像素点的双buffer。

    3最占用RAM,但显示效果最好。

    disp_drv.hor_res = 480;disp_drv.ver_res = 320;也修改为对应屏幕大小的像素。
    我觉得直接删除这一段话也可,因为在lv_conf.h中我们已经设置过最大像素了。

        void lv_port_disp_init(void)
        {
            /*-------------------------
            * Initialize your display
            * -----------------------*/
            disp_init();
    
            /*-----------------------------
            * Create a buffer for drawing
            *----------------------------*/
    
            /* Example for 1) */
            static lv_disp_buf_t draw_buf_dsc_1;
            static lv_color_t draw_buf_1[LV_HOR_RES_MAX * 10];                          /*A buffer for 10 rows*/
            lv_disp_buf_init(&draw_buf_dsc_1, draw_buf_1, NULL, LV_HOR_RES_MAX * 10);   /*Initialize the display buffer*/
    
            /* Example for 2) */
            static lv_disp_buf_t draw_buf_dsc_2;
            static lv_color_t draw_buf_2_1[LV_HOR_RES_MAX * 10];                        /*A buffer for 10 rows*/
            static lv_color_t draw_buf_2_2[LV_HOR_RES_MAX * 10];                        /*An other buffer for 10 rows*/
            lv_disp_buf_init(&draw_buf_dsc_2, draw_buf_2_1, draw_buf_2_2, LV_HOR_RES_MAX * 10);   /*Initialize the display buffer*/
    
            /* Example for 3) */
            static lv_disp_buf_t draw_buf_dsc_3;
            static lv_color_t draw_buf_3_1[LV_HOR_RES_MAX * LV_VER_RES_MAX];            /*A screen sized buffer*/
            static lv_color_t draw_buf_3_2[LV_HOR_RES_MAX * LV_VER_RES_MAX];            /*An other screen sized buffer*/
            lv_disp_buf_init(&draw_buf_dsc_3, draw_buf_3_1, draw_buf_3_2, LV_HOR_RES_MAX * LV_VER_RES_MAX);   /*Initialize the display buffer*/
    
            /*-----------------------------------
            * Register the display in LVGL
            *----------------------------------*/
    
            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 = 480;
            disp_drv.ver_res = 320;
    
            /*Used to copy the buffer's content to the display*/
            disp_drv.flush_cb = disp_flush;
    
            /*Set a display buffer*/
            disp_drv.buffer = &draw_buf_dsc_1;
    
        #if LV_USE_GPU
            /*Optionally add functions to access the GPU. (Only in buffered mode, LV_VDB_SIZE != 0)*/
    
            /*Blend two color array using opacity*/
            disp_drv.gpu_blend_cb = gpu_blend;
    
            /*Fill a memory array with a color*/
            disp_drv.gpu_fill_cb = gpu_fill;
        #endif
    
            /*Finally register the driver*/
            lv_disp_drv_register(&disp_drv);
        }
    

    LVGL基于绘制每一个像素点来实现整个UI的绘制,

    所以在移植的时候还需要将绘制一个像素点的屏幕驱动函数提供给 lvgl。

    例如:put_px(x, y, *color_p)

    改程序需要添加在static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)函数中,

    即前面注册屏幕显示的时候有一个结构体成员disp_drv.flush_cb = disp_flush;

    该函数会刷新屏幕显示。

    我在移植的时候,显示驱动函数只有绘制像素点,不带有颜色,所以我需要先设置画笔颜色,
    再调用绘制函数进行一个点的绘制。

    cplor_p是一个指针,由于我的设置颜色的函数需要一个u16类型的变量,
    所以先将其强制转换成 ((u16*) color_p)的指针,再通过指针取数据*((u16*) color_p)后强制转换成(u16) *((u16*) color_p)类型的数据(RGB565)。

        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*/
    
            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, *color_p)*/
                    LCD_SetTextColor( ((uint16_t) *((u16*)color_p)) );
                    ILI9341_SetPointPixel( (int16_t) x, (int16_t) y );
                color_p++;
                }
            }
    
            /* IMPORTANT!!!
            * Inform the graphics library that you are ready with the flushing*/
            lv_disp_flush_ready(disp_drv);
        }
    
  4. 初始化lvgl

    注意在"lv_port_disp.h"中声明对应的初始化函数。

    在定时器中断中添加lvgl的计时节拍lv_tick_inc(1);
    1ms定时器中断,lvgl计时加1。

    这样基本上显示的移植就完成了。

  5. 交互移植

    lvgl的交互驱动在"lv_port_indev.h"和"lv_port_indev.c"中,使能这两个文件。
    交互系统的注册在lv_port_indev_init();函数
    lvgl提供了很多交互输入设备,有Touchpad、Mouse、Keypad、Encoder、Button。
    在使用的时候初始化对应的交互设备和结构体即可。
    还没实现交互,努力中。

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

    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);

   /*------------------
    * Mouse
    * -----------------*/

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

   /*Register a mouse input device*/
   lv_indev_drv_init(&indev_drv);
   indev_drv.type = LV_INDEV_TYPE_POINTER;
   indev_drv.read_cb = mouse_read;
   indev_mouse = lv_indev_drv_register(&indev_drv);

   /*Set cursor. For simplicity set a HOME symbol now.*/
   lv_obj_t * mouse_cursor = lv_img_create(lv_disp_get_scr_act(NULL), NULL);
   lv_img_set_src(mouse_cursor, LV_SYMBOL_HOME);
   lv_indev_set_cursor(indev_mouse, mouse_cursor);

   /*------------------
    * Keypad
    * -----------------*/

   /*Initialize your keypad or keyboard if you have*/
   keypad_init();

   /*Register a keypad input device*/
   lv_indev_drv_init(&indev_drv);
   indev_drv.type = LV_INDEV_TYPE_KEYPAD;
   indev_drv.read_cb = keypad_read;
   indev_keypad = lv_indev_drv_register(&indev_drv);

   /* Later you should create group(s) with `lv_group_t * group = lv_group_create()`,
    * add objects to the group with `lv_group_add_obj(group, obj)`
    * and assign this input device to group to navigate in it:
    * `lv_indev_set_group(indev_keypad, group);` */

   /*------------------
    * Encoder
    * -----------------*/

   /*Initialize your encoder if you have*/
   encoder_init();

   /*Register a encoder input device*/
   lv_indev_drv_init(&indev_drv);
   indev_drv.type = LV_INDEV_TYPE_ENCODER;
   indev_drv.read_cb = encoder_read;
   indev_encoder = lv_indev_drv_register(&indev_drv);

   /* Later you should create group(s) with `lv_group_t * group = lv_group_create()`,
    * add objects to the group with `lv_group_add_obj(group, obj)`
    * and assign this input device to group to navigate in it:
    * `lv_indev_set_group(indev_encoder, group);` */

   /*------------------
    * Button
    * -----------------*/

   /*Initialize your button if you have*/
   button_init();

   /*Register a button input device*/
   lv_indev_drv_init(&indev_drv);
   indev_drv.type = LV_INDEV_TYPE_BUTTON;
   indev_drv.read_cb = button_read;
   indev_button = lv_indev_drv_register(&indev_drv);

   /*Assign buttons to points on the screen*/
   static const lv_point_t btn_points[2] = {
           {10, 10},   /*Button 0 -> x:10; y:10*/
           {40, 100},  /*Button 1 -> x:40; y:100*/
   };
   lv_indev_set_button_points(indev_button, btn_points);
}
  1. 运行lvgl

    #include "lvgl.h"
    #include "lv_port_indev.h"
    #include "lv_port_disp.h"
    //其他所需要的头文件
    int main(void)
    {	
        lv_init();              //初始化lvgl
        lv_port_disp_init();    //注册显示设备
        lv_port_indev_init();   //注册交互设备,支持键盘、触摸屏、按键、编码器等
        //lv_port_fs_init();    //初始化文件系统
        //根据需求自行添加
    
        while ( 1 )
        {
            lv_task_handler();
            indev_read();//根据自己设备编写,交互设备输入数据读取,例如:触摸屏坐标,按钮,编码器等
        }
    }
    
    

lvgl输入设备

Encoder

使用Encoder,需要object添加到group

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值