嵌入式技术基础与实践-学习札记(三)
嵌入式硬件构件
概念
嵌入式硬件构件是指将一个或多个硬件功能模块,支撑电路及其功能描述封装成一个可重用的硬件实体,并提供一系列规范的输入/输出接口。硬件模块是硬件构件的组成部分,一个硬件构件可能包含多个硬件功能模块。
分类
根据接口之间的生产消费关系,接口可分为供给接口和需求接口两类。根据所拥有的接口类型的不同,硬件构件分为核心构件、中间构件和终端构件。
- 核心构件只有供给结构,没有需求接口。也就是说,只为其他硬件构件提供服务,而不接受服务。例如芯片的硬件最小系统
- 中间构件既有需求接口又有供给接口。例如电源控制构件,(232)电平转换构件。
- 终端构件只有需求接口,它只接受其他构件提供的服务。例如(LCD)构件,(LED)构件,键盘构件。
利用硬件构件进行嵌入式系统硬件设计之前,应该进行硬件构件的合理划分,按照一定规则,设计与系统目标无关的构件个体,然后进行“组装”,完成具体系统的硬件设计。
电路图设计简明规则
在绘制原理图时,一个硬件构件使用一个虚线框,把硬件构件的电路及其文字描述括在其中,对外接口引出到虚线框外,填上接口网标。
1. 硬件构件设计的通用规则
(1)、元器件命名格式:对于核心构件,其元器件直接编号命名,同种类型的元件命名时冠以相同字母前缀。如电阻(R1,R2)。对于中间构件和终端构件,其元器件命名格式采用“构件名-标志字符?“。例如,(LCD)构件的电阻名为(LCD-C1)。当构件原理图应用到具体系统时,可借助原理图编辑软件自动编号。
(2)、为硬件构件添加详细的文字描述,包括中文名称、英文名称、功能描述、接口描述、注意事项等,以增强原理图的可读性。
(3)、前两步产生的内容封装在一个虚线框内,组成硬件构件的内部实体。
(4)、为该硬件构件添加与其他构件交互的输入/输出接口标识。接口标识有两种:
- 接口注释标于虚线框内,是为构件接口所做的解释性文字。
- 接口网标位于虚线框外,且具有电路连接特性。
2. 核心构件设计规则
设计核心构件时,需要考虑的问题是:“核心构件能为其他构件提供哪些信号?“
核心构件其实就是某型号(MCU)的硬件最小系统。核心构件设计的目标是:凡是使用该(MCU)进行硬件系统设计时,核心构件可以直接“组装”到系统中,无需任何改动。
在进行接口设计时,需要将所有可能使用到的引脚都标注上接口网标。若同一引脚具有不同的功能,则接口网标依据第一功能命名。
3. 中间构件设计规则
设计中间构件时,需要考虑的问题是:”中间构件需要接受哪些信号,以及提供哪些信号?”
一个中间构件应具有明确的且相对独立的功能,它既要有接受其他构件提供的服务的接口,即需求接口,又要有为其他构件提供服务的接口,即供给接口。描述需求接口采用接口注释,处于虚线框内,描述供给接口采用接口网标,处于虚线框外。
将构件的需求接口放置在构件实体的左侧,供给接口放置在右侧。接口网标的命名规则是:构件名称-引脚信号/功能名称。
4. 终端构件设计规则
设计终端构件时,需要考虑的问题是:”终端构件需要什么信号才能工作?“
它仅有与上一级构件交互的需求接口,因而街廓标识均为斜体标注的接口注释。
使用硬件构件化思想设计嵌入式硬件系统的过程与步骤如下:
- 根据系统的功能划分出若干个硬件构件。
- 将所有的硬件构件原理图”组装“在一起
- 为中间构件和终端构件添加接口网标。
嵌入式底层驱动构件的概念与层次模型
嵌入式系统中,驱动程序是直接工作在各种硬件设备上的软件,是硬件和高层软件之间桥梁。
嵌入式底层驱动构件的概念
-
构件((Component))是可重用的实体,它包含合乎规范的接口和功能实现,能够被独立部署和被第三方组装。
-
软件构件是指,在软件系统中具有相对独立功能、可以明确辨识的构件实体。
-
嵌入式软件构件是实现一定嵌入式系统功能的一组封装的、规范的、可重用的、具有嵌入式特性的软件构件单元。是组织嵌入式系统功能的基本单位。
-
嵌入式底层驱动构件,简称底层驱动构件或硬件驱动构件,是直接面向硬件操作系统的程序代码及使用说明。规范的底层驱动构件由头文件及源程序文件构成。头文件是底层驱动构件简明且完备的使用说明,也就是说,不需要查看源程序文件,就能够使用该构件进行下一层程序的开发。
嵌入式硬件构件和软件构件的层次模型
在硬件构件层中,相对于核心构件而言,中间构件和终端构件是核心构件的”外设“。由这些”外设“的驱动程序封装而成的软件构件成为底层外设构件。
由上图可以看出,底层外设构件可以调用底层内部构件,如(LCD)构件可以调用(GPIO)驱动构件。而高层构件可以调用底层外设构件和底层内部构件中的功能构件,而不能直接调用(GPIO)驱动构件。另外,几乎所有的底层内部构件都涉及(MCU)各种寄存器额使用,因此将(MCU)的所有寄存器定义组织在一起,形成(MCU)头文件。
底层驱动构件的封装规范
构件设计的基本思想与基本原则
-
构件设计的基本思想
底层构件被组织成具有一定独立性的功能模块,由头文件和源程序文件两部分组成。构件的头文件名和源程序名一致,且为构件名。
构件的头文件中,主要包含必要的引用文件、描述构件功能特性的宏定义语句以及声明对外接口函数。
构件的源程序文件中包含构件的头文件,内部函数声明、对外接口函数的实现。
尽量做到:当一个底层构件应用到不同系统中时,仅需修改构件的头文件,对于构件的源程序文件则不必要修改或改动很小。
-
构件设计的基本原则
良好的底层驱动具有以下特性:
-
封装性。即内部实现的调整不会影响构件调用者的使用。
-
描述性。构件必须提供规范的函数名称、接口信息,参数含义与范围、必要的注意事项等。
-
可移植性。同样功能的构件,做到不改动或少改动,而方便的移植到同系列及不同系列芯片内。
-
可复用性。高层调用者对构件的使用不会因底层实现的变化而有所改变。
1、层次化原则
-
针对应用场景和服务对象,分层组织构件。设计底层驱动构件的过程中,有一些与处理器相关的、描述了芯片寄存器映射的内容,这些是所有底层驱动构件都需要使用的,将这些内容组织成底层驱动的公共内容,作为底层驱动构件的基础。
-
在构件的层次模型中,上层构件可以调用下层构件提供的服务,同一层次的构件不存在相互依赖关系,不能相互调用。
2、易用性原则
- 函数名简洁且达意;接口参数清晰,范围明确,使用说明语言精炼规范,避免二义性。
3、鲁棒性原则
- 再明确函数输入输出的取值范围,提供清晰接口描述的同时,在函数实现内部要有对输入输出参数的检测,对超出合法范围的输入参数进行必要的处理。
4、内存可靠使用原则
- 优先使用静态分配内存。
- 谨慎使用变量。
- 检测空指针。
- 检测缓冲区溢出,并为内存中的缓冲区预留不小于(20\%)的冗余。
-
编码风格基本规范
命名基本原则:
-
命名清晰明了,有明确含义,使用完整单词或约定俗称的缩写。
-
命名风格要自始至终保持一致。
-
为了代码的复用,命名中应避免使用与具体项目相关的前缀。
-
为了便于管理,对程序实体的命名要体现出所属构件的名称。
-
使用英文命名。
-
除宏命名外,名称字符全部小写,以”_”作为单词的分隔符。
1、文件的命名
- 底层驱动构件在具体设计时分为两个文件,头文件,源文件,命名格式为<硬件模块名称>.后缀。
2、函数的命名
- 底层驱动构件的函数从属于驱动构件,驱动函数的命名除了要体现函数功能外,还需要使用命名前缀和后缀标识其所属的构件及不同的实现方式。
- 函数名前缀:底层驱动构件中定义的所用函数均使用”<构件名>_“前缀标识其所属的驱动构件模块。
- 函数名后缀:对同一服务的不同方式的实现,使用后缀加以区分。
3、函数形参变量与函数内局部变量的命名
- 函数形参变量:函数形参变量名应直观表明参数意义,若传入的参数是指针类型应使用(“\_prt”)后缀加以标识。
- 局部变量:局部变量的命名与函数形参变量类型。注意一般不取单个字符((i,j,k))进行命名。
4、宏常量及宏函数的命名
- 宏常量和宏函数的命名全部使用大写字符,使用下划线为分隔符。
5、结构体类型的命名、类型定义与变量声明
- 结构体类型名称使用小写字母命名,定义结构体类型变量时,全部使用大写字母命名。
- 对结构体内部字段全部使用大写字母命名。
- 定义类型时,同时声明一个结构体变量和结构体指针变量。
注释
在程序代码中使用注释,说明程序在“做什么”,解释代码的目的,功能和采用的方法。
1、 文件头注释
2、函数头注释
公共要素文件
为某一款芯片编写驱动构件时,不同的构件存在公共使用的内容,将这些内容以构件的形式组织起来,称为构件公共要素。所有底层驱动都包含对构件公共要素的引用。
-
芯片寄存器映射文件
每个底层驱动构件都是以硬件模块的特殊功能寄存器为操作对象,因此,在(common.h)文件中包含描述芯片寄存器映射的头文件。
还需要将内核及芯片相关文件引用到公共要素中。
-
移位操作的宏函数
-
重定义基本数据类型
在编写嵌入式时要明确使用变量的字长,因此,需根据具体编译器重新定义嵌入式基本数据类型。有利于软件的移植。
头文件的设计规范
-
编码框架
编写每个构件的头文件时,应使用
#ifndef……#define……#endif
编码结构,防止对头文件的重复包含。 -
使用宏定义
使用宏定义标识构件中的常量,为常量提供有意义的别名。
使用宏函数实现构件对外部请求服务的接口映射。
-
声明对外接口函数,包含对外接口函数的使用说明
源程序文件设计规范
- 只允许一处使用
#include
包含自身头文件。 - 合理设计与实现对外接口函数与内部函数。
- 不使用全局变量