目录
概述
1 硬件介绍
1.1 ST7796-LCD
1.2 MCU IO与LCD PIN对应关系
1.3 MCU IO与Touch PIN对应关系
2 N32G45x移植 LVGL
2.1 移植步骤
2.2 注意点
2.2.1 UI刷新函数
2.2.2 主函数中调用
3 LVGL的应用Demo
3.1 功能描述
3.2 代码实现
3.3 测试
N32G45XVL-STB之lvgl的应用实例
概述
本文主要介绍在N32G45XVL上移植lvgl应该注意的问题,其主要包括驱动程序接口的实现,UI刷新速度的优化。还编写一个简单的案例用以测试LVGL的UI显示和触摸功能的响应速度。相比与Contex-M3内核来说,基于Contex-M4内核的N32G45XVL在UI刷新速度上当然快了好多,当在用户体验上,任有值得优化的地方。
1 硬件介绍
1.1 ST7796-LCD
LCD的PIN引脚功能介绍
| 序号 | 模块引脚 | 引脚说明 | 
| 1 | VCC | 屏电源正 | 
| 2 | GND | 屏电源地 | 
| 3 | LCD_CS | 液晶屏片选控制信号,低电平有效 | 
| 4 | LCD_RST | 液晶屏复位控制信号,低电平复位 | 
| 5 | LCD_RS | 液晶屏命令/数据选择控制信号 高电平:数据,低电平:命令 | 
| 6 | SDI(MOSI) | SPI总线写数据信号(SD卡和液晶屏共用) | 
| 7 | SCK | SPI总线时钟信号(SD卡和液晶屏共用) | 
| 8 | LED | 液晶屏背光控制信号(如需要控制,请接引脚,如不需要控制,可以不接) | 
| 9 | SDO(MISO) | SPI总线读数据信号(SD卡和液晶屏共用) | 
| 10 | CTP_SCL | 电容触摸屏IIC总线时钟信号(无触摸屏的模块不需连接) | 
| 11 | CTP_RST | 电容触摸屏复位控制信号,低电平复位(无触摸屏的模块不需连接) | 
| 12 | CTP_SDA | 电容触摸屏IIC总线数据信号(无触摸屏的模块不需连接) | 
| 13 | CTP_INT | 电容触摸屏IIC总线触摸中断信号,产生触摸时,输入低电平到主控(无触摸屏的模块不需连接) | 
| 14 | SD_CS | SD卡片选控制信号,低电平有效(不使用SD卡功能,可不接) | 
实体LCD Port对应关系如下图所示

1.2 MCU IO与LCD PIN对应关系
| N32G45X PIN引脚 | LCD PIN引脚 | 
|---|---|
| PA7-MOSI | MOSI | 
| PA6-MISO | MISO | 
| PA5-SCK | SCK | 
| PD4 | CS | 
| PD5 | RST | 
| PD6 | RS | 
1.3 MCU IO与Touch PIN对应关系
| N32G45X PIN引脚 | touch PIN引脚 | 
|---|---|
| PB6 | I2C-SCK | 
| PB7 | I2C-SDA | 
| PB10 | INIT | 
| PB9 | RST | 
2 N32G45x移植 LVGL
2.1 移植步骤
关于LVGL的移植参考如下文档:
N32G45XVL-STB之移植LVGL(lvgl-8.2.0)-CSDN博客
2.2 注意点
2.2.1 UI刷新函数
笔者使用SPI接口类型的LCD,相比较有图形接口的LCD来说,其速度刷新速度函数比较慢的。为了尽可能加快UI的刷新速度,笔者做了如下优化:
1)重新写数据函数
代码26行: 计算刷新点个数
代码30行:设置窗口
代码31行:设置传递数据模式
代码34~39行:SPI模式写数据

源代码
static 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;
    uint32_t draw_size = w * h;
    uint32_t i;
    uint16_t tempcolor;
    LCD_SetWindows(sx, sy, ex, ey);
    LCD_RS_SET;
    LCD_CS_CLR;
    // set point value 
    for( i = 0; i < draw_size; i++)
    {
        tempcolor =  color[i];
        SPI_WriteByte(tempcolor>>8);
        SPI_WriteByte(tempcolor);
    }
    
    LCD_CS_SET;
}2.2.2 主函数中调用
在main函数中需要调用两个函数:
1)刷新UI函数: lv_task_handler()
2)触摸监测tick函数: lv_tick_inc(1)

源代码:
/**
 * @brief  Main program
 */
int main(void)
{
    uint32_t time_count;
    
    Board_Init();
    ui_init();
    usr_touchInit();
    LCD_DrvInit();
    lvgl_test();
    while (1)
    {
        // refresh tje UI interval: 300 ms 
        time_count =  get_timer1_countMs();
        if( (time_count % 50) == 0)
        {
        }
        if( (time_count % 5) == 0)
        {
            lv_tick_inc(1);
        }
        lv_task_handler();
    }
}
3 LVGL的应用Demo
3.1 功能描述
1)实现3个Button
2)通过Button改变数值
3.2 代码实现
#include "lv_mainstart.h"
#include "lvgl.h"
#include <stdio.h>
static const lv_font_t* font;       /* 定义字体 */
static lv_obj_t *label_speed;       /* 速度提示文本 */
static lv_obj_t *btn_speed_up;      /* 加速按钮 */
static lv_obj_t *btn_speed_down;    /* 减速按钮 */
static lv_obj_t *btn_stop;          /* 急停按钮 */
static int32_t speed_val = 0;       /* 速度值 */
/* 获取当前活动屏幕的宽高 */
#define scr_act_width() lv_obj_get_width(lv_scr_act())
#define scr_act_height() lv_obj_get_height(lv_scr_act())
/**
 * @brief  按钮回调
 * @param  *e :事件相关参数的集合,它包含了该事件的所有数据
 * @return 无
 */
static void btn_event_cb(lv_event_t * e)
{
    lv_obj_t *target = lv_event_get_target(e);      /* 获取触发源 */
    if(target == btn_speed_up)                      /* 加速按钮 */
    {
        speed_val += 30;
    }
    else if(target == btn_speed_down)               /* 减速按钮 */
    {
        speed_val -= 30;
    }
    else if(target == btn_stop)                     /* 急停按钮 */
    {
        speed_val = 0;
    }
    lv_label_set_text_fmt(label_speed, "Speed : %d RPM", speed_val);    /* 更新速度值 */
}
/**
 * @brief  速度值提示标签
 * @param  无
 * @return 无
 */
static void lv_example_label(void)
{
    /* 根据活动屏幕宽度选择字体 */
    if (scr_act_width() <= 320)
    {
        font = &lv_font_montserrat_20;
    }
    else if (scr_act_width() <= 480)
    {
        font = &lv_font_montserrat_20;
    }
    else
    {
        font = &lv_font_montserrat_20;
    }
    label_speed = lv_label_create(lv_scr_act());                                    /* 创建速度显示标签 */
    lv_obj_set_style_text_font(label_speed, font, LV_PART_MAIN);                    /* 设置字体 */
    lv_label_set_text(label_speed, "Speed : 0 RPM");                                /* 设置文本 */
    lv_obj_align(label_speed, LV_ALIGN_CENTER, 0, -scr_act_height() / 3);           /* 设置标签位置 */
}
/**
 * @brief  加速按钮
 * @param  无
 * @return 无
 */
static void lv_example_btn_up(void)
{
    font = &lv_font_montserrat_18;
    btn_speed_up = lv_btn_create(lv_scr_act());                                     /* 创建加速按钮 */
    lv_obj_set_size(btn_speed_up, scr_act_width() / 4, scr_act_height() / 6);       /* 设置按钮大小 */
    lv_obj_align(btn_speed_up, LV_ALIGN_CENTER, -scr_act_width() / 3, 0);           /* 设置按钮位置 */
    lv_obj_add_event_cb(btn_speed_up, btn_event_cb, LV_EVENT_CLICKED, NULL);        /* 设置按钮事件 */
    lv_obj_t* label = lv_label_create(btn_speed_up);                                /* 创建加速按钮标签 */
    lv_obj_set_style_text_font(label, font, LV_PART_MAIN);                          /* 设置字体 */
    lv_label_set_text(label, "Speed +");                                            /* 设置标签文本 */
    lv_obj_set_align(label,LV_ALIGN_CENTER);                                        /* 设置标签位置 */
}
/**
 * @brief  减速按钮
 * @param  无
 * @return 无
 */
static void lv_example_btn_down(void)
{
    font = &lv_font_montserrat_18;
    btn_speed_down = lv_btn_create(lv_scr_act());                                   /* 创建加速按钮 */
    lv_obj_set_size(btn_speed_down, scr_act_width() / 4, scr_act_height() / 6);     /* 设置按钮大小 */
    lv_obj_align(btn_speed_down, LV_ALIGN_CENTER, 0, 0);                            /* 设置按钮位置 */
    lv_obj_add_event_cb(btn_speed_down, btn_event_cb, LV_EVENT_CLICKED, NULL);      /* 设置按钮事件 */
    lv_obj_t* label = lv_label_create(btn_speed_down);                              /* 创建减速按钮标签 */
    lv_obj_set_style_text_font(label, font, LV_PART_MAIN);                          /* 设置字体 */
    lv_label_set_text(label, "Speed -");                                            /* 设置标签文本 */
    lv_obj_set_align(label,LV_ALIGN_CENTER);                                        /* 设置标签位置 */
}
/**
 * @brief  急停按钮
 * @param  无
 * @return 无
 */
static void lv_example_btn_stop(void)
{
    font = &lv_font_montserrat_18;
    btn_stop = lv_btn_create(lv_scr_act());                                         /* 创建急停按钮 */
    lv_obj_set_size(btn_stop, scr_act_width() / 4, scr_act_height() / 6);           /* 设置按钮大小 */
    lv_obj_align(btn_stop, LV_ALIGN_CENTER, scr_act_width() / 3, 0);                /* 设置按钮位置 */
    lv_obj_set_style_bg_color(btn_stop, lv_color_hex(0xef5f60), LV_STATE_DEFAULT);  /* 设置按钮背景颜色(默认) */
    lv_obj_set_style_bg_color(btn_stop, lv_color_hex(0xff0000), LV_STATE_PRESSED);  /* 设置按钮背景颜色(按下) */
    lv_obj_add_event_cb(btn_stop, btn_event_cb, LV_EVENT_CLICKED, NULL);            /* 设置按钮事件 */
    lv_obj_t* label = lv_label_create(btn_stop);                                    /* 创建急停按钮标签 */
    lv_obj_set_style_text_font(label, font, LV_PART_MAIN);                          /* 设置字体 */
    lv_label_set_text(label, "Stop");                                               /* 设置标签文本 */
    lv_obj_set_align(label,LV_ALIGN_CENTER);                                        /* 设置标签位置 */
}
/**
 * @brief  LVGL演示
 * @param  无
 * @return 无
 */
void lv_mainstart(void)
{
    lv_example_label();             /* 速度提示标签 */
    lv_example_btn_up();            /* 加速按钮 */
    lv_example_btn_down();          /* 减速按钮 */
    lv_example_btn_stop();          /* 急停按钮 */
}
/* End of this file */
3.3 测试
点击按键改变数据


 



















