STM32移植LVGL+旋转编码器接口对接

写在前面:本菜鸟结合了许多大佬的文章,成功实现了基于LVGL的GUI设计,小开心~浅浅记录一下!~

本文以单片机STM32F103VET6为核心,利用ST7796芯片驱动分辨率为480*320的LCD液晶屏模块,移植LVGL,对接显示接口,对接外部接口——旋转编码器,完成以上两步,就可以实现LVGL的显示和控制啦!Emmm可以开始你的创作了!~

一、显示接口对接

具体步骤:

下载源码文件lvgl-master8.3进行移植

这里我们以LCD显示工程为基础进行移植。

1.新建四个组,分别存放源文件(source)、配置文件(config)、接口层文件(port)、示例(app)。

2.添加文件,lvgl/src下的.c文件移到source中,lv.conf.h添加到config中,lv_port_xxx.c文件添加到port中,示例文件添加到app中。

3.添加路径,勾选C99,此时进行编译会有四个错误,因为C99的原因,在部分函数前要加static,否则会报错,再进行编译会发现还有一个错误:

解决方法是取消勾选Use MicroLIB,再编译就会发现零错误。

4.lv_conf.h配置:主要是一些宏定义,只需要修改一些宏定义即可进行一些定制配置,如显示器的宽度高度、色彩深度、DPI、提供给LVGL的空间等,可根据自己的需求打开即可使用。

5.修改lv_port_disp.c接口文件:

使能后开始对其进行配置,修改头文件名称并添加LCD头文件,添加两个宏,分别是屏幕的宽(480)和高(320)。

修改lv_port_disp_init()显示接口初始化函数,它是一个最顶层的初始化显示设备的函数。然后选择一种写缓存的方式及设置显示分辨,这里我们选择保留第一种写缓存的方式:只使用一个缓冲区


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

该文件内还有两个函数disp_init()和disp_flush()。在disp_init()中,需要提供屏幕的初始化代码,这里直接调用驱动成功的LCD模块初始化代码LCD_init()。接下来是disp_flush屏幕刷新函数,这个函数需要调用底层LCD的操作接口,这里调用一个画点的函数,因为屏幕是逐个绘制像素点,从而填充一块区域的,所以也可以直接调用一个绘制方形函数填充区域显示。


/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
    /*You code here*/
    LCD_Init();
}

/*Flush the content of the internal buffer the specific area on the display
 *You can use DMA or any hardware acceleration to do this operation in the background but
 *'lv_disp_flush_ready()' has to be called when finished.*/
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_DrawPoint(x,y,color_p->full);
            color_p++;
        }
    }
    /*IMPORTANT!!!
     *Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}

6.最后需要配置一个定时器为LVGL提供心跳,这里可以使用系统滴答定时器,也可以使用其他定时器配置,然后在主循环中调用lv_task_handler()函数,这样需要显示的内容才会实时更新到屏幕上,至此LVGL的显示配置完成。


    while(1)
    {
        lv_tick_inc(5);
        lv_task_handler();
        delay_ms(5);
    }

二、旋转编码器接口对接

首先在lv_port_indev.c的接口初始化中保留Encoder部分,在encoder_init()中编写旋转编码器相关的初始化代码,再指定用于读取按键状态的函数encoder_read,将旋转编码器注册到LVGL中。最后对encoder相关函数进行编写,主要是encoder_read,分为三种情形,分别是旋转编码器左旋、右旋和按下时对应控制界面的功能。


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;
    
    /*------------------
     * 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);`*/
    lv_group_t * group= lv_group_create();
    lv_indev_set_group(indev_encoder, group);

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

/*Initialize your keypad*/
static void encoder_init(void)
{
    /*Your code comes here*/
    Encoder_Init();
}

/*Will be called by the library to read the encoder*/
static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    static uint32_t last_key = 0;
    uint32_t act_key = Encoder_Scan(0);
    if(act_key != 0) {
        switch(act_key) {
            case 1:
                act_key = LV_KEY_ENTER;
                encoder_state = LV_INDEV_STATE_PR;    
                break;
            case 2:
                act_key = LV_KEY_LEFT;
                encoder_diff = -1;
                encoder_state = LV_INDEV_STATE_REL;
                break;
            case 3:
                act_key = LV_KEY_RIGHT;
                encoder_state = LV_INDEV_STATE_REL;
                encoder_diff = 1;
                break;
        }
        last_key = act_key;
    }
    else{
        encoder_diff = 0;
        encoder_state = LV_INDEV_STATE_REL;
        }
    data->key = last_key;
    data->enc_diff = encoder_diff;
    data->state = encoder_state;
    encoder_diff=0;
}


/*Call this function in an interrupt to process encoder events (turn, press)*/
static void encoder_handler(void)
{
    /*Your code comes here*/
    encoder_diff += 0;
    encoder_state = LV_INDEV_STATE_REL;

}

与其他输入设备接口不同的是,旋转编码器较特殊,光移植完还无法使用,如需使用还要创建“组”。这里引入“组”这一概念,当需要用键盘或者编码器来模拟按键控制对象时,就需要把控制对象添加进“组”。例如,如果一个旋钮被聚焦,当向左或向右旋转编码器时,旋钮的值会随之改变。这种操作的前提便是将输入设备与“组”关联起来,即通过lv_group_add_obj()函数将控件添加进“组”,才能实现编码器与LVGL接口对接和实现界面控制。但是需要注意的是,并非所有控件都能够加入“组”并且被使用。比如我们添加“标签”这个控件时,即使将它加入到“组”中,用编码器旋转聚焦时也不会切换到这个“标签”。

将所需控件加入“组”旋转编码器即可正常使用,即可完成编码器接口与LVGL的对接。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值