基于MCU平台的HMI开发的性能优化与实战(上)

随着汽车座舱智能化的不断演进,车内显示设备的数量显著增加,从传统的仪表盘和中控屏扩展至空调控制、扶手、副驾驶区域以及抬头显示(HUD)等多样化的显示单元。为了有效支持这些功能单元,同时控制整车成本,越来越多的汽车制造商开始采用微控制器单元(MCU)芯片。MCU以其低功耗、高集成度和经济性,成为降低成本的优选方案。

但由于平台的计算能力和存储空间受限,如何有效利用有限的资源来实现功能丰富、页面切换平滑的HMI应用变得至关重要。资源是否被合理的使用将直接影响应用的性能和用户体验。如果计算能力或存储空间使用不当,程序可能在PC上运行流畅,但在MCU上会遇到卡顿甚至崩溃的情况,无法满足设计目标。为应对此挑战,专为资源受限设备量身定制的工具——Qt for MCUs应运而生。凭借其极小内存占用和高度优化的库,Qt for MCUs旨在为MCU和低端MPU提供高性能HMI应用程序开发工具。采用Qt for MCUs在MCU平台上可以获得极佳的开发体验以及更好性能的HMI应用。

Qt for MCUs极大地减轻了开发人员在移植和调优方面的成本,但在资源受限的MCU平台上,性能优化始终是一项不可回避的挑战。

本文将基于Qt for MCUs工具,探讨如何通过精简代码、提升运行效率以及优化内存和资源管理等策略,来提高MCU平台下的HMI开发效率和应用性能。

一、降低代码量

减少代码量不仅能够降低程序对存储空间的需求,还能简化程序结构,使代码更加清晰。这有助于系统承载更多功能,同时还可以避免因内存不足导致的系统崩溃。简化的代码逻辑减少了CPU的分支判断,从而减轻了处理器的负担。此外,减少的运行时间还能降低能耗,并且有助于编译器更有效地优化代码,生成更高效的机器码。

在Qt for MCUs平台,我们推荐从以下三个方面对代码量进行优化:

1、减少锚点的使用

锚点是一种布局方式,用于将一个元素相对于另一个元素进行定位。

通过设置元素的anchors属性,可以将元素的边缘与其父元素或其他元素的边缘对齐。锚点可以在不同大小的屏幕上自适应,并且可以根据不同的屏幕方向进行动态调整。每个项目都可以被认为有一组 6 条不可见的“锚线”:

左 | 水平中心 | 右 | 顶部 | 垂直中心 | 底部

使用锚点进行开发虽然提供了布局的灵活性,但过度依赖它们可能会带来一些弊端。特别是在界面尺寸固定的情况下,锚点的动态计算过程不仅增加了代码的复杂度,还会带来不必要的性能开销。

通过直接指定坐标位置来替代部分锚点,可以简化代码结构,降低代码行数,从而提高代码的可读性和可维护性。

让我们通过一个简单的图形示例来比较 锚点定位 和 绝对定位 两种实现方式的不同。

下表左侧代码为绝对布局实现方式,右侧代码是锚点布局实现方式

import QtQuick

Item {

    id: root

    width: 500

    height: 200

    Rectangle {

        id: rect

        x: 50

        y: 50

        width: 200

        height: 100

        color: "#ED8E00"

    }

}

import QtQuick

Item {

    id: root

    width: 500

    height: 200

    Rectangle {

        id: rect

        anchors.left: parent.left

        anchors.top: parent.top

        anchors.leftMargin: 50

        anchors.topMargin: 50

        width: 200

        height: 100

        color: "#ED8E00"

    }

}

对比可以看出锚点布局的实现方式相较于绝对布局方式代码行数要多,且从代码逻辑上看,计算逻辑要更为复杂。

  1. 使用Repeater     

Repeater是Qt for MCUs提供的一个自动重复的功能组件。通过使用Repeater可以方便的创建多个相似的控件,而无需手动编写重复的布局和逻辑代码。这不仅可以减少代码量,还可以提高界面的一致性和可维护性。

import QtQuick

Item {

    .........

    //Column布局矩形元素竖向排列

    Column {

        spacing: 10 // 列元素之间的间距为10

        Repeater { // 用于重复生成元素

            model: 3 // 模型为3,生成三个矩形

            //delegate 定义了每个重复元素的模板,这里每个元素都是矩形

            delegate: Rectangle {

                id: rect

                width: 100

                height: 100

                color: getColor(index) // 使用预定义的函数获取矩形填充颜色

            }

        }

}

..........

}

通过上图的例子可以看出,创建三个矩形,我们可以通过将编辑好的矩形样式应用到Repeater内的组件中来实现,无需三次重复编写矩形控件代码和使用布局来设置它们的位置。同时还可以通过函数调用的方式为每个矩形设置不同的属性。这种方法不仅减少了代码量,还提高了代码的可维护性。

3、增加可复用组件

在UI界面开发中,经常会遇到默认的组件样式无法完全满足设计需求的情况。为了解决这一问题,我们可以将基础组件进行样式定制,以满足特定的设计要求。然后,将这些定制的组件封装到一个独立的文件中,创建为自定义组件。这样,我们就可以像使用官方组件一样,通过几行简单的代码来调用这些封装好的自定义组件。这种方法不仅提高了代码的复用性,减少了冗余,也提升了整体的代码质量,如下图所示。

除了提取重复使用的组件样式代码外,我们还可以通过将多处出现的逻辑代码抽取并封装到单独的文件中,实现代码的集中管理和统一维护。

二、提高运行效率

提升运行效率能够显著加快系统的响应速度,从而增强用户的使用体验。我们可以通过以下四种策略来提高运行效率:

1、减少动态绑定依赖次数

如图所示,当属性与其他属性绑定并形成依赖关系时,若属性值发生变化,依赖属性会被标记为“脏”状态。随后,系统会触发并处理所有标记为“脏”的事件,确保依赖属性能够及时更新其值。这种动态更新机制虽然有效,但其复杂的依赖管理和事件处理过程可能会导致性能下降。通过减少不必要的动态绑定和依赖次数,我们可以降低属性刷新的频率,进而提升系统的运行效率。

2、修改控件源代码

修改Qt for MCUs的控件源代码,可以暴露更多的控制接口,从而能够更直接地操作控件的属性和行为,减少中间层的开销,提高运行效率。

3、错峰加载与预加载

Loader是Qt for MCUs中用于加载UI资源的组件。修改Loader的加载策略可以有效平衡性能消耗,减少资源加载期间的卡顿现象。

错峰加载策略:分散资源或任务的加载时间

系统启动时可能会因资源争用而遇到性能下降或崩溃的问题。通过实施错峰加载机制,我们不是同时加载和初始化所有模块或任务,而是按计划的顺序和时间间隔分批进行。这种方法可以缓解启动时的资源竞争和高负载,确保系统的平稳运行。

预加载策略:提前加载资源或执行任务

提前加载资源

预加载策略指的是在页面实际显示给用户之前,就预先加载未显示的页面。这样做可以防止在页面加载过程中出现空白屏幕,从而提升用户体验。

为了实现系统性能的优化和用户体验的提升,我们需要根据具体状况,选择最合适的加载策略。

4、局部数据刷新

全局数据刷新会触发整个界面的重绘,造成不必要的性能损耗。通过改进刷新策略,采用局部配置数据刷新代替全局刷新,可以只更新界面中需要变化的部分,减少不必要的渲染工作,从而提高运行效率。

全局刷新

局部刷新

如上图所示,当数据发生变化时,首先进行数据对比,有数据变化的部分重新加载刷新数据,无数据变化的部分保持不变,无需再次加载,减少了渲染操作,提高了运行效率。

三、内存管理

高效的内存管理对于提升HMI的应用性能和稳定性至关重要。它有助于减少内存碎片、加快访问速度、降低分配成本、防止内存泄漏,并优化内存使用。在资源受限的MCU环境中,可以确保HMI应用的流畅运行。我们提供三种关键的内存管理策略,旨在优化内存使用。

1、单例模式

单例模式是一种设计模式,它保证一个类在整个应用中只有一个实例,并且提供了一个统一的访问点。这种模式通过一个特定的类来实现,这个类负责自己的实例化,并且保证只实例化一次。它允许我们直接访问这个唯一的实例,无需通过常规的实例化过程。这有助于降低系统复杂性,提高性能,并节省宝贵的资源。

2、内部申请机制

我们采用统一且预定义的内存管理机制,有效预防出现内存泄漏、碎片化和过度分配等问题。

上图展示了FreeRTOS中pvPortMalloc的内存分配流程,这是FreeRTOS为动态内存分配特别设计的函数,与标准C库中的函数类似,但专为FreeRTOS的任务调度和内存管理机制优化。FreeRTOS提供了五种内存管理方案:

  1. heap_1:最基础的实现,不支持内存释放。
  2. heap_2:支持内存释放,采用简单的连续内存分配算法,可能产生内存碎片。
  3. heap_3:使用标准库的malloc()和free()函数,依赖于标准库的实现。
  4. heap_4:提供最佳平衡,采用首次适应算法,并通过合并空闲块减少碎片化。
  5. heap_5:最灵活,支持多个独立堆区域,适合复杂内存管理场景。

开发者可以根据设备条件和需求选择最合适的内存管理方案。

3、内存池技术

内存碎片是嵌入式系统中普遍存在的问题,尤其是在频繁申请和释放小块内存时更为明显。内存池技术通过预先分配一定数量的小块内存,并在程序运行期间循环使用这些内存块来解决这一问题。需要内存时,直接从内存池中获取;不再需要时,则将其返还给内存池,而不是释放回系统。这种方法减少了内存的频繁分配与释放,有效防止了内存碎片的产生。此外,内存池还有助于优化内存对齐,进一步提升内存的使用效率。

如上图所示,程序启动时,我们预先分配一定数量的固定大小内存块。在申请内存时,直接从这些预分配的块中获取;释放内存时,则将其放回预分配的块中,以便再次使用。每个内存池针对特定的使用场景设计,与传统的malloc/free相比,它减少了复杂的逻辑处理,可以显著提高性能。

四、资源管理

资源管理的核心在于优化图片资源的性能,我们采用以下三种策略来应对系统对图片资源的各种需求,目的是不影响用户体验的前提下,降低图片存储的开销。

1、BorderImage

BorderImage属性允许在用户界面中绘制可伸缩的边框图像,非常适合创建大小可变且边缘不失真的UI元素,例如按钮、面板和背景。当处理图像内容简单(如纯色图片)时,BorderImage可以替代传统的Image属性。它能够无损放大图像边缘,防止拉伸时的失真,同时减少了存储空间中不必要的像素数据。在某些特殊场景下,这种方法几乎可以避免图像质量损失,具体效果如下方图示。

2、ColorizedImage

ColorizedImage组件用于展示图片并应用颜色遮罩,能够将指定颜色应用于原始图像,从而生成具有不同色彩效果的图像。当面对内容相同但颜色各异的大量图像时,ColorizedImage提供了一种高效的解决方案:只需存储一张基础图片并进行动态上色,这样可以大幅减少因颜色不同而需存储的多张图片所占用的存储资源。然而,这种方法在执行效率上可能略低于直接使用Image,因此更适合于小型图标以及显示数量较少的场景,具体效果可以参考以下图示。

3、降低图片编码渲染格式

Qt for MCUs针对图片资源提供了多种格式选项,允许开发者根据不同场景和图片特性选择最合适的格式,以优化存储效率。每种图片格式都有其特点和占用空间大小,合理选择格式有助于在图片资源的存储优化和MCU的计算能力之间找到最佳平衡点。

图像格式

格式描述

清晰度描述

像素占用

ARGB8888

拥有透明度、红、绿、蓝四个通道,每个通道占用8位

可最大化保证图片质量和原图一致

32

ARGB4444

拥有透明度、红、绿、蓝四个通道,每个通道占用4

将会损失绝大部分的色彩细节,在复杂图像肉眼可明显感受到失真

16

RGB888

拥有红、绿、蓝三个通道,每个通道占用8位

可最大化保证图片质量和原图一致,但无法实现显示透明像素的效果

24

RGB565

拥有红、绿、蓝三个通道,其中,红色和蓝色通道占用5位,绿色通道占用6

可在图像质量和图像大小之间取得较好的平衡,对于复杂色彩的图像可能失真,但肉眼感知不明显

16

RGB444

拥有红、绿、蓝三个通道,每个通道占用4位

将会损失绝大部分的色彩细节,在复杂图像肉眼可明显感受到失真且无法显示透明像素效果

12

通过在合适的场景下使用适合的图片存储格式可平衡显示效果和存储、加载的空间占用,如下图所示,上方图片为在RGB444下的显示效果,下方图片为在RGB888下的显示效果,在色彩丰富的情况下可明显看出两者的区别,但同大小图RGB888的存储占用是RGB444的2倍,但在图像颜色简单的情况下者区别肉眼 

本文深入探讨了使用Qt for MCUs进行HMI应用开发时,通过优化代码、提升运行效率、管理内存以及合理使用资源来提高应用性能的策略。这些优化措施使开发者能够在资源有限的MCU平台上构建高效且功能丰富的HMI应用,确保用户获得流畅、稳定的操作体验。随着技术的不断发展,我们将探索和分享更多的优化方法,进一步提升MCU平台上的HMI应用性能。

下一章,我们将结合实际案例,深入开展Qt for MCUs的实战演练,通过具体示例详细讲解HMI开发过程中的各项优化策略的应用及其效果,帮助开发者全面掌握通过Qt for MCUs来进行HMI开发的实战开发技巧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/709851.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

59.指向指针的指针(二级指针)

目录 一.什么是指向指针的指针 二.扩展 三.视频教程 一.什么是指向指针的指针 我们先看回顾一下指针&#xff1a; #include <stdio.h>int main(void) {int a 100;int *p &a;printf("*p is %d\n",*p);return 0;} 解析&#xff1a; 所以printf输出的结…

最长连续序列

题目&#xff1a;最长连续序列 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 解题思路&#xff1a; 思路一:先排序&#xff0c;然…

49.Chome浏览器有三种清缓存方式

49.Chome浏览器有三种清缓存方式&#xff1a;正常重新加载、硬件重新加载、清空缓存并硬性重新加载 1、【正常重新加载】 触发方式&#xff1a;①F5  ②CtrlR  ③在地址栏上回车  ④点击链接 如果缓存不过期会使用缓存。这样浏览器可以避免重新下载JavaScript文件、图像、…

如何应对生活中的不确定性:仁者安仁,知者利仁。

有较高自尊水平的人&#xff0c;接近于孔子说的&#xff1a;仁者。 ——— 有着稳定的高自尊&#xff0c;无论外在环境如何变化&#xff0c;对其影响都不大&#xff0c;他能够愉快地生活。 相反&#xff1a;一个人处于低自尊状态&#xff0c;就会活得很痛苦&#xff0c;对自己…

Visual Studio Code连接VMware虚拟机

1.安装VS Code插件 在拓展中安装插件 Remote-SSH 2.在虚拟机中安装OpenSSH服务器 使用超级用权限(root)更新软件包列表&#xff0c;Debian系统和Ubuntu系统使用apt包管理工具&#xff1a; sudo apt update CentOS系统使用yum或dnf包管理工具&#xff1a; sudo yum update …

LeetCode | 434.字符串中的单词数

这道题直接使用语言内置的 split 函数可直接分离出字符串中的每个单词&#xff0c;但是要注意区分两种情况&#xff1a;1、空串&#xff1b;2、多个空格连续&#xff0c;分割后会出现空字符的情况&#xff0c;应该舍弃 class Solution(object):def countSegments(self, s):&qu…

C++青少年简明教程:C++的指针入门

C青少年简明教程&#xff1a;C的指针入门 说到指针&#xff0c;就不可能脱离开内存。了解C的指针对于初学者来说可能有些复杂&#xff0c;我们可以试着以一种简单、形象且易于理解的方式来解释&#xff1a; 首先&#xff0c;我们可以将计算机内存想象成一个巨大的有许多格子的…

论文阅读:H-ViT,一种用于医学图像配准的层级化ViT

来自CVPR的一篇文章&#xff0c;https://openaccess.thecvf.com/content/CVPR2024/papers/Ghahremani_H-ViT_A_Hierarchical_Vision_Transformer_for_Deformable_Image_Registration_CVPR_2024_paper.pdf 用CNNTransformer混合模型做图像配准。可变形图像配准是一种在相同视场…

windows上安装redis,并且用pycharm联通调用测试

在 Windows 上启动 Redis&#xff0c;官网版本不支持windows直接安装&#xff0c;你可以按照以下步骤进行操作&#xff1a; 使用Github Redis 版本启动 Redis 如果你想使用 Redis 在 Windows 上启动 Redis&#xff0c;以下是基本的步骤&#xff1a; 下载 Redis&#xff1a; 访…

Commons-Collections篇-CC4链分析

前言 因为 CommonsCollections4 除 4.0 的其他版本去掉了 InvokerTransformer 继承 Serializable&#xff0c;导致该方法无法序列化。 同时 CommonsCollections 4的版本 TransformingComparator 继承了 Serializable接口&#xff0c;而CommonsCollections 3里是没有的&#xf…

【中台】数字中台整体建设技术方案(doc原件获取)

1. 中台概念 2. 推动企业组织模式演进 3. 建设方法 4 .中台内容 5. 数据安全体系 中台内容围绕数据中台建设评估、整体框架、数据采集&#xff0c;结构化、半结构化、非结构化的数据采集&#xff0c;数据计算能力、存储计算引擎、数据架构、数据挖掘、各种不同数据层建设、模型…

火爆全网《pvz植物大战僵尸杂交版》最新安装包,支持Android、Windows、iOS!

我是阿星&#xff0c;今天跟大家聊聊最近在B站火得一塌糊涂的老游戏——《植物大战僵尸》。你没听错&#xff0c;就是那个曾经让我们熬夜奋战&#xff0c;一关又一关的游戏。 话说回来&#xff0c;这游戏怎么就突然又火起来了呢&#xff1f; 原来&#xff0c;是因为它的最新整…

54.Python-web框架-Django-免费模板django-datta-able

1.Datta Able Django介绍 Detta Able Djiango是什么 Datta Able Django 是一个由AppSeed提供的开源Django管理面板&#xff0c;基于现代设计&#xff0c;为开发者提供了一流的功能和优雅的界面。它源自CodedThemes的高风格化Bootstrap 4模板——Datta Able Bootstrap Lite&…

手机在网状态-手机在网状态查询-手机在网站状态接口

查询手机号在网状态&#xff0c;返回正常使用、停机、未启用/在网但不可用、不在网&#xff08;销号/未启用/异常&#xff09;、预销户等多种状态 直连三大运营商&#xff0c;实时更新&#xff0c;可查询实时在网状态 高准确率-实时更新&#xff0c;准确率99.99% 接口地址&…

MySQL与PostgreSQL关键对比四(关联查询性能)

引言&#xff1a;MySQL单表的数据规模一般建议在百万级别&#xff0c;而PostgreSQL的单表级别一般可以到亿级&#xff0c;如果是MPP版本就会更多。从基础数据建议上&#xff0c;不难看出&#xff0c;MySQL在Join的情况下也就是主要查询的情况下性能和PostgreSQL相差还是很大的。…

Minecraft模组开发(fabric)之准备工作

Minecraft模组开发&#xff08;fabric&#xff09;之准备工作 最近心血来潮想开发个Minecraft的模组&#xff0c;一边学习一边开发&#xff0c;顺带着将一些步骤、学习心得整理下来。之所以选择fabric&#xff0c;是因为自己的光影包使用的是iris-fabric&#xff0c;所以就想着…

蓝牙耳机怎么连接电脑?轻松实现无线连接

蓝牙耳机已经成为许多人生活中不可或缺的一部分&#xff0c;不仅可以方便地连接手机&#xff0c;还能轻松连接电脑&#xff0c;让我们在工作和娱乐时享受无线的自由。然而&#xff0c;对于一些用户来说&#xff0c;将蓝牙耳机与电脑连接可能会遇到一些问题。本文将介绍蓝牙耳机…

[Java基本语法] 抽象类与接口

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏:&#x1f355; Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 &#x1f9c0;线程与…

SuperMap iClient3D 11i(2023) SP1 for Cesium 调整

SuperMap iClient3D 11i(2023) SP1 for Cesium 最新版本 下载地址 SuperMap技术资源中心|为您提供全面的在线技术服务 每一次版本升级,都要对代码进行修改调整,都是为了解决功能需求。当然,也为产品做了小白鼠测试,发现bug,优化功能。 由于前端开发使用的是dojo框架,类…

Node入门以及express创建项目

前言 记录学习NodeJS 一、NodeJS是什么&#xff1f; Node.js 是一个开源和跨平台的 JavaScript 运行时环境 二、下载NodeJs 1.下载地址(一直点击next即可&#xff0c;记得修改安装地址) https://nodejs.p2hp.com/download/ 2.查看是否安装成功&#xff0c;打开命令行 nod…