嵌入式软件架构 - CSDN
精华内容
参与话题
  • 嵌入式系统软件架构浅析

    千次阅读 2019-10-24 11:26:24
    软件架构,就是软件的结构,包含软件元素(模块构件等)、外部接口及其相互关系。 1.软件架构的作用 做到嵌入式软件的代码逻辑清晰,且避免重复造轮子; 架构设计有利于软件的移植,没有架构,代码混乱,移植将...

    软件架构,就是软件的结构,包含软件元素(模块构件等)、外部接口及其相互关系。

    1.软件架构的作用

    1. 做到嵌入式软件的代码逻辑清晰,且避免重复造轮子;
    2. 架构设计有利于软件的移植,没有架构,代码混乱,移植将非常痛苦;
    3. 能最大限度地复用原有的代码;
    4. 使代码高内聚低耦合,维护和修改简单方便。

    2.设计思路

    2.1架构风格

    嵌入式系统软件与硬件联系紧密。首先想到要将硬件的驱动程序和功能应用的程序分开,且相对独立,做到高内聚、低耦合。最常用的方法就是模块化设计,就是将驱动程序、功能程序封装成一个个独立的模块,模块留出接口,方便组合(联想一下乐高的缺口)。

    另外,嵌入式软件除了有硬件,还有对硬件的功能操作、一些控制算法等,为了便于移植和扩充,我们可以采用分层的思想,将不同特性的代码放在不同的逻辑层上。

    简而言之,我们的嵌入式架构风格就是功能模块化设计、分层设计。

    2.2 架构分析

    ⑴模块化设计:

    将收集到的需求,进行归类,总结和分析,将这些需求概括为一个个单独的功能,每一个功能,做成一个单独的功能模块。

    用C语言编写模块时,需要理解以下几点:

    1. 模块由一个.c文件和一个.h文件组成,头文件(.h)中是对于该模块接口的声明
    2. 某模块提供给其它模块调用的外部函数及数据需在.h中文件中冠以extern关键字声明;
    3. 模块内的函数和全局变量需在.c文件开头冠以static关键字声明
    4. 永远不要在.h文件中定义变量,若头文件被多个源文件包含,则会多出几个内存单元。

    嵌入式系统通常包括两类模块:

    ①硬件驱动模块,一种特定硬件对应一个模块;

    ②软件功能模块,其模块的划分应满足高内聚、低耦合的要求。

    分层设计:

    1. 先把一个应用进行功能模块划分,并对整体结构进行分层,然后设计出功能独立的各个模块(如算法模块,文件库模块,通信库模块),在模块之上开放公共接口API。
    2. 功能模块对外调用的模块封装成一个个API,将底层驱动做个API以供功能模块调用。(各个功能模块可以独立编译(如通信模块纯ANSI C,可在任意平台复用),或者调用驱动层接口(日志库模块调用了驱动读写Flash),总之,封装出各个功能独立的可复用的功能模块。)
    3. API分为驱动层API和应用层API,而不是所有程序都调用驱动层API(整个应用中都调用驱动层API会导致应用中驱动调用随处可见,无法移植和最大限度的复用)

    层数不宜过多

    分层结构有利于清晰的划分系统职责,实现系统的解耦,但是每多一个层次,就意味着性能的一次损失。尤其是当层和层之间需要传递大量数据的时候。对嵌入式系统而言,在采用分层结构时要控制层次数量,并且尽量不要传递大量数据,尤其是在不同进程的层次之间。如果一定要传递数据,要避免大量的数据格式转换,如XML到二进制,C++结构到Python结构。嵌入式系统能力有限,一定要将有限的能力用在系统的核心功能上。

    ⑷举例说明:

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

    对于简单的嵌入式系统,可能不需要分这么多层,有时只要应用层和硬件驱动层即可。

    总体结构示意框图:(下面是带操作系统的)

    以上只是举例,具体架构要根据项目的实际情况设计

    说明:
    1.层与层之间不能跨层调用。
    2.模块与模块各自独立,无依赖关系。
    3.模块提供统一的接口供上层调用,模块的内外接口分明。
    4.模块的功能只能增,不能改。
    5.各个功能模块层也还可以进行继续分层,比如接口层、驱动层、硬件层。

    2.3 模块层次说明

    硬件抽象层(HAL

    硬件抽象层包含板载硬件资源正常运行所需的所有驱动程序并提供API给功能模块调用。

    通常硬件驱动模块包括:

    ①硬件初始化——设置硬件参数,分配所需资源,如内存、中断向量等;

    ②设备操作接口函数——完成设备指定的功能;

    ③中断服务程序——系统通过中断服务程序实现与外部事件的交互(对应OS内核的中断对象)。

    HAL包括两层:

    1. 底层是片内外设驱动;
    2. 上层是板级支持包(BSP):硬件模块初始化、操作接口、ISR。

    功能模块层

    功能模块层包括实现具体功能的函数,通过调用驱动层API实现相应功能,同时提供可调用的API给业务逻辑层。

    该层也可以称为中间件(middleware),提供具有标准程序接口和协议的通用服务,取得了相对稳定的应用软件开发和运行环境。

    业务逻辑层

    业务逻辑层包括产品整体功能的各个业务流程,通过调用功能模块层的API实现。

    应用层

    应用层将各个业务逻辑进行整合调用,完成整个产品的功能。

    3.最后

    最后提出一个问题,为什么要用面向过程(OP)的程序设计,而不用面向对象(OO)?
    要解答这个问题,我们先问下面几个问题:
    ①系统中有多个相同或相似类型的实体吗?
    ②面向对象操作是否更容易组织和编写代码?
    如果这两个答案都是否定的,则用面向过程的程序设计。
    面向过程程序设计,向上层提供的是模块操作接口;面向对象程序设计,向上层提供的是模块抽象的类结构(或对象)。
    在面向过程的编程中,也可以部分使用面向对象编程。

     

    展开全文
  • 起因 继前一篇介绍了一些别人家的代码架构之后,其实最近实践了一下,还是有些感悟。又参考了一些文档,觉得还是要记录一下,最近整理代码的心得。...随便上百度搜了一张嵌入式软件架构图为例...

    起因

    前一篇介绍了一些别人家的代码架构之后,其实最近实践了一下,还是有些感悟。又参考了一些文档,觉得还是要记录一下,最近整理代码的心得。

    整理系统架构,主要就是为了:

    • 方便移植
    • 便于复用
    • 模块增加删减方便

    其实整理代码结构,最主要想实现的就是:

    • 高内聚
    • 低耦合

    这样的代码方便移植管理,流程接口明确。

    一般的架构图主要就是两部分:

    • 分层
    • 分模块

    随便上百度搜了一张嵌入式的软件架构图为例。
    在这里插入图片描述

    20200611补记:
    最近在看韦东山的课程和linux源码。其实我所总结的分层分模块就是linux中的上下分离,左右分离。不过linux中的左右分离,分的不仅仅是模块,而是又抽象了设备、驱动、总线 等等。

    1. 分层设计

    分层设计,就是把整个流程要做的事情按照模块化各自的特征,进行功能的分层,是和硬件寄存器打交道的,还是完全脱离硬件和业务打交道的。
    一般来说,个人总结有几个原则

    1. 接口是上下级调用,很少跨层调用。即第4层的代码一般不会直接去第1/2层调用接口,非要用的话,就从第3层透传封装一下。
    2. 同层级的模块间尽量避免相互调用,需要的数据都是通过高一层的接口获取再下传

    1.1 单片机程序

    单片机程序就是一个程序驱动硬件,实现一个具体功能,代码特点就是从底到高,基本所有层都会涉及,所以对单片机程序进行分层,相对来说会比较完整。

    找到了别人的一些设计,我觉得还挺全面的。

    5层软件架构

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

    6层软件架构

    • HAL硬件抽象层
    • OSL操作系统层
    • HDL硬件驱动层
    • FML功能模块层
    • BLL业务逻辑层
    • APL应用层

    简单列了一下每层功能如下:

    简写 含义 包含 说明
    HAL Hardware Abstract Layer
    硬件抽象层
    内核驱动
    寄存器配置
    主要是对SFR的配置,不同芯片把这部分封装起来
    OSL Open System Layer
    操作系统层
    操作系统(eg:FreeRTOS)
    文件系统(eg Fatfs)
    GUI
    这是上文作者分的,按笔者的看法,这一层的意义不大
    HDL Hardware Drvier Layer
    硬件驱动层
    对HAL层和OSL层进行封装,因为HAL层一般是厂家提供,不是特别方便直接使用
    对一些非片内的硬件资源(HAL库不提供)进行驱动
    FML Functional Module Layer
    功能模块层
    按照功能模块来做划分
    BLL Business Logic Layer
    业务逻辑层
    按照流程来调用功能模块工作
    APL Application Layer
    应用层
    运行不同的流程,笔者认为APL 和 BLL的界限不是特别明显

    对于这个表,其实看起来有些繁琐了,层级分的太多,隔离的太彻底,有时候反而增加了无谓的损耗。

    依笔者的看法,比较简单实用的系统就是分四层或者五层。
    操作系统层没有太多必要。
    BLL和APL有时可以合并。
    HAL和HDL有时可以合并。

    • HAL:对SFR的配置,主要针对片内资源
    • HDL:对厂家给的HAL库进行进一步封装,对于每个真实物理外设有接口
    • FML:功能模块层,封装到
    • APL:应用层

    1.2 混淆概念

    分层概念中,比如容易混淆的就是HAL和HDL。
    区别这里总结的很好:
    硬件抽象层和硬件驱动层的主要区别

    借一张图和一段话来说明:
    在这里插入图片描述

    功能模块层是按照项目需求提取出来的功能,需要硬件抽象层和硬件驱动层的硬件支持才能实现,功能模块层根据项目的功能需求改变而改变,而硬件抽象层和硬件驱动层则是项目需求书中的功耗等硬件相关的需求变动而改变,当然,若子功能的增加而硬件不支持,则也需更换硬件驱动。比如项目中的数据储存功能,硬件支持有AT24C02、W25Q128和芯片本身的FLASH,都可以支持数据储存功能,即使后期因为功耗或节约成本等问题,硬件的更换也不影响数据储存功能的实现(前提规划好标准规范的API函数定义)且避免了重写该功能代码所带来的各种问题,保证了该功能的稳定性。

    1.2 计划代码结构:

    • Doc
    • Code
      • HAL
        • Core
        • Hal
        • Startup
      • HDL
        • Gpio对HAL再封装
        • Flash对HAL再封装
        • Uart对HAL再封装
        • Mpu6050
        • 加密芯片
      • FML
        • ThirdParty
        • eg:PumpCtrl:封装了泵的串口控制协议
        • eg: ValueCtrl:封装了阀的串口控制协议和IO控制协议
        • eg: StrrierCtrl:封装了搅拌器的控制
      • BLL
        • eg: WarnProcess
        • eg:CtrlProcess
      • APL
        • main.c
    • Project
      • SI
      • Keil5
      • VsCode
      • CubeIDE

    2. 模块设计

    其实分层设计好之后,模块化相对来说就简单很多。
    做模块化设计的优势就在于方便移植,如果应用层的流程变了,直接改流程就行,FML的模块都不用改。
    如果模块变了,比如阀型号变了,只要另外写一个阀功能模块,能兼容以前的模块接口,即可。

    3. 几个实践中的疑问:

    1. 同层模块间能不能相互调用?即使是通过上层模块传递,那结构体怎么处理?接口可以不调,但是头文件要包含的。
    2. 如果是公用的结构体,是放到公用模块,还是每个模块自己维护自己的结构体?还是接口入参不传结构体,都用最简单的int ,char 这种。如果放到公用模块,但是这个结构体明显又是私用的,属于某个模块特别明显的,怎么办?

    4. 总结

    其实单片机的程序相对来说,还是比较简单的,简单的程序,分层太多,反而有时候过于拘泥于形式。
    复杂的程序,就上系统了,比如linux,这样就会有别的大师给你做好架构,你只需要按照这个框架进行填充即可。
    这也是为什么嵌入式的架构师需求不大的原因。
    在上一篇的Demo中,能看出很多厂家其实都是直接分3层,底层,中间层,应用层,简单粗暴,底层和硬件相关,类似本文的HAL和HDL,中间层就是协议,模块,类似本文的FML,应用层就是应用。
    其实都是一样的,看个人偏好吧,不要太在意分层这个形式。

    展开全文
  • 我从事嵌入式软件开发有6,7个年头,bsp,驱动,应用软件,android hall,framework等都有涉猎。平时除了关注嵌入式行业的发展,也多少对Web,后台服务端,分布式等方向的技术有一些关注。 近期有萌生换个行业...

     

    我从事嵌入式软件开发有6,7个年头,bsp,驱动,应用软件,android hall,framework等都有涉猎。平时除了关注嵌入式行业的发展,也多少对Web,后台服务端,分布式等方向的技术有一些关注。

     

    近期有萌生换个行业方向的想法,想做做后台服务器相关的开发,由于之前工作中并没有这方面的实际需求,只是自己平时关注,了解了些知识,比如:NIO,epoll,ngnix,zeromq,libevent,libuv,高并发,分布式,redis,python,tornado,django,涉猎比较杂,都了解个皮毛,不精。意外的是屡屡被互联网行业鄙视,面试机会都寥寥无几。

     

    此时我想到底是什么问题呢,难道嵌入式出身的已经这么不受待见了吗?想当初,嵌入式,驱动开发,可是趋之若鹜的行业(有点夸张,不过8,9年前嵌入式可是听着比做java web的要牛逼些哦)

     

    问题总是有原因的,我说下自己的理解:

     

    嵌入式是否真的高大上之为什么没有嵌入式软件架构师?

     

    打开各种招聘网站,搜索架构师,会出现各种系统架构师,web架构师,后台服务端架构师等等,但是唯独很难看到嵌入式软件架构师。嵌入式软件不需要架构吗,驱动不需要架构吗?答案是当然需要,不过为什么没有这方面的职位?

     

    我的看法:目前国内的嵌入式开发主要分为嵌入式底层开发和嵌入式应用开发,嵌入式的底层开发一般叫做驱动开发,或者bsp开发,有时也有称之为linux内核开发,名字听着都很高大上的感觉。

     

    这么高大上的名字为什么没有架构师呢:linux kernel的架构师是linus等一众linux kernel开发维护者,因为本身linux kernel或者操作系统就是一个通用的平台,解决通用的问题,linux开源届的大牛都已经制定好了架构规则,留给可发挥的地方并不多,大部分工作只需要按照规则框架填充就可以了,而且以目前国内大部分公司的业务需求,只是在做外围设备的集成,嵌入式平台的porting,搭建裁剪,业务需求完全不会超过kernel里提供的功能范围。导致没有什么新的架构需要开发人员去设计,实现。那嵌入式bsp开发人员都在做什么:除了调试多种多样的外设,替硬件擦屁股,就是解些稳定性的bug了(这里对具体工作不详细描述了,调试外设只会增加一些经验,增加广度,对提高深度贡献不大,只是按不会调试-》会调试-》调试的快这个路线发展,而解稳定性问题确实是需要一些积累经验)

     

    而嵌入式上的应用开发,一般业务逻辑比较简单,被很多人忽略,所以招聘方也会感觉没有什么必要找架构师级别的了。

     

    至此感觉嵌入式行业的确不需要架构师,被互联网行业的鄙视也没什么大惊小怪的。

     

    但的确是这样子的吗?对于嵌入式底层的开发,有能力对kernel,驱动架构提出架构层优化的,国内的开发人员应该不多,所以对于大部分普通人,还是不要“妄想”做Linux kernel的架构师了(当然我相信国人中一定存在有这个能力的大牛),发现,解决一些bug,到更靠谱些。

     

    那么对于嵌入式应用层的开发,我们真的不需要架构吗?

     

    以自己的实际经历讲述下曾经对一个嵌入式设备应用软件的架构设计和优化:

     

    我曾经接手过一个项目,项目采用单进程多线程的模型,项目中包括几个模块,以a, b, c, d,e代表。这个项目的业务逻辑决定这几个模块有不少关联。

     

    例如:最初的设计中a模块是一个状态监测模块,它会基于监测到的状态调用b,c模块的接口实现一些功能(多线程的好处就是直接调用很方便,所以开发人员大多这么干,简单粗暴),但是需求总是千变万化,加入一个f模块,f模块也需要对a模块监测的状态进行一个处理,按照之前的套路,完成这个功能分两步:1,在f模块提供个接口,2,在a模块中调用该接口。至此新需求已经“完美”的解决了。

     

    前面提到需求总是千变万化的,新的需求又来了,客户提出定制需求,需要加入另一个g模块,同样处理a模块监测的状态,但是该定制需求不需要刚刚加入的f模块,此时最简单粗暴的方式是,定义一个宏,区分该定制需求和之前的通用需求,build两个程序版本。这样的做法看似简单,但后面如果定制需求逐渐增多,维护这么多定制版本程序就是个噩梦,代码管理和通用性也会是很大的问题,同时代码中充斥着对不同宏定义的差异化处理,#ifdef xxx;do_something;#endif比较好的做法是加入设备型号版本的动态监测,用一个build程序版本动态支持所有的定制需求,这样减少了对不同build程序的维护。但是这种做法只解决build程序的版本维护工作,没有解决宏定义差异化处理的问题,只是会将之前的宏判断,改为动态设备版本号判断,如果这些差异化的判断只集中在一处进行,也不会引起大的复杂化的问题,但显然这个是不好保证,有可能这些差异化的处理会蔓延到整个项目的各个角落,这样项目维护起来就会变成一场噩梦。

     

    不需要什么高深的软件思想,大部人都会想到把差异化的部分提取出来,放在一个统一的地方集中管理,对差异化的修改只集中在这个统一管理的地方。

     

    通用做法就是采用callback设置钩子,然后在callback中定制差异化的需求,对callback的处理做差异化的配置,对应到上面例子,就是在a模块添加一个钩子,然后在系统初始化时,根据设备版本号的不同,差异化定制callback处理函数,同时要将这些定制callback处理函数放在同一地方处理,否则仍然分散在各个角落里就没有意义(前一种方式不放置钩子是无法将这些差异化配置放在一起的),这样处理带来的另外一个好处是,我们对功能性需求的改变,不会影响到a模块的处理,也就是我们添加功能,不需要修改a模块的代码了(前一种方式要修改a模块的调用流程),这样也就实现了一个模块的分离。

     

    至此第二种的方案的架构(其实也谈不上架构了)相比第一种方案已经有了不少提升,至少让开发人员稍微轻松了些,对于其他定制需求,开发人员之需要修改这个callback处理,关注差异化部分就可以了。

     

    软件是需要不断进化的,第二种方案是最优解吗,当然不是,还有优化空间吗?

     

    下面先跑个题,谈谈多线程/多进程模型的优缺点,主要谈多进程的优点了:

    教科书上的解释就不提了,首先我对大的项目是推崇多进程模型,无关性能,主要原因有:

     

    模块的解耦:很多开发人员维护开发的多线程模型项目应该都多少会存在下面的问题:跨模块间的直接调用,如果不相信,好,你的项目一定是分模块的吧,现在随机的删掉一个模块,build下看能build通过吗(只需要build不需要运行),我相信大部分情况下一定会遇到某个函数调用,某个全局变量找不到的情况,这种情况说明你的模块间存在强耦合了。由于多线程天然的优势,地址空间的相互可见,导致直接调用十分容易,很多经验尚浅的工程师,很容易就写出直接调用的简单粗暴的接口,如果遇到个static接口的函数,图方便也会把static去掉,直接拿过来用了。这样整个工程随着功能不断的添加,模块间的交叉越来越多,耦合越高。

     

    而我之所以推崇多进程的原因就是,多进程能从物理上隔绝了这种“方便”的通讯方式,导致在想实现一个模块交互时,会多思考下这个交互是必要的吗,如果是必要的,则会进一步思考接口定义是否简单明了(因为进程间的通讯相对会麻烦些,开发人员会本着能减少交互,明确接口的想法去仔细考虑接口,协议的定义,否则折腾的是自己了),这如同人生,如果一直顺风顺水,人们可能不会想太多,思考太多,而如果道路上有些坎坷,则会有另一种感悟吧。

     

    所以我的想法是多进程的模型会逼迫你去更多的思考想程序的设计,物理上减少模块的耦合。

     

    抽象通用组件,分离通用功能和业务逻辑功能:当把一个多线程模型修改为多进程模型的过程中,经常会发现有些接口代码重复的出现在多个进程模块中,因为之前接口函数是在一个进程空间,大家都可以直接调用的,比如接口A被模块a,b调用,模块a,b分离为两个独立的进程后,接口A需要在a,b中分别实现了,无需解释,重复代码这个在软件工程中是大忌,必须消除。做法也很简单,将这些被多个模块调用的接口分离处理做成lib,供其他模块调用,当你完成这部分工作后,你发现了什么,是不是剥离的接口,可以作为整个项目的通用组件存在了,完美的情况下,lib下的代码是通用基础组件,各个模块中是独立的业务处理模块。

     

    方便定位问题:多线程模型中当又一个线程异常退出,会导致整个进程退出,当然通过一些crash信息,可以定位是那个线程死掉,但如果这些线程模块是由多个小组,人员维护,当整个进程崩溃掉后,如何判断由那个小组解决,会是一个大的问题,而且有时还会出现的现象是挂在一个线程,但其实是另外一个线程模块引起的(耦合的祸端),遇到这种情况,难免出现小组间的扯皮,推诿。(自信的工程师都认为我的代码没有问题)

     

    而如果采用多进程的模型,好吧,你的服务进程挂了,你自己找原因吧,没什么可争辩的了。

     

    方便性能测试:多线程种单个线程的资源占用不是很好查看(至少有些嵌入式系统没有完善的命令),当整个进程资源消耗很高时,如何判断定位时那个模块线程的问题,同3一样难以抉择,而如果是多进程的模型,谁的进程占了好多资源,谁就去查下吧,其实这个还是个颗粒度的问题,同样的系统,划分成多个进程,单个进程的复杂度一定比只有一个进程的复杂度低的多,复杂度降低,也就更容易定位查找各种问题。

     

    分布式部署:互联网行业一直强调的分布式,云啊什么的,嵌入式行业就很苦逼了,貌似不需要什么分布式吧,其实也对,大部分情况下,嵌入式采用单芯片,独立运行,分布式遇到的很少。但如果万一那天你在一个设备中,将本来一个芯片完成的功能分散到两个芯片中处理呢,多进程的扩展就容易的多了。

     

    这只是举个特殊的例子,其实嵌入式设备就是个分布式的行业,只是一开始就已经实现分离了,而不是从集中到分布式的路线发展起来的。

     

    方便公司的代码权限隔离:其实我鄙视这种做法,公司要相信自己的员工,但鉴于诚信在中国已经。。。。,做些隔离也无可厚非了。

     

    多线程模型下,前面讲到如果去除一个模块,你可能都不能build了,那么是要把所有代码暴露给所有的工程师吗,显然不能,所以各个模块只能提供库的形式了,不过我觉得将通用功能接口组织成通用库是正常的做法,而如果把和业务相关的模块也提供成库,就有点。。。。

     

    至此在补充一下,以上所有的优点,其实都不是很关键的点,都不能够让多进程有绝对的优势压倒多线程模型,只是从个人的角度觉得,多进程模型更能强迫工程师思考解决一些问题。(而这些问题有经验的工程师无论什么模型都会思考的)

     

    上面说了这么多,该考虑下把之前项目的例子改成多进程模型,否则就只是纸上谈兵了,下面开始:

    首当其冲的问题就是:选择多进程的通讯方式,多线程间的直接调用是不能用了,那么如何选择多进程的通讯方式呢?

     

    linux下提供很多ipc方式,此处不一一列举,对于非大数据量的控制,通讯消息的传递,比较好的方式是采用socket,本机上更多采用unix socket方式,(这种方式有什么好处?当你有需要把单一系统做成分布式系统时,优势就明显了)

     

    但是仅仅采用socket来实现前面例子的功能,同样会存在一些问题:

    还是前面的例子,首先说明前面我们优化后的第二种方案在多进程模型已经不能在继续使用了,原因比较简单,应该不需要解释。。。

     

    简单的做法即基于方案一,把直接调用改为socket通信(定义好通信协议即可),但是熟悉socket开发的工程师都清楚,开始socket通信要先进行一些前期的工作(主要就是连接,将两个模块关联起来),所以前面的例子会变成这个样子,模块a要和模块b,c建立连接,如果加入f模块,模块a还要和f模块建立连接。这样情况在心里画一张连接图就会发现好像我们织了一张蜘蛛网,节点间的关系错综复杂,而且和方案一一样,我们添加一个和a关联的模块,就要修改模块a的代码,而且这种情况比多线程模型还有繁琐复杂的多了。这种做法绝对是个噩梦。

     

    好吧如何解决,我想很多人一定想到了采用总线分发的方式。了解android系统开发的会想到binder,了解openwrt的会想到ubus,了解桌面会想到dbus,互联网行业的开发者一定也知道redis里提供的sub/pub模块。

     

    上面的binder,ubus等原理很简单,就是建立一个消息中心,构建一个转发路由模型,所有其他模块之间不直接交互,而是采用消息中心转发,路由,而如何决定路由规则,则采用订阅/发布的观察者模式来进行规则的定义。(嵌入式开发或者c语言开发者,经常会误以为设计模式是和面向对象语言关联的,是面向对象语言独有,虽然有很多大牛做了这方面的普及,但鉴于有些开发者的信息渠道比较闭塞,导致这种想法仍然十分盛行)

     

    基于这个模型,我们上面例子的需求就很好解决了,加入一个消息中心模块,所有需要通信的模块只同该消息中心模块连接,然后订阅自己感兴趣的事件,当事件发生时,只需要进行相应的处理就可以了。

     

    这样上面的模块b,c订阅模块a的事件,当模块a检测到某事件时,发布该事件,该事件先到达消息中心,在由消息中心转发给模块b,c,而对于新加入的模块f,也只需要订阅该模块,而不需要在修改到模块a的代码,使功能的扩展十分方便。

     

    同时对于前面提到的定制化开发同样得到了简化,如果定制化版本需要加入模块g,这样只需要定制化版本中将模块g作为一个独立进程启动,然后订阅模块a的事件即可,而定制版本和通用版的区别就在于是否启动模块g的进程,从而实现了软件工程的一个目标:功能的添加如同搭积木一样,只需要把一个模块插入(启动)或拔出(不启动)即可,功能的改变只局限在一个或某几个模块间,对主体框架不会有任何影响。

     

    以上大概描述了对一个项目需求逐步优化的过程,例子看似是基于嵌入式项目,但貌似对软件工程同样适用。

     

    来到互联网行业:

    查看下各大网站架构师对本网站技术架构变革分享的文章,首先提到的一般都是,基于业务将之前的一个应用服务器功能拆分,更加细化(比如电商对登录,注册,交易,商品,卖家等业务服务的拆分),然后将拆分出来的服务部署在多台服务器上,来提供并发。这里是否有些耳熟,和前面讲到的多线程到多进程的划分是否有相似呢。

     

    拆分后同样遇到通信的问题,此时很多消息中间件应运而生,比如阿里的duboo,简单了解下这些中间件的原理,无外乎订阅发布,RPC等机制,可以说大同小异,而难点在于协议的制定和性能处理的提升。

     

    在对照下互联网行业的负载均衡方案,仿佛那个负载均衡的前端也像一个消息中心了。

     

    上面说了这么多,只是想说明一个问题,软件的设计是相通的,基于的思想是相同的,虽然嵌入式行业的业务逻辑相对比较简单,但其实在仔细思考后,仍然会有很多架构上的改进,设计。

     

    但是让我感到悲哀的是,有些嵌入式开发者,鉴于业务逻辑的简单,感觉采用一些不那么好的处理方式也能解决问题,不去思考如何去优化,改进。比如上面例子的方案一,如果在定制需求不多的情况下,维护起来也没太大问题,即使定制需求多了,再招些初级程序员也能维护的过来,一个人一套代码负责一个项目的公司也不是不存在。

    同样互联网行业和嵌入式行业也不应该存在一个不可以逾越的高墙,我们更应该关注的是通用的软件工程思想。 

     

    免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我联系,将根据您提供的版权证明材料确认版权并删除内容。

    展开全文
  • 嵌入式软件架构设计

    万次阅读 2018-08-31 11:49:26
    在开发中一直觉得好的软件架构可以做到事半功倍,而且可以做到代码复用和移植。 但是如果没有架构或者说架构很差,那么移植将是很痛苦的事,特别是对不熟悉改功能的人来讲还不如自己写呢,移植不对那将是很头疼的事...

    摘要

    在开发中一直觉得好的软件架构可以做到事半功倍,而且可以做到代码复用和移植。

    但是如果没有架构或者说架构很差,那么移植将是很痛苦的事,特别是对不熟悉改功能的人来讲还不如自己写呢,移植不对那将是很头疼的事。

    所以随着开发越来越多,渐渐的发现我们考虑问题应该从广度和深度来考虑,做新项目的时候,更应该考虑到以后出现的可能性,比如说需求变更,底层变更,所以这个时候软件的架构和程序模块化就很重要。

    我们不能做牵一发而动全身的事,所以提出了软件架构的一些想法。

    基本框架图

    (1)架构设计的目的

    1、应用的代码逻辑清晰,且避免重复的造轮子。

    2、如果没有好的架构,移植将会是一件很痛苦的事情,因此一个好的架构设计,方便软件的移植。

    3、最大限度的复用。

    4、高耦合低内聚。 

     

    (2)设计思路

    如何把硬件的驱动和一个功能封装成一个个的模块,然后可以像小朋友搭积木一个,一个个模块可以快速的拼接起来,组成一个个不同的模型。

    我们的嵌入式架构思路也是来源于此,即功能模块化设计、分层设计。

    模块化设计:将收集到的需求,进行归类,总结和分析,将这些需求概括为一个个单独的功能,每一个功能,做成一个单独的功能模块。

    分层设计一句话不好直接表达,其主要体现在一下几方面:

    1、功能模块对外调用的模块封装成一个个API,将底层驱动做个API以供功能模块调用。(各个功能模块可以独立编译(如通信模块纯ANSI C,可在任意平台复用),或者调用驱动层接口(日志库模块调用了驱动读写Flash),总而言之,言而总之,封装出各个功能独立的可复用的功能模块。)

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

     

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

    总体结构示意框图:

     

    说明:

    1.层与层之间不能跨层调用。

    2.模块与模块各自独立,无依赖关系。

    3.模块提供统一的接口供上层调用,模块的内外接口分明。

     

    (3)模块层次说明

    硬件驱动层

    硬件驱动层包含板载硬件资源正常运行所需的所有驱动程序并提供API给功能模块调用。

    功能模块层

    功能模块层包括实现具体功能的函数,通过调用驱动层API实现相应功能,同时提供可调用的API给业务逻辑层。

    应用层

    应用层对业务层提供使用到的接口。一般可以和功能模块层划归一层

    业务逻辑层

    业务逻辑层包括产品整体功能的各个业务流程,通过调用功能模块层的API实现。

    应用层

    应用层将各个业务逻辑进行整合调用,完成整个产品的功能。

     

    (4)优势

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

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

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

    开发心得

    除了软件架构,良好的编程习惯就显得很重要,特别是做到归类,对于用不到的代码应该及时清理,对于一些变量和数据结构的定义等应该集中,还有就是代码的注释,代码的简洁,尽量做到不写效率低下的代码。总之,每个人都有自己的习惯和对编程的认识,只要能在过程中提升就是进步。加油 老铁们!

    展开全文
  • 嵌入式软件架构的设计

    千次阅读 2019-02-18 22:00:35
    嵌入式软件架构的设计 大多数嵌入式程序员学习编程,都是从开发板的附带例程开始。之后工作也会继续参考那些例程,很多编程习惯、方式也会受之影响。 其实开发板式的编程方式与工作中实际需求的并不完全一致。 ...
  • 如何用一个实例来探讨嵌入式软件架构设计

    万次阅读 多人点赞 2018-07-01 20:50:04
    一、感慨近公司新招了一个做嵌入式软件开发开发的童鞋,该童鞋是从上海的某一个上市公司出来的,因为我们这边人手不够,因此把他安排了去负责一个新产品的研发,前期让他负责加速度计、NB-IOT、舵机、外置Flash的...
  • 我从事嵌入式软件开发有6,7个年头,bsp、驱动、应用软件、android hall、framework等都有涉猎。平时除了关注嵌入式行业的发展,也多少对Web、后台服务端、分布式等方向的技术有一些关注。 近期有萌生换个行...
  • 关于嵌入式软件架构的一点理解

    千次阅读 2016-01-24 19:54:16
    本人学生,在参与企业开发的过程中了解到关于嵌入式软件框架设计问题,通过不断的深入学习,本人决定在乘着广州的雪意书写此文章。
  • 嵌入式软件架构设计之分层设计

    千次阅读 2020-01-16 03:15:29
    关注、星标公众号,不错过精彩内容整理:黄工素材来源:网络参考来源:https://blog.51cto.com/kenotu/1614390在正规的项目开发中,项目往往是并行开发的,也就...
  • SoC嵌入式软件架构设计

    千次阅读 2016-02-26 20:36:45
    内存是SoC(System on Chip,片上系统)集成设计的重要...系统内存需求评估是对嵌入式软件架构师的最基本要求,同时也是其最重要的技能之一。一般在SoC项目立项的时候,架构师就要完成系统内存需求评估。  下面以一个
  • 我是做智能电表嵌入式软件开发的,因项目需要,现打算设计一个软件架构以实现模块化编程,同时兼顾单相、三相电表。同时,方便多人合作开发、方便以后维护。大家不知有什么好的建议?
  • 嵌入式应用软件架构设计

    万次阅读 多人点赞 2019-08-07 17:40:36
    要做到嵌入式应用的代码逻辑清晰,且避免重复的造轮子,没有好的应用架构怎么行。 如果没有好的架构,移植将会是一件很痛苦的事情。 如果没有好的架构,复用是最大的难题,没法更大限度的复用原有的代码。 如果...
  • 本文继续阐述基于低端控制器CPU的SoC固件架构设计。这一节讲述内存空间的具体规划分配,包括嵌入式固件系统软件层次、程度段组成、物理内存分块设计和具体的程序内存空间分配原则。
  • 嵌入式单片机软件架构

    千次阅读 多人点赞 2019-01-25 22:20:55
    经过几天的回忆与思考,分析了我的成长路径,选择一些我自认为是成长关键点的位置,总结一个关键字,一步一步来讨论关于嵌入式单片机软件架构。 我先把总结出的关键字写出来吧:**流水式、中断前后台、任务式、...
  • 所以就让我这个老程序员浅谈一下嵌入式软件架构设计。 我参考的也是一篇博文。原图如下 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190815141639688.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5...
  • 嵌入式系统软件架构设计

    千次阅读 2019-04-24 14:58:12
    嵌入式系统软件架构设计 目录 1.前言4 2.决定架构的因素和架构的影响4 2.1.常见的误解5 2.1.1.小型的系统不需要架构5 2.1.2.敏捷开发不需要架构7 3.嵌入式环境下软件设计的特点7 3.1.和硬件密切相关7 3.2...
  • 嵌入式软件开发之程序架构(一)

    千次阅读 2019-02-24 14:23:49
    嵌入式软件开发过程中,程序架构的搭建尤为重要,下面介绍三种常用的程序框架设计方案: 前后台顺序执行法、时间片论法、操作系统 1、前后台顺序执行法: 这是初学者们常用的程序框架设计方案,不用考虑太多东....
1 2 3 4 5 ... 20
收藏数 58,257
精华内容 23,302
热门标签
关键字:

嵌入式软件架构