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

2024-06-15 04:12

本文主要是介绍基于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开发的实战开发技巧。

这篇关于基于MCU平台的HMI开发的性能优化与实战(上)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1062393

相关文章

Spring Shell 命令行实现交互式Shell应用开发

《SpringShell命令行实现交互式Shell应用开发》本文主要介绍了SpringShell命令行实现交互式Shell应用开发,能够帮助开发者快速构建功能丰富的命令行应用程序,具有一定的参考价... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定义S

在Android平台上实现消息推送功能

《在Android平台上实现消息推送功能》随着移动互联网应用的飞速发展,消息推送已成为移动应用中不可或缺的功能,在Android平台上,实现消息推送涉及到服务端的消息发送、客户端的消息接收、通知渠道(... 目录一、项目概述二、相关知识介绍2.1 消息推送的基本原理2.2 Firebase Cloud Me

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优