板子介绍
看到一个板子还挺酷的,就买了,后面的记录以这个板子为基础
以下链接仅供参考,不代表本人建议
https://item.taobao.com/item.htm?_u=83qifgevfef5&id=701035004759&spm=a1z09.2.0.0.425b2e8duB8l4o
1、板子电路部分
芯片本身,这里主控室esp32s3,所有引脚都引出来了
触摸屏,这里用了一个驱动芯片,然后连到屏幕的接口,看样子是spi驱动的
引出来一路USB一路串口
引出来一路摄像头
tf卡引出
按键,这两个都不可用作自定义的
led,高电平点亮
稳压芯片
2、初体验lvgl
这里用的是espidf的开发环境,搭建开发环境的教程我之前有发过,这里不再多说,用的是这个例程(应该是个显示字符串的):
准备编译
编译成功后如下所示
刷完固件
效果
3、模拟器推荐
学习lvgl有一些东西可以参考,比如如果没有设备,可以先用一些模拟器来实现就很方便,我主要是看了这个up主的视频,讲的这个模拟器还是很不错的,主要是可以直接用在实际的硬件上来
https://www.bilibili.com/video/BV1LG411D7YQ/?spm_id_from=333.1391.0.0&p=4&vd_source=f5fd730321bc0e9ca497d98869046942
可以参考这个文档
https://www.yuque.com/icheima/vzsofu
他是在windows上操作的,用的是MinGW(Minimalist GNU for Windows)和cmake来搭建的开发环境,这两个下好之后配置到环境变量即可。
可以直接参考他的工程,在vscode里面先设置一下cmake的可见性
之后先把这两个编译产物删掉(因为编译器可能不会重新编译,这个时候编译就会因为路径错误导致编译不过)
之后重新编译
直接点击运行会失败,需要把这个dll文件拷贝到路径下才行
拷贝到这里
运行成功
可以修改代码跑个demo
具体改动就是把lv_conf.h
里面的这个宏变化一下就行
同时也可以知道他这个lvgl的版本是8.2.0,在文件的最开头可以看到
另外也可以跑个其他的例程,例如LV_USE_DEMO_WIDGETS
,效果如下:
4、代码分析
发现用esp32 idf来开发还是很方便的,他内部集成了很多东西,几乎可以直接使用
这里有参考这篇文章(有一点出入,用这个不能完全跑起来)
https://blog.youkuaiyun.com/m0_55986987/article/details/132875484
点击这里进入终端
输入git init
,之后拉取代码,分别是驱动库和对应的lvgl的库,这里如果拉不下来,可以提前下载下来再用(部分资源我上传到我的资源,如果没有下载币的话可以留邮箱)
先创建文件夹
mkdir components
cd components
之后在该文件夹下创建拉两个库
git submodule add -b release/v8.3 https://github.com/lvgl/lvgl.git lvgl
git submodule add https://github.com/lvgl/lvgl_esp32_drivers.git lvgl_esp32_drivers
下载好是这样的
点击进入sdk的配置页面
这里如果进不去,按照下面步骤执行一下
或者在这里设置
之后开始设置,这里先设置一下flash的大小
接下来设置屏幕驱动
往下拉进入io口的设置
这里设置按照屏幕的来即可
main.c直接抄过来用,下面我附上代码
#include <stdio.h>
#include "esp_log.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "lvgl.h"
#include "lvgl_helpers.h"
#include "demos/lv_demos.h"
#define TAG "main"
void lv_tick_task(void *arg)
{
lv_tick_inc(1);
}
void app_main(void)
{
/* Initialize SPI or I2C bus used by the drivers */
lvgl_driver_init();
lv_init();
lv_color_t *buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
assert(buf1 != NULL);
static lv_color_t *buf2 = NULL;
static lv_disp_draw_buf_t disp_buf;
uint32_t size_in_px = DISP_BUF_SIZE;
lv_disp_draw_buf_init(&disp_buf, buf1, buf2, size_in_px);
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = 320;
disp_drv.ver_res = 240;
disp_drv.flush_cb = disp_driver_flush;
disp_drv.draw_buf = &disp_buf;
lv_disp_drv_register(&disp_drv);
const esp_timer_create_args_t periodic_timer_args = {
.callback = &lv_tick_task,
.name = "periodic_gui"};
esp_timer_handle_t periodic_timer;
ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, 1 * 1000));
// lvgl demo演示
lv_demo_music();
// lv_demo_stress();
while (1)
{
/* Delay 1 tick (assumes FreeRTOS tick is 10ms */
vTaskDelay(pdMS_TO_TICKS(10));
lv_task_handler();
}
}
直接烧录,下载
可以看到屏幕被成功驱动
前面尝试了跑模拟器,因此也可以试下在这里跑下模拟器,下面是前面模拟器跑的样子
把模拟器的代码复制过来
void demo_style()
{
// 1. 得到当前活跃的屏幕
lv_obj_t *screen = lv_scr_act();
// 2. 在当前屏幕上显示一个对象
lv_obj_t *obj = lv_obj_create(screen);
lv_obj_align(obj, LV_ALIGN_CENTER, 0, 0);
// 3. 通过样式修改对象的样式
static lv_style_t style;
lv_style_init(&style);
lv_style_set_width(&style, 100);
lv_style_set_height(&style, 200);
// lv_style_set_x(&style,50);
// lv_style_set_y(&style,50);
lv_style_set_bg_color(&style, lv_palette_main(LV_PALETTE_CYAN));
lv_style_set_radius(&style, 25);
// 将样式与obj关联起来
lv_obj_add_style(obj, &style, 0);
}
注释掉demo的调用,加上模拟器的函数
可以看到模拟器写的代码被成功跑到esp32上了
那么既然esp32的lvgl这么好用,是不是换个mcu也可以很方便的跑起来呢
显然!是的
下面换一个esp32,不带s3的版本,换一块其他的屏幕试试,换上了这个mcu
屏幕换成了一个大的,驱动也不再是st7789改为ILI9488了
下面开整:
还是先设置一下flash大小
设置drivers
引脚设置(这里我没有设置背光,没勾选,直接vcc怼上就行了)
lvgl这里,这次跑另外一个demo
如果编译不过,记得开启对应的字体
尴尬,直接编译不过,这个需要的内存太大了
改回music重新编译,记得在main.c这里修改屏幕大小
成功写入
运行效果,可以看到是可以正常跑起来的
因此就不用担心换屏幕,换mcu了。
后面会继续分享一下使用其他MCU,例如GD32,STM32来完成LVGL的移植实现,也考虑一些linux系统的移植。
5、GUI设计工具
从模拟器的开发可以了解到,开发这个页面需要自己一个个设计控件,这个显然速度是很慢的,需要一步步的调试使用,那么有没有快速的方式呢?
之前用QT的话,会有QT Disenger的说法,这个应该也有GUI设计工具的,查了一下还真有,这里我用GUI GUIder试试,页面大概是这样的
打开这里可以看到控件
展开大概是这样的
点击运行
下面开始准备移植到我们的代码里面:
打开GUI界面的项目文件夹
移植到我们的这个路径下面
main.c改为
#include <stdio.h>
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "lvgl.h"
#include "lvgl_helpers.h"
#include "gui_guider.h"
#include "custom.h"
lv_ui guider_ui;
#include "demos/lv_demos.h"
#define LVGL_TICK_MS 1
#define TAG "main"
void lv_tick_task(void *arg)
{
lv_tick_inc(LVGL_TICK_MS);
}
void app_main(void)
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
/* Initialize SPI or I2C bus used by the drivers */
lvgl_driver_init();
lv_init();
lv_color_t *buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
assert(buf1 != NULL);
static lv_color_t *buf2 = NULL;
static lv_disp_draw_buf_t disp_buf;
uint32_t size_in_px = DISP_BUF_SIZE;
lv_disp_draw_buf_init(&disp_buf, buf1, buf2, size_in_px);
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = 480;
disp_drv.ver_res = 320;
disp_drv.flush_cb = disp_driver_flush;
disp_drv.draw_buf = &disp_buf;
lv_disp_drv_register(&disp_drv);
const esp_timer_create_args_t periodic_timer_args = {
.callback = &lv_tick_task,
.name = "periodic_gui"};
esp_timer_handle_t periodic_timer;
ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, 1 * 1000));
// lvgl demo演示
// lv_demo_music();
// lv_demo_stress();
setup_ui(&guider_ui);
while (1)
{
/* Delay 1 tick (assumes FreeRTOS tick is 10ms */
vTaskDelay(pdMS_TO_TICKS(10));
lv_task_handler();
}
}
修改main文件夹下的makefile,确保我们的添加进来的文件被修改
# idf_component_register(SRCS "main.c"
# INCLUDE_DIRS ".")
file(GLOB_RECURSE srcs *.c
ui/custom/*.c
ui/generated/*.c
ui/generated/guider_customer_fonts/*.c
ui/generated/guider_fonts/*.c
ui/generated/images/*.c
)
set(include_dirs
.
ui/custom
ui/generated
ui/generated/guider_customer_fonts
ui/generated/guider_fonts
ui/generated/images
)
idf_component_register(
SRCS ${srcs}
INCLUDE_DIRS ${include_dirs}
)
之后电机编译烧录,运行结果如下:
LVGL可以用的东西还是很多的,后续会探索在linux上的一些用法