嵌入式系统软件架构浅析
软件架构,就是软件的结构,包含软件元素(模块构件等)、外部接口及其相互关系。
1.软件架构的作用
- 做到嵌入式软件的代码逻辑清晰,且避免重复造轮子;
- 架构设计有利于软件的移植,没有架构,代码混乱,移植将非常痛苦;
- 能最大限度地复用原有的代码;
- 使代码高内聚低耦合,维护和修改简单方便。
2.设计思路
2.1架构风格
嵌入式系统软件与硬件联系紧密。首先想到要将硬件的驱动程序和功能应用的程序分开,且相对独立,做到高内聚、低耦合。最常用的方法就是模块化设计,就是将驱动程序、功能程序封装成一个个独立的模块,模块留出接口,方便组合(联想一下乐高的缺口)。
另外,嵌入式软件除了有硬件,还有对硬件的功能操作、一些控制算法等,为了便于移植和扩充,我们可以采用分层的思想,将不同特性的代码放在不同的逻辑层上。
简而言之,我们的嵌入式架构风格就是功能模块化设计、分层设计。
2.2 架构分析
⑴模块化设计:
将收集到的需求,进行归类,总结和分析,将这些需求概括为一个个单独的功能,每一个功能,做成一个单独的功能模块。
用C语言编写模块时,需要理解以下几点:
- 模块由一个.c文件和一个.h文件组成,头文件(.h)中是对于该模块接口的声明;
- 某模块提供给其它模块调用的外部函数及数据需在.h中文件中冠以extern关键字声明;
- 模块内的函数和全局变量需在.c文件开头冠以static关键字声明;
- 永远不要在.h文件中定义变量,若头文件被多个源文件包含,则会多出几个内存单元。
嵌入式系统通常包括两类模块:
①硬件驱动模块,一种特定硬件对应一个模块;
②软件功能模块,其模块的划分应满足高内聚、低耦合的要求。
⑵分层设计:
- 先把一个应用进行功能模块划分,并对整体结构进行分层,然后设计出功能独立的各个模块(如算法模块,文件库模块,通信库模块),在模块之上开放公共接口API。
- 功能模块对外调用的模块封装成一个个API,将底层驱动做个API以供功能模块调用。(各个功能模块可以独立编译(如通信模块纯ANSI C,可在任意平台复用),或者调用驱动层接口(日志库模块调用了驱动读写Flash),总之,封装出各个功能独立的可复用的功能模块。)
- API分为驱动层API和应用层API,而不是所有程序都调用驱动层API。(整个应用中都调用驱动层API会导致应用中驱动调用随处可见,无法移植和最大限度的复用)
⑶层数不宜过多
分层结构有利于清晰的划分系统职责,实现系统的解耦,但是每多一个层次,就意味着性能的一次损失。尤其是当层和层之间需要传递大量数据的时候。对嵌入式系统而言,在采用分层结构时要控制层次数量,并且尽量不要传递大量数据,尤其是在不同进程的层次之间。如果一定要传递数据,要避免大量的数据格式转换,如XML到二进制,C++结构到Python结构。嵌入式系统能力有限,一定要将有限的能力用在系统的核心功能上。
⑷举例说明:
总体分成:硬件驱动层-->功能模块层-->业务逻辑层-->应用层。
对于简单的嵌入式系统,可能不需要分这么多层,有时只要应用层和硬件驱动层即可。
总体结构示意框图:(下面是带操作系统的)
说明:
1.层与层之间不能跨层调用。
2.模块与模块各自独立,无依赖关系。
3.模块提供统一的接口供上层调用,模块的内外接口分明。
4.模块的功能只能增,不能改。
5.各个功能模块层也还可以进行继续分层,比如接口层、驱动层、硬件层。
2.3 模块层次说明
⑴硬件抽象层(HAL)
硬件抽象层包含板载硬件资源正常运行所需的所有驱动程序并提供API给功能模块调用。
通常硬件驱动模块包括:
①硬件初始化——设置硬件参数,分配所需资源,如内存、中断向量等;
②设备操作接口函数——完成设备指定的功能;
③中断服务程序——系统通过中断服务程序实现与外部事件的交互(对应OS内核的中断对象)。
HAL包括两层:
- 底层是片内外设驱动;
- 上层是板级支持包(BSP):硬件模块初始化、操作接口、ISR。
⑵功能模块层
功能模块层包括实现具体功能的函数,通过调用驱动层API实现相应功能,同时提供可调用的API给业务逻辑层。
该层也可以称为中间件(middleware),提供具有标准程序接口和协议的通用服务,取得了相对稳定的应用软件开发和运行环境。
⑶业务逻辑层
业务逻辑层包括产品整体功能的各个业务流程,通过调用功能模块层的API实现。
⑷应用层
应用层将各个业务逻辑进行整合调用,完成整个产品的功能。
3.最后
最后提出一个问题,为什么要用面向过程(OP)的程序设计,而不用面向对象(OO)?
要解答这个问题,我们先问下面几个问题:
①系统中有多个相同或相似类型的实体吗?
②面向对象操作是否更容易组织和编写代码?
如果这两个答案都是否定的,则用面向过程的程序设计。
面向过程程序设计,向上层提供的是模块操作接口;面向对象程序设计,向上层提供的是模块抽象的类结构(或对象)。
在面向过程的编程中,也可以部分使用面向对象编程。