#GUI_GUIDER使用

一、GUI_GUIDER

1.是NXP的一款用于LVGL设计的工具,图形化设计,移植到LVGL非常简单。

2.注意每个版本的GUI_GUIDER只支持两个版本的LVGL

******下面给出的这个网盘的GUI_GUIDER支持的是V8.2.0V7.10.1两个版本

二、GUI_GUIDER下载

1.官网(需要NXP账号)

图形用户界面指南 |恩智浦半导体 (nxp.com)icon-default.png?t=N7T8https://www.nxp.com/design/design-center/software/development-software/gui-guider:GUI-GUIDER

2.ARM论坛老哥网盘

Gui-Guider-Setup-1.4.1-GA.exe_免费高速下载|百度网盘-分享无限制 (baidu.com)icon-default.png?t=N7T8https://pan.baidu.com/s/11AV-Qt7V2zgIOMNFUlVtKg提取码:6lj0

3.安装

正常安装就行,路径别太深,不要有中文。

三、创建一个工程

四、完成一个UI界面 

五、移植到KEIL

 1.打开编译后生成文件的位置

2.复制custon和generated文件夹到keil工程中,将其存放进入一个lvgl_app文件夹 

3.在keil中在LVGL_APP中将刚才拷贝的文件夹中的所有C文件加入

4.将路径加入 

5.加入以下代码编译下载

#include "system.h"
#include "SysTick.h"
#include "usart.h"
#include "tftlcd.h"
#include "touch.h"
#include "time.h"

#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
//#include "lv_demo_keypad_encoder.h"
#include "gui_guider.h"
#include "events_init.h"

lv_ui guider_ui;

int main()
{
	u8 i=0;
	u8 key;
	u16 penColor = BLUE;
	
	SysTick_Init(72);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组
	USART1_Init(115200);
	TFTLCD_Init();			//LCD初始化
	LCD_Display_Dir(1);
	TP_Init();
//	tp_dev.init();
	TIM4_Init(200,360-1);  //定时1ms
	
	
	lv_init();
	lv_port_disp_init();  // lvgl显示接口初始化,放在lv_init()的后面
	lv_port_indev_init(); // lvgl输入接口初始化,放在lv_init()的后面
//	lv_demo_keypad_encoder();
  setup_ui(&guider_ui);
//  events_init(&guider_ui);

	while(1)
	{	

		 lv_task_handler(); // lvgl的事务处理
		 tp_dev.scan(0);
     delay_ms(100);
	
	}
}


void TIM4_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM4,TIM_IT_Update))
	{
		TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
		lv_tick_inc(1);//lvgl的1ms中断
	}
		
}

六、事件触发(实现交互)(已证实无法在MCU运行,直接看七)

1.参考博客

【LVGL学习手札】(1)VSCode+GuiGuider搞定UI设计与调试_lvgl界面编辑器-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/coolouba/article/details/130459069

2.创建界面

拖入一个按钮和两个标签,实现一个三个任务:

(1)按钮短按其中一个标签显示数值加1

(2)按钮长按标签显示数值开始减

(3)按钮按下时另外一个标签显示按钮状态

注意按钮默认的名字为btn_1 ,这个名字应该是可以更改的,后面程序只需要改一下就可以

标签也向上述方式命名label_1label_2

3.代码修改

主要修改custom.c

主要逻辑就是添加一个按钮事件,判断按钮事件类型为什么再做出对应的操作

//按键回调函数
static void btn_cb(lv_event_t* e)
{
    static int cnt = 0; //静态计数值
    lv_event_code_t code = lv_event_get_code(e);    //获取按键值
    switch (code)
    {
    case LV_EVENT_SHORT_CLICKED:    //单击加计数
        cnt++;  
        lv_label_set_text_fmt(guider_ui.screen_label_2, "Button Status: %s","CLICKED"); //设置文本标签
        break;
    case LV_EVENT_LONG_PRESSED:
    case LV_EVENT_LONG_PRESSED_REPEAT:  //长按减计数
        lv_label_set_text_fmt(guider_ui.screen_label_2, "Button Status: %s", "LONG PRESSED"); //设置文本标签
        cnt--;
        break;
    default:
        break;
    }
    lv_label_set_text_fmt(guider_ui.screen_label_1, "%d", cnt); //设置文本标签
}

void custom_init(lv_ui *ui)
{
    /* Add your codes here */
    lv_obj_add_event_cb(guider_ui.screen_btn_1, btn_cb, LV_EVENT_ALL, NULL);    //绑定回调函数
}

修改代码找到生成的文件就行,修改custom.c就行,修改完成之后再进入到GUI GUIDER进行模拟运行看效果。

4.运行效果

七、事件触发更新(7月28日)(正确的事件交互)

1.之前的方式有问题

上面“六”说的是交互的功能写在custom.c里面就行,但是后面发现这个custom.c只能加入第一个screen里面的事件,其他页面screen的事件无法加入,运行仿真会出错。

2.解决办法(其他屏幕的事件)

(1)选中控件添加事件

选择触发方式和作用对象,再自定义代码,在code中添加代码,比如我这里的逻辑就是screen_1中的sw_1值改变时,screen_1中的led_1电平翻转。

(2)在code中添加的代码

lv_led_toggle(guider_ui.screen_1_led_1);

(3)具体API参考网址:

事件(Events) — LVGL_Chinese_Documents 文档 (lvgl-chinese-doc.readthedocs.io)icon-default.png?t=N7T8https://lvgl-chinese-doc.readthedocs.io/zh-cn/latest/overview/event.html

如果说能够加入在custom.c中,那么代码应该为

// SPDX-License-Identifier: MIT
// Copyright 2020 NXP

/**
 * @file custom.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include <stdio.h>
#include "lvgl.h"
#include "custom.h"

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/

/**********************
 *  STATIC VARIABLES
 **********************/

/**
 * Create a demo application
 */
//按键回调函数
//按键回调函数
static void btn_cb(lv_event_t* e)
{
    static int cnt = 0; //静态计数值
    lv_event_code_t code = lv_event_get_code(e);    //获取按键值
    switch (code)
    {
    case LV_EVENT_SHORT_CLICKED:    //单击加计数
        cnt++;  
        lv_label_set_text_fmt(guider_ui.screen_label_2, "Button Status: %s","CLICKED"); //设置文本标签
        break;
    case LV_EVENT_LONG_PRESSED:
    case LV_EVENT_LONG_PRESSED_REPEAT:  //长按减计数
        lv_label_set_text_fmt(guider_ui.screen_label_2, "Button Status: %s", "LONG PRESSED"); //设置文本标签
        cnt--;
        break;
    default:
        break;
    }
    lv_label_set_text_fmt(guider_ui.screen_label_1, "%d", cnt); //设置文本标签
}


/*界面:screen_1
 *控件: sw_1
 *受控件: led_1
 *事件:通过sw_1拨动开关led_1灯
 */
static void sw1_led1_cb(lv_event_t* e)
{
	lv_event_code_t code = lv_event_get_code(e);
	if(code==LV_EVENT_VALUE_CHANGED)
	 lv_led_toggle(guider_ui.screen_1_led_1); 
} 

void custom_init(lv_ui *ui)
{
    /* Add your codes here */
 	lv_obj_add_event_cb(guider_ui.screen_btn_1, btn_cb, LV_EVENT_ALL, NULL);    //绑定回调函数
    lv_obj_add_event_cb(guider_ui.screen_1_sw_1,sw1_led1_cb,LV_EVENT_VALUE_CHANGED,NULL);  //screen_1中的sw_1切换触发事件
}

(4)按这种方法生成的代码

在generated/event_init.c中有这个事件处理函数,所以也给了我们一个启示:如果我们向让单片机与其交互,可以在这里加入自己的代码(需要遵守编写规范)

static void screen_1_sw_1_event_handler(lv_event_t *e)
{
	lv_event_code_t code = lv_event_get_code(e);
	switch (code)
	{
	case LV_EVENT_VALUE_CHANGED:
	{
		lv_led_toggle(guider_ui.screen_1_led_1);
	}
		break;
	default:
		break;
	}
}

 (5)规范写法

 上面虽然说可以在event_init.c中加入自己的代码,但是用户主要的函数建议还是写到custom.c中,所以custom.c主要用于处理其他函数和第一个页面的事件

八、一些记录

1.读取SW的状态来决定LED的亮与灭

	//SW_1开就打开led_1,关就关闭led_1
    if(lv_obj_has_state(guider_ui.screen_1_sw_1,LV_STATE_CHECKED))
       lv_led_on(guider_ui.screen_1_led_1); 
    else
	   lv_led_off(guider_ui.screen_1_led_1); 

2.读取滑动条的值显示在标签上面

//获取滑块值
uint32_t value=lv_slider_get_value(guider_ui.screen_2_slider_1);
lv_label_set_text_fmt(guider_ui.screen_2_label_1, "%d", value); //设置文本标签

3. 读取spinbox的值显示在标签上面

uint8_t value=lv_spinbox_get_value(guider_ui.screen_spinbox_1);
lv_label_set_text_fmt(guider_ui.screen_label_1, "%d",value);

这里spinbox如果设置为有小数位读取出来的值完全不对,当设置没有小数位时读出来的数据则正确。

4.图表绘制折线图

uint8_t data[10]={0};
static lv_chart_series_t * chart_clean_ser;   //用于记录序列号
if(chart_clean_ser!=NULL)     //不是初次创建
   lv_chart_remove_series(guider_ui.screen_chart_1,chart_clean_ser);   //移除之前的连续折线
lv_chart_set_point_count(guider_ui.screen_chart_1, 6);
lv_chart_series_t * screen_chart_1_0 = lv_chart_add_series(guider_ui.screen_chart_1, lv_color_make(0x2c, 0xc9, 0x53), LV_CHART_AXIS_PRIMARY_Y);
lv_chart_set_point_count(guider_ui.screen_chart_1, 10);    //设置折线点数
chart_clean_ser=screen_chart_1_0;      //记住序列号(方便后面删除进行下一次绘制图形)
for(uint8_t i=0;i<10;i++)	
{
	data[i]=rand()%100;             //余100是因为设置的值范围是(0~100)
  	lv_chart_set_next_value(guider_ui.screen_chart_1, screen_chart_1_0, data[i]);    //像链表一样插入数据点
}

这里用随机数当作数据绘制折线图 ,第六句代码是到GUIGUIDER生成的代码中复制的,主要是为了保持格式色彩一致性。(在GUIGUIDER屏幕初始化函数中去找,先图形界面手动添加一条数据线,看它的添加连续折线的代码)

运行效果:

5.图表绘制折线图修正

上述4.的图表绘制折线图的方式有一个问题:如果绘制过折线,切换屏幕后,回到本屏幕再次打点会出错,主要是因为屏幕切换回来初始化之后,屏幕上没有折线,而下面这句代码会根据

if(chart_clean_ser!=NULL)     //不是初次创建
   lv_chart_remove_series(guider_ui.screen_chart_1,chart_clean_ser);   //移除之前的连续折线

 chart_clean_ser是否为空来进行移除,这个变量定义为static类型,屏幕切换回来后虽然没有折线,但是chart_clean_ser变量不为NULL,就会触发移除函数,这样就会出错,我们用一个全局变量来记录是否有切换屏幕的记录,如果切换了屏幕则不要触发移除函数。这个全局变量为了方便管理定义在custom.c中。(同时如果我们想要知道某一个事件是否触发也可以在custom.c中定义一个全局变量,然后在触发事件的代码中对全局变量进行赋值,再在主函数中检查这个全局变量的值即可知道事件有没有触发。)下面是修改后的代码:

uint8_t data[10]={0};
static lv_chart_series_t * chart_clean_ser;   //用于记录序列号
extern bool avoid_screenchange_to_chartclean_error;
if((chart_clean_ser!=NULL)&&(avoid_screenchange_to_chartclean_error==0))     //不是初次创建并且不是处于刚初始化屏幕阶段
    lv_chart_remove_series(guider_ui.screen_chart_1,chart_clean_ser);
else if(avoid_screenchange_to_chartclean_error==1)      //有切换屏幕,屏幕上面没有内容,这次不能清屏幕上的折线,否则出错
    avoid_screenchange_to_chartclean_error=0;                                //屏幕完成初始化清空标志位
lv_chart_set_point_count(guider_ui.screen_chart_1, 6);
lv_chart_series_t * screen_chart_1_0 = lv_chart_add_series(guider_ui.screen_chart_1, lv_color_make(0x2c, 0xc9, 0x53), LV_CHART_AXIS_PRIMARY_Y);
lv_chart_set_point_count(guider_ui.screen_chart_1, 10);    //设置折线点数
chart_clean_ser=screen_chart_1_0;      //记住序列号(方便后面删除进行下一次绘制图形)
for(uint8_t i=0;i<10;i++)	
{
	data[i]=rand()%100;             //余100是因为设置的值范围是(0~100)
  	lv_chart_set_next_value(guider_ui.screen_chart_1, screen_chart_1_0, data[i]);    //像链表一样插入数据点
}

定义在custom.c中 :

bool avoid_screenchange_to_chartclean_error=0;  //防止屏幕初始化而chart_clean_ser不为NULL

6.下拉列表(下拉框)选中文本显示在标签上

char buf[5]={0};
lv_dropdown_get_selected_str(guider_ui.screen_3_ddlist_1,buf,sizeof(buf));
lv_label_set_text_fmt(guider_ui.screen_3_label_1, "%s",buf); 

九、补坑

1.经过实践发现如果将事件函数添加到custom.c中,切换屏幕时删除屏幕会将事件删除,再次回到这个屏幕就不会再触发这个页面的事件,所以事件函数不要写在custom.c中,按“七”的方法来。(只运行在PC模拟器时,后面发现运行在MCU上根本不能正常运行)

2.下载到MCU中后发现第六种办法根本无法在MCU上正常运行,而第七种可以。

十、关于GUI-GUIDER移植到KEIL的一些问题

1.编码

在一个例子中移植之后出现以下报错

lvgl_app\generated\setup_scr_screen.c(442): error:  #8: missing closing quote

解决参考网址:keil5 出现error: #8: missing closing quote 解决办法-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_64562382/article/details/136821878

按这篇博客的说法应该是UTF-8编码导致的编码错误,在如下框中加入以下内容可解决问题

--no-multibyte-chars

  • 24
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值