嵌入式应用软件架构设计

简介: 嵌入式应用软件架构设计

要做到嵌入式应用的代码逻辑清晰,且避免重复的造轮子,没有好的应用架构怎么行。

如果没有好的架构,移植将会是一件很痛苦的事情。


如果没有好的架构,复用是最大的难题,没法更大限度的复用原有的代码。


如果没有好的架构,一旦驱动改了,所有的地方都要改,费时费力且很容易出错。


如果没有好的架构,应用层中穿插着硬件驱动层的代码,看着会是一片混乱,逻辑不清,代码维护起来会很困难。


这里总结下我的嵌入式程序设计思路,分享出来与大家共同探讨,同时也欢迎提出不同意见。

现在的小朋友都爱玩搭积木的游戏,一个模块一个模块的拼装起来,快速组成各种不同的模型。现在的产品设计也很少从零开始。大都复用现有成熟的模块,专注于某个擅长领域。


我的嵌入式应用架构思路来源与此,即功能模块设计与分层。


把API分为驱动层和应用层API,而不是所有程序都调用驱动层API。(整个应用中都调用驱动层API会导致应用中驱动调用随处可见,无法移植和最大限度的复用)


先把一个应用进行功能模块划分,并对整体结构进行分层,然后设计出功能独立的各个模块(如算法模块,文件库模块,通信库模块),在模块之上开放公共接口。


驱动层提供出公共接口供上层调用。各个功能模块可以独立编译(如算法模块纯ANSI C,可在任意平台复用),或者调用驱动层接口(文件库模块调用了驱动读写Flash),总而言之,言而总之,封装出各个功能独立的可复用的功能模块。


总体分 硬件驱动层-->功能模块层-->应用接口层-->业务逻辑层-->应用层


总体结构示意框图:



应用层,为程序的总体的运行框架,组织调用业务逻辑。可以用某种嵌入式操作系统实现几种任务 。如定时任务,卡处理任务,菜单任务,通信任务。


业务逻辑层,如CPU卡处理,交通部卡处理,银联卡处理,M1卡处理,通信记录上传,黑名单下载,票价参数下载等。


应用接口层,提供公共的api接口供应用接口供上层调用。这些接口也可由下层的功能模块开放出来,应用接口层负责汇总。


功能模块层,可以封装不同的功能模块。如算法库,文件库,通信库,银联库,向上提供应用接口层的接口,向下调用驱动接口。


硬件驱动层,由各个驱动模块组成,向上提供统一的接口。


遵循一些约定,


1.每个模块提供出的接口要统一,后续只能增,不能改原来的接口。


2.模块与模块之间相互独立,互不影响,不能相互调用,只能调用它下层的接口。


3.由模块构成层,层与层之间不能跨级调用。如在应用层中不能看到直接调用驱动层的代码。


4.模块中又可以继续分层,如接口层,驱动层,硬件层。



如果驱动变动了,或者换不同平台,只需更改驱动层,应用层不受影响。


如果功能模块变动了,只需升级功能功能模块,其他的模块不受影响,应用层也不受影响。



按照这种逻辑设计好之后,主要的工作就是在业务逻辑层。应用层则为程序的总体流程和框架,主要调用业务逻辑层实现不同的功能。


我们现在的代码结构,基本是按这个思路来的。


硬件驱动层-->功能模块层-->应用接口层-->业务逻辑层-->应用层。


看看以下两种风格的代码,你更喜欢哪个。



另一种风格:



同样是保存参数,非要拆成 AlgCRC16  ,WritePraFlash( (unsigned char *)&NetPra , NETPRA_ADDR , sizeof(_NetPra) )两步吗?


还有AH_Para_Verify这个,在应用层中真是多余啊,检测失败又从Flash读取。关于参数,一开机就应该检测合法性了。


不要在应用层看到驱动的影子和具体实现细节。要让谁不了解底层细节的情况下按照模块接口文档都能容易的使用。


比如上面的风格1,目的就是往flash里保存参数,但是非要让搞应用的人了解你底层的那么多细节,这样好吗?不怕给你搞崩了?


不管你是往falsh还是往文件存,还是做了个crc16校验,让做应用的人看到这些细节作甚?徒增加烦恼和出错的概率。


脑海中一定要有一种模块化,组件化和分层的概念,先谋而后动,做好规划和分层。这样模块化达到一定积累后,效率会倍增,稳定性和拓展性,维护性才能有提高。



既然都是要保存参数,就应该做个封装,如上图所示,把系统用到的不同参数做个规划。应用层调用APP_Open_UseFile 或者APP_Read_UseFile,


而不是直接的去读写Flash。


来看看赫赫有名的谷歌的android架构,虽然很复杂,但从框图上看,也像是搭积木,各个功能模块独立,层次分明。最低层建立在linux Kernel基础上,然后是各个组件库libraries,再往上是应用框架和应用。



以NC_FileLib,文件库模块为例,如果要用在其他平台,如EH0918手持机设备,只需要移植几个硬件层接口即可。



NC_FileSys文件库,跟硬件相关的接口在Hook文件夹,


重新实现以下几个函数即可:


void HW_FRAM_Init( void )
unsigned int HW_FRAM_Read( unsigned int    addr,unsigned int    size,unsigned char    *buffer)
unsigned int HW_FRAM_Write( unsigned int    addr, unsigned int    size,unsigned char    *buffer )
//擦除FLASH一页 (FLASH擦除的最小单元)
unsigned int HW_Flash_PageErase( unsigned int page )
unsigned int HW_Flash_Read( unsigned int addr, unsigned int size, unsigned char *buffer )
unsigned int HW_Flash_NotEraseWrite( unsigned int addr, unsigned int size, unsigned char *buffer )
//擦除FLASH一页 (FLASH擦除的最小单元)
unsigned int HW_Flash_PageErase( unsigned int page )


按照以上模块化设计思想,很容易实现一模拟pos机。


以开发一个智能pos应用为例:


一个智能pos涉及到的功能模块有:


读写卡功能,保存与读取消费记录,查找保存黑名单,界面显示,菜单显示,通信下载参数上传记录等。


以下为移植功能模块到电脑上,自己做的一个模拟Pos工具:


在电脑上实现一模拟pos(只是功能上的实现,完成刷卡消费,记录存储,记录上传,黑名单,票价下载等功能。界面为Dos窗口。后续如果用QT把界面也做出来,就是一功能齐全的模拟POS机,不过得把荒废多年的C++重新拾起来了。可以继续完善做一个上位机模拟pos,改变编译器在上位机仿真调试并交叉编译后运行在真实POS上)。


用到的功能模块有 文件存储模块,卡处理模块,算法模块,银联库模块。我把这些模块移植到电脑上。


关于卡处理模块的实现,由于电脑上没读卡头,于是用外接读卡器。把读卡器串口接电脑上。

电脑上做一读写卡服务,提供TCP接口的读写卡接口。


移植文件库,嵌入式程序中是操作的flash,在电脑上把文件库中用到的接口用读写文件的形式替换。


移植算法库,算法库都是c写的,直接用gcc在windows平台重新编译即可。


实现效果:



第7项,模拟POS与银联通信:



POSP模拟器为模拟银联后台的一个工具。运行bus,exe进行签到,下载IC卡参数与公钥并保存至电脑上,



第5项,银联卡消费:



读卡器通过串口接到电脑上,电脑上运行读写卡服务tcpserver.exe,,提供读写卡APDU指令接口。利用之前做的小工具远程读卡器。



相关文章
|
6月前
|
人工智能 自然语言处理 开发工具
统一多模态 Transformer 架构在跨模态表示学习中的应用与优化
本文介绍统一多模态 Transformer(UMT)在跨模态表示学习中的应用与优化,涵盖模型架构、实现细节与实验效果,探讨其在图文检索、图像生成等任务中的卓越性能。
统一多模态 Transformer 架构在跨模态表示学习中的应用与优化
|
5月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
879 3
|
8月前
|
人工智能 监控 安全
NTP网络子钟的技术架构与行业应用解析
在数字化与智能化时代,时间同步精度至关重要。西安同步电子科技有限公司专注时间频率领域,以“同步天下”品牌提供可靠解决方案。其明星产品SYN6109型NTP网络子钟基于网络时间协议,实现高精度时间同步,广泛应用于考场、医院、智慧场景等领域。公司坚持技术创新,产品通过权威认证,未来将结合5G、物联网等技术推动行业进步,引领精准时间管理新时代。
|
7月前
|
存储 编解码 Serverless
Serverless架构下的OSS应用:函数计算FC自动处理图片/视频转码(演示水印添加+缩略图生成流水线)
本文介绍基于阿里云函数计算(FC)和对象存储(OSS)构建Serverless媒体处理流水线,解决传统方案资源利用率低、运维复杂、成本高等问题。通过事件驱动机制实现图片水印添加、多规格缩略图生成及视频转码优化,支持毫秒级弹性伸缩与精确计费,提升处理效率并降低成本,适用于高并发媒体处理场景。
359 0
|
3月前
|
人工智能 JavaScript 前端开发
GenSX (不一样的AI应用框架)架构学习指南
GenSX 是一个基于 TypeScript 的函数式 AI 工作流框架,以“函数组合替代图编排”为核心理念。它通过纯函数组件、自动追踪与断点恢复等特性,让开发者用自然代码构建可追溯、易测试的 LLM 应用。支持多模型集成与插件化扩展,兼具灵活性与工程化优势。
294 6
|
4月前
|
人工智能 Cloud Native 中间件
划重点|云栖大会「AI 原生应用架构论坛」看点梳理
本场论坛将系统性阐述 AI 原生应用架构的新范式、演进趋势与技术突破,并分享来自真实生产环境下的一线实践经验与思考。
|
4月前
|
机器学习/深度学习 人工智能 vr&ar
H4H:面向AR/VR应用的NPU-CIM异构系统混合卷积-Transformer架构搜索——论文阅读
H4H是一种面向AR/VR应用的混合卷积-Transformer架构,基于NPU-CIM异构系统,通过神经架构搜索实现高效模型设计。该架构结合卷积神经网络(CNN)的局部特征提取与视觉Transformer(ViT)的全局信息处理能力,提升模型性能与效率。通过两阶段增量训练策略,缓解混合模型训练中的梯度冲突问题,并利用异构计算资源优化推理延迟与能耗。实验表明,H4H在相同准确率下显著降低延迟和功耗,为AR/VR设备上的边缘AI推理提供了高效解决方案。
513 0
|
3月前
|
机器学习/深度学习 自然语言处理 算法
48_动态架构模型:NAS在LLM中的应用
大型语言模型(LLM)在自然语言处理领域的突破性进展,很大程度上归功于其庞大的参数量和复杂的网络架构。然而,随着模型规模的不断增长,计算资源消耗、推理延迟和部署成本等问题日益凸显。如何在保持模型性能的同时,优化模型架构以提高效率,成为2025年大模型研究的核心方向之一。神经架构搜索(Neural Architecture Search, NAS)作为一种自动化的网络设计方法,正在为这一挑战提供创新性解决方案。本文将深入探讨NAS技术如何应用于LLM的架构优化,特别是在层数与维度调整方面的最新进展,并通过代码实现展示简单的NAS实验。
|
5月前
|
Web App开发 Linux 虚拟化
Omnissa Horizon 8 2506 (8.16) - 虚拟桌面基础架构 (VDI) 和应用软件
Omnissa Horizon 8 2506 (8.16) - 虚拟桌面基础架构 (VDI) 和应用软件
291 0
Omnissa Horizon 8 2506 (8.16) - 虚拟桌面基础架构 (VDI) 和应用软件
|
7月前
|
消息中间件 存储 Kafka
一文带你从入门到实战全面掌握RocketMQ核心概念、架构部署、实践应用和高级特性
本文详细介绍了分布式消息中间件RocketMQ的核心概念、部署方式及使用方法。RocketMQ由阿里研发并开源,具有高性能、高可靠性和分布式特性,广泛应用于金融、互联网等领域。文章从环境搭建到消息类型的实战(普通消息、延迟消息、顺序消息和事务消息)进行了全面解析,并对比了三种消费者类型(PushConsumer、SimpleConsumer和PullConsumer)的特点与适用场景。最后总结了使用RocketMQ时的关键注意事项,如Topic和Tag的设计、监控告警的重要性以及性能与可靠性的平衡。通过学习本文,读者可掌握RocketMQ的使用精髓并灵活应用于实际项目中。
5373 9
 一文带你从入门到实战全面掌握RocketMQ核心概念、架构部署、实践应用和高级特性