[笔记] 基于esp32s3用GUI-Guider-1.9.1-GA开发LVGL界面
基于esp32s3用GUI-Guider-1.9.1-GA开发LVGL界面用于485通讯
1. 准备措施
1.1.硬件准备
仓库内含视频地址, 配套的视频很简单, 不过够用了.仓库地址: 禾木科技/esp32-s3-4inch-001-sdk
-
使用的硬件是某宝买的一个方案板: [esp32s3蓝牙wifi板4寸RGB屏UI开发LVGL方案电容触摸st7701s驱动]
-
他们提供了驱动库, 有完整配套例程, 和视频讲解,很是方便, 不用关心屏幕的驱动和LVGL库的移植, 所以本文主要讲解使用.
-
缺点就是把驱动库的.c文件都打包加密了.不能观看学习,也不开源原理图,导致只能自己反推接线.
1.2.环境准备
关于ESP32S3的环境部署, 参考笔记: 【ESP】一小时速通入门笔记
- 使用ESP32S3作为主控, 关于环境配置可以看我之前的笔记.
1.3.工具准备
官网下载 GUI-Guider-1.9.1-GA
移植参考: GUI-Guider安装使用及项目移植(7.11版本)
- 仓库配套例程推荐的是
SquareLine_Studio
, 它收费, 试用只有1个月,但因为我的公司电脑, 电脑时间和网络时间不一致, 导致我安装后直接用不了,试了半天没成功, 也没找到破解版, 就放弃了… - 我搜了一下, 发现NXP有推出一款免费的
GUI-Guider
, 注册就可以用. - 注意
GUI-Guider
迭代了几个版本, 我看了一下:1.5.1
只支持v7
的LVGL
;1.6.1
支持v7
和v8
的LVGL
;1.9.1
支持v8
和v9
的LVGL
;
- 而且它不同版本直接是不能相互打开工程的!!!示意开始创建工程之前一定要确定使用哪个版本的软件, 避免后面要改, 更改就得重做了.
- 而且不同版本之间操作方式也有较大的差异性.
2.开始测试
2.1.测试LVGL
例程目录:
esp32-s3-4inch-001-sdk\examples\1.lvgl_v8
例程视频: esp32通用RGB驱动板开源lvgl V8.3.11程序下载及86盒方案演示
- 只需要将仓库的
components
和examples/1.lvgl_v8
拷贝到自己的新建文件夹即可,1.lvgl_v8
可以修改名字app_main
,只要和组件的相对路径不变即可; 类似下图, 我加了.git
管理和LVGL
工程文件,也放一起.
- 然后打开
esp-idf
终端,cd
切换目录,idf.py set-target {esp32s3}
切换芯片类型,idf.py build
编译文件.idf.py menuconfig
修改配置(默认不用,只是我想列从来),idf.py {-p COM8} flash
下载,idf.py {-p COM8} monitor
监听. 最后成功运行, 和视频介绍的一样.
- 使用
vscode
打开工程, 为了方便代码之间跳转查看, 添加.vscode/c_cpp_properties.json
文件, 在"configurations"
内添加"compileCommands": "${workspaceFolder}/build/compile_commands.json"
. 再编译一下, 没有问题. 速通成功, 下一步.
2.2. 替换GUI-Guider文件
参考笔记: LVGL使用GUI Guider配置STM32界面详细笔记教程
- 例程自带的是
SquareLine Studio
的代码文件, 和GUI-Guider
不通用, 需要修改. - 先打开软件
GUI-Guider-1.9.1-GA
,创建v8
工程: - 板子选择默认
Simulator
,模板选择一个例程SmartBuiding
,屏幕选择Custom
,尺寸填写480*480
;后续会围绕这个模板将LVGL的功能.
- 界面大体如下: 不同版本差别较大, 认准目前讲解的
1.9.1
版本
- 直接编译运行, 初次比较久, 过了一会就能看到弹窗, 可以试一下功能;
- 然后开始导出代码,选择放在esp32工程里的新建文件夹.
然后会导出2个文件夹,custom
和generated
, 然后将2个文件夹的路径添加到esp32编译文件配置CMakeLists.txt
中:
idf_component_register( SRC_DIRS".""gui_app/custom""gui_app/generated"INCLUDE_DIRS ".""gui_app/custom""gui_app/generated")
- 然后在
main.c
文件中直接添加代码即可:
...省略...
#include "gui_app/generated/gui_guider.h"
#include "gui_app/generated/events_init.h"
lv_ui guider_ui;
...省略...void app_main(void)
{...省略...lv_port_sem_take();setup_ui(&guider_ui);events_init(&guider_ui);lv_port_sem_give();
}
- 然后编译运行(
报错
), 就能看到板子上呈现一样的界面.唯一问题就是比较卡顿, 可能是因为算力不够,运行太慢.
2.3. 移植GUI-Guider时钟组件dclock
参考笔记: Gui-Guider1.8.1 数字时钟控件找不到定义,无法编译
-
上面的正常操作最后是会编译报错, 因为使用的这个gui工程使用了私有组件, 需要手动移植;
-
打开软件所在文件夹, 然后找到以下文件夹:
E:\NXP\GUI-Guider-1.9.1-GA\environment\template\project\v8\lvgl\src\extra\widgets
- 将文件夹复制到工程里, 记得添加esp32文件编译路径
idf_component_register( SRC_DIRS".""gui_app/custom""gui_app/dclock""gui_app/generated"INCLUDE_DIRS ".""gui_app/custom""gui_app/dclock""gui_app/generated")
- 然后找到这个esp32s3组件里的头文件
lvgl.h
, 添加一行头文件路径.
/*-----------------* EXTRAS*----------------*/
#include "src/extra/lv_extra.h"#include "../../../examples/app_main_s100/main/gui_app/dclock/lv_dclock.h"
/********************** DEFINES*********************/
- 然后回到
lv_dclock.c
和lv_dclock.h
,进行如下修改.
// lv_dclock.c:/********************** INCLUDES*********************/
#include "lv_dclock.h"
#if LV_USE_DCLOCK != 0
//注释掉原有的头文件
//#include "../../../core/lv_obj.h"
//#include "../../../misc/lv_assert.h"
//#include "../../../core/lv_group.h"
//#include "../../../draw/lv_draw.h"
//#include "../../../misc/lv_color.h"
//#include "../../../misc/lv_math.h"
//#include "../../../misc/lv_bidi.h"
//#include "../../../misc/lv_txt_ap.h"
//#include "../../../misc/lv_printf.h"
//#include "../../../widgets/lv_label.h"
- 宏定义
LV_USE_DCLOCK
和LV_DCLOCK_TEXT_SELECTION
的添加是因为又耦合了另一文件, 避免多余的移植, 就直接将用到的宏定义写在这里.
// lv_dclock.h: #ifndef LV_DCLOCK_H
#define LV_DCLOCK_H#ifdef __cplusplus
extern "C" {
#endif/********************** INCLUDES*********************/
//#include "../../../lv_conf_internal.h" //注释掉原有的lv_conf_internal.h文件//观察lv_conf_internal.h文件,选择需要的参数置位1
#define LV_USE_DCLOCK 1
#define LV_DCLOCK_TEXT_SELECTION 1#if LV_USE_DCLOCK != 0#include <stdarg.h>
#include <stdlib.h>
#include "lvgl.h" //我们自己的lvgl.h头文件,代替其原有调用的一些lvgl有文件
//#include "../../../core/lv_obj.h"
//#include "../../../font/lv_font.h"
//#include "../../../font/lv_symbol_def.h"
//#include "../../../misc/lv_txt.h"
//#include "../../../draw/lv_draw.h"
- 写在再编译应该就万无一失了, 可以正常运行下载了.
2.4. 测试RS485
官方指南: 通用异步接收器/发送器 (UART)
参考笔记: ESP32 单片机学习笔记 - 01 - gpio&ledc&uart
esp32自带例程地址:\Espressif\frameworks\esp-idf-v5.3.1\examples\peripherals\uart\uart_echo_rs485
参考笔记: 6.RS485模块发布esp32方案86盒温控器加入RS485通信控制
方案板自带例程地址:\esp32-s3-4inch-001-sdk\examples\6.RS485
- 先用方案板例程跑一下, 正常运行, 使用万用表蜂鸣档和查看手册描述知道, 板载自带的RS485接口的具体IO是IO4/5/6.
- 然后可以直接使用esp32自带的例程, 使用
idf.py menuconfig
修改默认配置,引脚和波特率.然后编译下载进去,得到和方案板例程一样的效果.
// 注意: 目标芯片上的某些引脚无法分配用于UART通信.
// 请参阅所选板和目标的文档, 以使用Kconfig配置引脚.
#define ECHO_TEST_TXD (CONFIG_ECHO_UART_TXD) // 目前板载的是IO6
#define ECHO_TEST_RXD (CONFIG_ECHO_UART_RXD) // 目前板载的是IO4// RS485半双工模式的 RTS 管理 DE / ~RE
#define ECHO_TEST_RTS (CONFIG_ECHO_UART_RTS) // 目前板载的是IO5
- 就可以把esp32例程里的代码移植到方案板例程上了,
因为方案板库自带的rs485组件功能很少, 不好打包使用, 所以重新实现, 屏幕驱动就用自带的组件. - 注意,将
/main/Kconfig.projbuild
文件的内容也移植, 它是规定idf.py menuconfig
配置的,可以方便修改配置, 具体的语法自行举一反三吧, 我不列举了.
menu "Echo RS485 Example Configuration"orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"config ECHO_UART_PORT_NUMint "UART port number"range 0 2 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3default 2 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3range 0 1default 0helpUART communication port number for the example.See UART documentation for available port numbers.config ECHO_UART_BAUD_RATEint "UART communication speed"range 1200 115200default 9600helpUART communication speed for Modbus example.config ECHO_UART_RXDint "UART RXD pin number"range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAXdefault 22 if IDF_TARGET_ESP32default 4 if !IDF_TARGET_ESP32helpGPIO number for UART RX pin. See UART documentation for more informationabout available pin numbers for UART.config ECHO_UART_TXDint "UART TXD pin number"range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAXdefault 23 if IDF_TARGET_ESP32default 6 if !IDF_TARGET_ESP32helpGPIO number for UART TX pin. See UART documentation for more informationabout available pin numbers for UART.config ECHO_UART_RTSint "UART RTS pin number"range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAXdefault 18 if IDF_TARGET_ESP32default 5 if !IDF_TARGET_ESP32helpGPIO number for UART RTS pin. This pin is connected to~RE/DE pin of RS485 transceiver to switch direction.See UART documentation for more information about available pinnumbers for UART.endmenu
-
使用esp32自带的rs485功能, 将
DE
引脚设置为RTS
功能引脚, 就可以在收发时自动切换使能, 免去控制逻辑. 作为主机使用很方便, 因为主机收发固定.从机的话就有点不一样,从机要考虑不发时一直收的情况. 自行判断要不要使用 -
软件流控: 如果硬件流控处于禁用状态,可使用函数
uart_set_rts()
和uart_set_dtr()
分别手动设置RTS
和DTR
信号电平。
// 设置RS485半双工模式
ESP_ERROR_CHECK(uart_set_mode(uart_num, UART_MODE_RS485_HALF_DUPLEX));
- 注意, 我目前遇到了2个未想明白的问题, 在收发函数前后使用打印函数, 老是容易死机重启. 其次就是, 这个
uart_read_bytes()
函数的超时时间, 是判断2次接收数据的时间差, 不能设置大, 不然会导致卡很久,将2次数据认为一次数据, 它居然不是按照uart_set_rx_timeout()
区分一次数据.可能还要另一个函数…
// 根据超时时间接收数据, 这里自行确保返回的长度是符合缓存大小的
uart_read_bytes(ECHO_UART_PORT, data, BUF_SIZE, pdMS_TO_TICKS(tick)); // 设置UART TOUT功能的读取超时
ESP_ERROR_CHECK(uart_set_rx_timeout(uart_num, ECHO_READ_TOUT));
3. 编辑界面
推荐中文英文手册网址: https://lvgl.100ask.net/master/intro/introduction.html#requirements
- 前期铺垫完了, 现在esp32编程和板子驱动, 还有
LVGL
测试确保正常. 开始编写LVGL
界面工程
3.1. 添加组件
- 直接点击这个图标就可以打开组件工具箱, 然后拖动组件到画布上就可以添加了, 也支持复制粘贴,
3.2. 组件属性
- 组件的属性可以通过右栏设置,
- 如果组件有
不同状态
, 就点右边的下拉框选择状态. 比如按钮有按下
,松开
等不同状态. - 如果组件有
不同模式
, 就点左边的下拉框选择模式, 比如进度条有底色和进度条颜色, 还有表格, 有表头和表单等组成.
- 如果组件有
- 不同模式又可能有多种状态可以供设置. 内置的预设样式也好过没有, 可以参考看看.
3.3. 布局对齐
- 有一个
容器
组件, 可以做嵌套式布局, 形成子级父级关系. 这个软件的坐标系统是相对父级
来说的, 如果起点都在左上角
, xy始终为正数, 终点在右下角. - 软件支持快捷对齐布局操作, 需要注意几点:
- 上下左右,中心对齐是以最后一个选择的组件作为对象,
这个逻辑和画pcb和模型图时用的对齐指令不一样. - 如果发现对齐后没有效果, 是因为两个组件不在同一的父级下, 对齐后坐标系统, 位置不同.
- 上下左右,中心对齐是以最后一个选择的组件作为对象,
3.4. 组件事件
-
模板里有很多可供学习的事件设置, 选择要设置的组件, 然后点击下栏中的
事件添加
即可. 软件提供的是可视化编程. 对于一些组件操作内置了选项, 也支持自定义事件代码. -
点击按调用
cont_menu
容器的isVisible(使能)
函数, 达到一个点击图标显示菜单的效果.
- 然后在对容器设置,点击后隐藏的效果:
- 也可以设置跳转屏幕,和跳转动画等效果.
- 也可以选择自定义代码. 更多其他内置事件功能自行尝试, 不赘述了.
3.5. 组件事件 自定义代码
- 选择
custom code -> Edit code
添加自定义代码.可以选择添加c或python类型. 添加并保存后, 点击右上角的生成代码, 即可自动将代码添加在工程中.在代码编辑中可以看到生成的内容.
- 工程代码主要是
Custom
文件夹 和Generated
文件夹 的内容. 前者是属于可更改的, 后者是不可更改的, 会在每次生成代码时自动刷新. - 其中
events_init.c
的内容就是对应组件事件
中编辑的内容. - 需要注意的是, 他们是杂糅堆一起的, 是可以
共同调用
定义的全局变量, 也需要注意不要重复定义
的全局变量!!!
Custom
文件夹的内容不会被自动刷新掉, 一般添加一下打包函数, 可以被events_init.c
文件调用到.
3.6. 选择编译
- 因为LVGL界面编辑是一个工程, 为了能编译运行, 不能添加一些多余的代码. 但最终是要给esp32工程里用的, 必定会用到一些工程里的变量函数, 如果每次导出都刷新掉, 重新更改, 就太不科学了. 所以我想到添加宏定义进行选择编译.
如果你有更好的方法请介绍给我.
#ifdef ESP_PLATFORM // esp32工程编译时自带的宏定义// 添加实际所需代码esp32_uart_read(rx_buf, 1000); // 假设的伪代码lv_spinbox_set_value(guider_ui.Settings_spinbox_2, reg.par.add); // 控制ui组件
#else // LVGL仿真时执行的测试内容// 不耦合的测试内容int add = 666; // 测试组件代码正常运行lv_spinbox_set_value(guider_ui.Settings_spinbox_2, add); // 控制ui组件
#endif
4. 总结
- 剩下的就是枯燥无味, 简单重复的ui的组件修改, 和接口协议匹配的内容.
或许可以尝试丢给ai, 最近挺流行的, 直接去研究怎么让ai帮忙写, 比自己写快多了.今天刚通关剑星, 不知道啥时候出现ai觉醒的剧情.