在TFT上简单的显示字符、数字、汉字、图形、图片等,都是一些简单的显示。如果想要进行较为复杂的显示,就推荐使用GUI。
市面上常见的嵌入式GUI有LVGL,emWin(ucGUI),TouchGFX,Embedded GUI、QT for MCU、GUIX、miniGUI、uGFX等等。本文使用的GUI是LVGL,是一款开源GUI项目。
那么,到底什么是LVGL?
官网:LVGL - Light and Versatile Embedded Graphics Library
关于LVGL的更多学习,参考:
LVGL|lvgl中文教程手册(lvgl中文文档学习教程)_挨踢民工biubiu的博客-CSDN博客_lvgl
一篇文章足够你学习嵌入式GUI LVGL技术,提供史上最全的LVGL技术文章总结,文档代码下载总结)_Wireless_Link的博客-CSDN博客_lvgl
LVGL 的第一个版本于 2016 年在 GitHub 上发布。 像一般的开源项目的那样,它是作为一个人的项目开始的。 从那时起,陆续有近 100 名贡献者参与了项目开发,使得 LVGL 逐渐成为最受欢迎的嵌入式图形库之一。
现在 LVGL 每 5 分钟就有一次下载量,她是 GitHub 上最受欢迎的 C 库之一。 除了吸引成千上万的用户之外,LVGL 还吸引了在其生态系统中的一些大公司。 2020 年,我们成立了 LVGL LLC,为库提供坚实的背景,并开发新的方法来帮助 UI 开发。
LVGL之前叫 LittleVGL,后来作者将其更名为 LVGL。
LVGL的项目作者是来自匈牙利首都布达佩斯的 Gábor Kiss-Vámosi 。Kiss 在2009年开始写 LVGL(LittleVGL),2016年将其重写并发布在 GitHub 上。
LVGL(轻巧而多功能的图形库)是一个免费的开放源代码图形库,它提供创建具有易于使用的图形元素,精美的视觉效果和低内存占用的嵌入式GUI所需的一切,具有如下特点:
- 丰富且强大的模块化图形组件:按钮 (buttons)、图表 (charts)、列表 (lists)、滑动条 (sliders)、图片 (images) 等
- 高级的图形引擎:动画、抗锯齿、透明度、平滑滚动、图层混合等效果
- 支持多种输入设备:触摸屏、 键盘、编码器、按键等
- 支持多显示设备
- 不依赖特定的硬件平台,可以在任何显示屏上运行
- 配置可裁剪(最低资源占用:64 kB Flash,16 kB RAM)
- 基于UTF-8的多语种支持,例如中文、日文、韩文、阿拉伯文等
- 可以通过类CSS的方式来设计、布局图形界面(例如:Flexbox、Grid)
- 支持操作系统、外置内存、以及硬件加速(LVGL已内建支持STM32 DMA2D、NXP PXP和VGLite)
- 即便仅有单缓冲区(frame buffer)的情况下,也可保证渲染如丝般顺滑
- 全部由C编写完成,并支持C++调用
- 支持Micropython编程,参见:LVGL API in Micropython
- 支持模拟器仿真,可以无硬件依托进行开发
基本上,每个现代控制器(肯定必须要能够驱动显示器)都适合运行LVGL。LVGL的最低运行要求很低:
系统学习课程:
LVGL开源GUI零基础入门课程(韦东山·监制) 教程基于lvgl v8.2版本,课程适配多个平台、多款板子(Linux单片机GUI、littleVGL教程)_哔哩哔哩_bilibili
TFT+GUI,可以实现HMI的效果。
二者对比如下:
HMI不用自己手动移植界面,但是比较贵。
TFT+GUI的硬件成本较便宜,但需要自己手动移植并编写界面。
另外TFT+GUI相比HMI更加灵活丰富,因为HMI的界面和样式相对比较固定。
除此之外,TFT+GUI对内存的要求会更高。
实际中,根据成本和开发周期等因素进行选择。
本文仅讨论TFT+GUI。
想了解HMI,参考:STM32实战总结:HAL之HMI_路溪非溪的博客-CSDN博客
LVGL移植
直接参考:
【LVGL学习之旅 01】移植LVGL到STM32_风中凌乱007的博客-CSDN博客_stm32移植lvgl
多多实践。
示例代码
/* Includes ------------------------------------------------------------------*/ #include "MyApplication.h" /* Private define-------------------------------------------------------------*/ /* Private variables----------------------------------------------------------*/ /* Private function prototypes------------------------------------------------*/ static void Button(void); //按钮 static void Label(void); //标签 /* Public variables-----------------------------------------------------------*/ GUI_t GUI = { Button, Label }; //按钮事件回调函数 static void btn_event_cb(lv_obj_t * btn, lv_event_t event) { if(event == LV_EVENT_CLICKED) { //控制蜂鸣器 if(Buzzer.Status == ON_Status) { Buzzer.OFF(); } else { Buzzer.ON(); } } } /* * @name Button * @brief 按钮 * @param None * @retval None */ static void Button(void) { lv_obj_t * btn = lv_btn_create(lv_scr_act (), NULL); //往当前屏幕增加按钮 lv_obj_set_pos(btn, 50, 160); //设置按钮的位置 lv_obj_set_size(btn, 140, 50); //设置按钮的尺寸 lv_obj_set_event_cb(btn, btn_event_cb); //为按钮指定回调函数 lv_obj_t * label = lv_label_create(btn, NULL); //按钮上增加标签 lv_label_set_text(label, "Buzzer"); //标签显示文本 } /* * @name Label * @brief 标签 * @param None * @retval None */ static void Label(void) { lv_obj_t * label = lv_label_create(lv_scr_act (), NULL); lv_obj_set_pos(label, 30, 120); lv_label_set_text(label, "Hello world!"); } /******************************************************** End Of File ********************************************************/